Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,36 @@ def load(
parser._return_value = return_value
return parser

@staticmethod
def _sanitize_schema(schema: Union[Schema, Dict[str, Any]]) -> Schema:
"""Sanitizes schema to ensure Pydantic 2.11+ compatibility.

Converts 'Any' type to 'object' type since Pydantic 2.11+ only accepts:
'array', 'boolean', 'integer', 'null', 'number', 'object', 'string'

Args:
schema: Schema object or dict to sanitize

Returns:
Sanitized Schema object
"""
if isinstance(schema, dict):
schema = Schema(**schema)

# If schema has 'Any' type, convert to 'object'
if hasattr(schema, 'type') and schema.type and schema.type.lower() == 'any':
schema.type = 'object'

return schema

@staticmethod
def _create_default_schema() -> Schema:
"""Creates a default schema that's compatible with Pydantic 2.11+.

Returns 'object' type instead of 'Any' to ensure Pydantic validation passes.
"""
return Schema(type='object')

def _process_operation_parameters(self):
"""Processes parameters from the OpenAPI operation."""
parameters = self._operation.parameters or []
Expand All @@ -86,6 +116,11 @@ def _process_operation_parameters(self):
description = param.description or ''
location = param.in_ or ''
schema = param.schema_ or {} # Use schema_ instead of .schema

# Sanitize schema to handle 'Any' type
if isinstance(schema, (Schema, dict)):
schema = self._sanitize_schema(schema)

schema.description = (
description if not schema.description else schema.description
)
Expand Down Expand Up @@ -115,11 +150,20 @@ def _process_request_body(self):
# If request body is an object, expand the properties as parameters
for _, media_type_object in content.items():
schema = media_type_object.schema_ or {}

# Sanitize schema to handle 'Any' type
if isinstance(schema, (Schema, dict)):
schema = self._sanitize_schema(schema)

description = request_body.description or ''

if schema and schema.type == 'object':
properties = schema.properties or {}
for prop_name, prop_details in properties.items():
# Sanitize nested schema
if isinstance(prop_details, Schema):
prop_details = self._sanitize_schema(prop_details)

self._params.append(
ApiParameter(
original_name=prop_name,
Expand Down Expand Up @@ -164,8 +208,8 @@ def _dedupe_param_names(self):
def _process_return_value(self) -> Parameter:
"""Returns a Parameter object representing the return type."""
responses = self._operation.responses or {}
# Default to empty schema if no 2xx response or if schema is missing
return_schema = Schema()
# Default to object type if no 2xx response or if schema is missing
return_schema = self._create_default_schema()

# Take the 20x response with the smallest response code.
valid_codes = list(
Expand All @@ -178,6 +222,11 @@ def _process_return_value(self) -> Parameter:
for mime_type in content:
if content[mime_type].schema_:
return_schema = content[mime_type].schema_

# Sanitize return schema
if isinstance(return_schema, Schema):
return_schema = self._sanitize_schema(return_schema)

break

self._return_value = ApiParameter(
Expand Down