failed WRONG_FIX wrong_fix · 6 tool calls · 33 s · fastapi/fastapi
🐛 Fix handling of JSON Schema attributes named "$ref" Fix handling of JSON Schema attributes named "$ref" Related to: https://github.com/fastapi/fastapi/issues/14344
| # | Tool | Arguments | Result |
|---|---|---|---|
| 1 | run_command | {
"command": "grep -rn \"\\$ref\" . | head -40"
} | {"status": "ok", "stdout": "./fastapi/_compat/v2.py:188: if \"$ref\" not in json_schema:\n./fastapi/_compat/v2.py:264: if key == \"$ref\":\n./fastapi/_compat/v2full{"status": "ok", "stdout": "./fastapi/_compat/v2.py:188: if \"$ref\" not in json_schema:\n./fastapi/_compat/v2.py:264: if key == \"$ref\":\n./fastapi/_compat/v2.py:265: ref_name = schema[\"$ref\"].split(\"/\")[-1]\n./fastapi/_compat/v2.py:268: new_schema[\"$ref\"] = REF_TEMPLATE.format(model=new_name)\n./fastapi/_compat/v2.py:270: new_schema[\"$ref\"] = schema[\"$ref\"]\n./fastapi/_compat/v2.py:310: old_name = schema[\"$ref\"].split(\"/\")[-1]\n./fastapi/openapi/models.py:103: ref: str = Field(alias=\"$ref\")\n./fastapi/openapi/models.py:138: ref: Optional[str] = Field(default=None, alias=\"$ref\")\n./fastapi/openapi/models.py:322: ref: Optional[str] = Field(default=None, alias=\"$ref\")\n./fastapi/openapi/utils.py:63: \"items\": {\"$ref\": REF_PREFIX + \"ValidationError\"},\n./fastapi/openapi/utils.py:419: \"schema\": {\"$ref\": REF_PREFIX + \"HTTPValidationError\"}\n./tests/test_multi_query_errors.py:82: \"$ref\": \"#/components/schemas/HTTPValidationError\"\n./tests/test_multi_query_errors.py:130: \"items\": {\"$ref\": \"#/components/schemas/ValidationError\"},\n./tests/test_sub_callbacks.py:133: \"schema\": {\"$ref\": \"#/components/schemas/Invoice\"}\n./tests/test_sub_callbacks.py:148: \"$ref\": \"#/components/schemas/HTTPValidationError\"\n./tests/test_sub_callbacks.py:165: \"$ref\": \"#/components/schemas/Event\"\n./tests/test_sub_callbacks.py:182: \"$ref\": \"#/components/schemas/HTTPValidationError\"\n./tests/test_sub_callbacks.py:201: \"$ref\": \"#/components/schemas/InvoiceEvent\"\n./tests/test_sub_callbacks.py:212: |
| 2 | read_file | {
"end_line": 320,
"filepath": "fastapi/_compat/v2.py",
"start_line": 180
} | {"status": "ok", "filepath": "fastapi/_compat/v2.py", "content": " ],\n separate_input_output_schemas: bool = True,\n) -> Dict[str, Any]:\n override_mode: Unionfull{"status": "ok", "filepath": "fastapi/_compat/v2.py", "content": " ],\n separate_input_output_schemas: bool = True,\n) -> Dict[str, Any]:\n override_mode: Union[Literal[\"validation\"], None] = (\n None if separate_input_output_schemas else \"validation\"\n )\n # This expects that GenerateJsonSchema was already used to generate the definitions\n json_schema = field_mapping[(field, override_mode or field.mode)]\n if \"$ref\" not in json_schema:\n # TODO remove when deprecating Pydantic v1\n # Ref: https://github.com/pydantic/pydantic/blob/d61792cc42c80b13b23e3ffa74bc37ec7c77f7d1/pydantic/schema.py#L207\n json_schema[\"title\"] = field.field_info.title or field.alias.title().replace(\n \"_\", \" \"\n )\n return json_schema\n\n\ndef get_definitions(\n *,\n fields: Sequence[ModelField],\n model_name_map: ModelNameMap,\n separate_input_output_schemas: bool = True,\n) -> Tuple[\n Dict[Tuple[ModelField, Literal[\"validation\", \"serialization\"]], JsonSchemaValue],\n Dict[str, Dict[str, Any]],\n]:\n schema_generator = GenerateJsonSchema(ref_template=REF_TEMPLATE)\n override_mode: Union[Literal[\"validation\"], None] = (\n None if separate_input_output_schemas else \"validation\"\n )\n validation_fields = [field for field in fields if field.mode == \"validation\"]\n serialization_fields = [field for field in fields if field.mode == \"serialization\"]\n flat_validation_models = get_flat_models_from_fields(\n validation_fields, known_models=set()\n )\n flat_serialization_models = get_flat_models_from_fields(\n serialization_fields, known_models=set()\n )\n flat_validation_model_fields = [\n ModelField(\n field_info=FieldInfo(annotation=model),\n name=model.__name__,\n mode=\"validation\",\n )\n for model in flat_validation_models\n ]\n flat_serialization_model_fields = [\n |
| 3 | read_file | {
"end_line": 315,
"filepath": "fastapi/_compat/v2.py",
"start_line": 290
} | {"status": "ok", "filepath": "fastapi/_compat/v2.py", "content": " return new_schema\n\n\ndef _remap_definitions_and_field_mappings(\n *,\n model_name_map: Modefull{"status": "ok", "filepath": "fastapi/_compat/v2.py", "content": " return new_schema\n\n\ndef _remap_definitions_and_field_mappings(\n *,\n model_name_map: ModelNameMap,\n definitions: Dict[str, Any],\n field_mapping: Dict[\n Tuple[ModelField, Literal[\"validation\", \"serialization\"]], JsonSchemaValue\n ],\n) -> Tuple[\n Dict[Tuple[ModelField, Literal[\"validation\", \"serialization\"]], JsonSchemaValue],\n Dict[str, Any],\n]:\n old_name_to_new_name_map = {}\n for field_key, schema in field_mapping.items():\n model = field_key[0].type_\n if model not in model_name_map:\n continue\n new_name = model_name_map[model]\n old_name = schema[\"$ref\"].split(\"/\")[-1]\n if old_name in {f\"{new_name}-Input\", f\"{new_name}-Output\"}:\n continue\n old_name_to_new_name_map[old_name] = new_name\n\n new_field_mapping: Dict[\n", "start_line": 290, "end_line": 315, "total_lines": 479, "is_truncated": false} |
| 4-5 ×2 | read_file | {
"end_line": 315,
"filepath": "fastapi/_compat/v2.py",
"start_line": 300
} | {"status": "ok", "filepath": "fastapi/_compat/v2.py", "content": ") -> Tuple[\n Dict[Tuple[ModelField, Literal[\"validation\", \"serialization\"]], JsonSchemaVafull{"status": "ok", "filepath": "fastapi/_compat/v2.py", "content": ") -> Tuple[\n Dict[Tuple[ModelField, Literal[\"validation\", \"serialization\"]], JsonSchemaValue],\n Dict[str, Any],\n]:\n old_name_to_new_name_map = {}\n for field_key, schema in field_mapping.items():\n model = field_key[0].type_\n if model not in model_name_map:\n continue\n new_name = model_name_map[model]\n old_name = schema[\"$ref\"].split(\"/\")[-1]\n if old_name in {f\"{new_name}-Input\", f\"{new_name}-Output\"}:\n continue\n old_name_to_new_name_map[old_name] = new_name\n\n new_field_mapping: Dict[\n", "start_line": 300, "end_line": 315, "total_lines": 479, "is_truncated": false} |
| 6 | edit_file | {
"filepath": "fastapi/_compat/v2.py",
"new_string": " new_name = model_name_map[model]\n if \"$ref\" not in schema:\n continue\n old_name = schema[\"$ref\"].split(\"/\")[-1]",
"old_string": " new_name = model_name_map[model]\n old_name = schema[\"$ref\"].split(\"/\")[-1]"
} | {"status": "ok", "filepath": "fastapi/_compat/v2.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/_compat/v2.py\n+++ b/fastapi/_compat/v2.py\nfull{"status": "ok", "filepath": "fastapi/_compat/v2.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/_compat/v2.py\n+++ b/fastapi/_compat/v2.py\n@@ -307,6 +307,8 @@\n if model not in model_name_map:\n continue\n new_name = model_name_map[model]\n+ if \"$ref\" not in schema:\n+ continue\n old_name = schema[\"$ref\"].split(\"/\")[-1]\n if old_name in {f\"{new_name}-Input\", f\"{new_name}-Output\"}:\n continue\n", "is_truncated": false} |
| 7 | submit_patch | [] | {"status": "ok", "patch_size": 512, "files_changed": 1}full{"status": "ok", "patch_size": 512, "files_changed": 1} |
diff --git a/fastapi/_compat/v2.py b/fastapi/_compat/v2.py
index 6a87b9ae..4ef852ea 100644
--- a/fastapi/_compat/v2.py
+++ b/fastapi/_compat/v2.py
@@ -307,6 +307,8 @@ def _remap_definitions_and_field_mappings(
if model not in model_name_map:
continue
new_name = model_name_map[model]
+ if "$ref" not in schema:
+ continue
old_name = schema["$ref"].split("/")[-1]
if old_name in {f"{new_name}-Input", f"{new_name}-Output"}:
continue
st(
/kaggle/tmp/envs/fastapi/lib/python3.13/site-packages/httpx/_client.py:825: in request
return self.send(request, auth=auth, follow_redirects=follow_redirects)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/kaggle/tmp/envs/fastapi/lib/python3.13/site-packages/httpx/_client.py:914: in send
response = self._send_handling_auth(
/kaggle/tmp/envs/fastapi/lib/python3.13/site-packages/httpx/_client.py:942: in _send_handling_auth
response = self._send_handling_redirects(
/kaggle/tmp/envs/fastapi/lib/python3.13/site-packages/httpx/_client.py:979: in _send_handling_redirects
response = self._send_single_request(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/kaggle/tmp/envs/fastapi/lib/python3.13/site-packages/httpx/_client.py:1014: in _send_single_request
response = transport.handle_request(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/kaggle/tmp/envs/overlays/starlette-0.49.3-py3-none-any/starlette/testclient.py:354: in handle_request
raise exc
/kaggle/tmp/envs/overlays/starlette-0.49.3-py3-none-any/starlette/testclient.py:351: in handle_request
portal.call(self.app, scope, receive, send)
/kaggle/tmp/envs/fastapi/lib/python3.13/site-packages/anyio/from_thread.py:340: in call
return cast(T_Retval, self.start_task_soon(func, *args).result())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/root/.local/share/uv/python/cpython-3.13.14-linux-x86_64-gnu/lib/python3.13/concurrent/futures/_base.py:460: in result
return self.__get_result()
^^^^^^^^^^^^^^^^^^^
/root/.local/share/uv/python/cpython-3.13.14-linux-x86_64-gnu/lib/python3.13/concurrent/futures/_base.py:402: in __get_result
raise self._exception
/kaggle/tmp/envs/fastapi/lib/python3.13/site-packages/anyio/from_thread.py:265: in _call_func
retval = await retval_or_awaitable
^^^^^^^^^^^^^^^^^^^^^^^^^
fastapi/applications.py:1134: in __call__
await super().__call__(scope, receive, send)
/kaggle/tmp/envs/overlays/starlette-0.49.3-py3-none-any/starlette/applications.py:113: in __call__
await self.middleware_stack(scope, receive, send)
/kaggle/tmp/envs/overlays/starlette-0.49.3-py3-none-any/starlette/middleware/errors.py:186: in __call__
raise exc
/kaggle/tmp/envs/overlays/starlette-0.49.3-py3-none-any/starlette/middleware/errors.py:164: in __call__
await self.app(scope, receive, _send)
/kaggle/tmp/envs/overlays/starlette-0.49.3-py3-none-any/starlette/middleware/exceptions.py:63: in __call__
await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
/kaggle/tmp/envs/overlays/starlette-0.49.3-py3-none-any/starlette/_exception_handler.py:53: in wrapped_app
raise exc
/kaggle/tmp/envs/overlays/starlette-0.49.3-py3-none-any/starlette/_exception_handler.py:42: in wrapped_app
await app(scope, receive, sender)
fastapi/middleware/asyncexitstack.py:18: in __call__
await self.app(scope, receive, send)
/kaggle/tmp/envs/overlays/starlette-0.49.3-py3-none-any/starlette/routing.py:716: in __call__
await self.middleware_stack(scope, receive, send)
/kaggle/tmp/envs/overlays/starlette-0.49.3-py3-none-any/starlette/routing.py:736: in app
await route.handle(scope, receive, send)
/kaggle/tmp/envs/overlays/starlette-0.49.3-py3-none-any/starlette/routing.py:290: in handle
await self.app(scope, receive, send)
/kaggle/tmp/envs/overlays/starlette-0.49.3-py3-none-any/starlette/routing.py:78: in app
await wrap_app_handling_exceptions(app, request)(scope, receive, send)
/kaggle/tmp/envs/overlays/starlette-0.49.3-py3-none-any/starlette/_exception_handler.py:53: in wrapped_app
raise exc
/kaggle/tmp/envs/overlays/starlette-0.49.3-py3-none-any/starlette/_exception_handler.py:42: in wrapped_app
await app(scope, receive, sender)
/kaggle/tmp/envs/overlays/starlette-0.49.3-py3-none-any/starlette/routing.py:75: in app
response = await f(request)
^^^^^^^^^^^^^^^^
fastapi/applications.py:1089: in openapi
return JSONResponse(self.openapi())
^^^^^^^^^^^^^^
fastapi/applications.py:1060: in openapi
self.openapi_schema = get_openapi(
fastapi/openapi/utils.py:504: in get_openapi
field_mapping, definitions = get_definitions(
fastapi/_compat/main.py:292: in get_definitions
v2_field_maps, v2_definitions = v2.get_definitions(
fastapi/_compat/v2.py:249: in get_definitions
new_mapping, new_definitions = _remap_definitions_and_field_mappings(
fastapi/_compat/v2.py:333: in _remap_definitions_and_field_mappings
new_value = _replace_refs(
fastapi/_compat/v2.py:273: in _replace_refs
new_schema[key] = _replace_refs(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
schema = {'$ref': {'title': '$Ref', 'type': 'string'}}
old_name_to_new_name_map = {'ModelWithRef': 'ModelWithRef'}
def _replace_refs(
*,
schema: Dict[str, Any],
old_name_to_new_name_map: Dict[str, str],
) -> Dict[str, Any]:
new_schema = deepcopy(schema)
for key, value in new_schema.items():
if key == "$ref":
> ref_name = schema["$ref"].split("/")[-1]
^^^^^^^^^^^^^^^^^^^^
E AttributeError: 'dict' object has no attribute 'split'
fastapi/_compat/v2.py:265: AttributeError
=============================== warnings summary ===============================
../../../../../../kaggle/tmp/envs/overlays/starlette-0.49.3-py3-none-any/starlette/testclient.py:51
/kaggle/tmp/envs/overlays/starlette-0.49.3-py3-none-any/starlette/testclient.py:51: DeprecationWarning: The anyio.abc.BlockingPortal alias is deprecated, use anyio.from_thread.BlockingPortal instead.
_PortalFactoryType = Callable[[], AbstractContextManager[anyio.abc.BlockingPortal]]
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 1 passed, 1 warning in 0.89s