Spaces:
Running
Running
openapi: Rewrite recursive #/components/schemas/ references
Browse filesWhen a schema referenced another schema as #/components/schemas/...
that wasn't properly rewritten into #/$defs/..
src/fastmcp/utilities/openapi.py
CHANGED
|
@@ -262,16 +262,18 @@ class OpenAPIParser(
|
|
| 262 |
|
| 263 |
if isinstance(resolved_schema, (self.schema_cls)):
|
| 264 |
# Convert schema to dictionary
|
| 265 |
-
|
| 266 |
mode="json", by_alias=True, exclude_none=True
|
| 267 |
)
|
| 268 |
elif isinstance(resolved_schema, dict):
|
| 269 |
-
|
| 270 |
else:
|
| 271 |
logger.warning(
|
| 272 |
f"Expected Schema after resolving, got {type(resolved_schema)}. Returning empty dict."
|
| 273 |
)
|
| 274 |
-
|
|
|
|
|
|
|
| 275 |
except Exception as e:
|
| 276 |
logger.error(f"Failed to extract schema as dict: {e}", exc_info=False)
|
| 277 |
return {}
|
|
|
|
| 262 |
|
| 263 |
if isinstance(resolved_schema, (self.schema_cls)):
|
| 264 |
# Convert schema to dictionary
|
| 265 |
+
result = resolved_schema.model_dump(
|
| 266 |
mode="json", by_alias=True, exclude_none=True
|
| 267 |
)
|
| 268 |
elif isinstance(resolved_schema, dict):
|
| 269 |
+
result = resolved_schema
|
| 270 |
else:
|
| 271 |
logger.warning(
|
| 272 |
f"Expected Schema after resolving, got {type(resolved_schema)}. Returning empty dict."
|
| 273 |
)
|
| 274 |
+
result = {}
|
| 275 |
+
|
| 276 |
+
return _replace_ref_with_defs(result)
|
| 277 |
except Exception as e:
|
| 278 |
logger.error(f"Failed to extract schema as dict: {e}", exc_info=False)
|
| 279 |
return {}
|
tests/utilities/openapi/test_openapi_advanced.py
CHANGED
|
@@ -294,6 +294,28 @@ def test_complex_schema_route_count(parsed_complex_routes):
|
|
| 294 |
assert len(parsed_complex_routes) == 3
|
| 295 |
|
| 296 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 297 |
def test_complex_schema_list_users_query_param_limit(complex_route_map):
|
| 298 |
"""Test that a reference to a limit query parameter is correctly resolved."""
|
| 299 |
list_users = complex_route_map["listUsers"]
|
|
|
|
| 294 |
assert len(parsed_complex_routes) == 3
|
| 295 |
|
| 296 |
|
| 297 |
+
def test_complex_schema_ref_rewriting(parsed_complex_routes):
|
| 298 |
+
"""Test that all #/components references have been rewritten."""
|
| 299 |
+
|
| 300 |
+
def no_components(value):
|
| 301 |
+
if isinstance(value, dict):
|
| 302 |
+
for k, v in value.items():
|
| 303 |
+
if k == "$ref":
|
| 304 |
+
assert not v.startswith("#/components/"), (
|
| 305 |
+
f"reference '{v}' was not rewritten"
|
| 306 |
+
)
|
| 307 |
+
else:
|
| 308 |
+
no_components(v)
|
| 309 |
+
elif isinstance(value, list):
|
| 310 |
+
for v in value:
|
| 311 |
+
no_components(v)
|
| 312 |
+
|
| 313 |
+
for route in parsed_complex_routes:
|
| 314 |
+
no_components(route.schema_definitions)
|
| 315 |
+
for param in route.parameters:
|
| 316 |
+
no_components(param.schema_)
|
| 317 |
+
|
| 318 |
+
|
| 319 |
def test_complex_schema_list_users_query_param_limit(complex_route_map):
|
| 320 |
"""Test that a reference to a limit query parameter is correctly resolved."""
|
| 321 |
list_users = complex_route_map["listUsers"]
|