โ† pod_r4_v1g

fastapi_14482

failed WRONG_FIX wrong_fix ยท 34 tool calls ยท 178 s ยท fastapi/fastapi

Task input

๐Ÿ› Fix handling arbitrary types when using `arbitrary_types_allowed=True`

๐Ÿ› Fix handling arbitrary types when using `arbitrary_types_allowed=True`

Related to https://github.com/fastapi/fastapi/discussions/14184, https://github.com/fastapi/fastapi/issues/14483

Tool calls (35)

#ToolArgumentsResult
1run_command
{
 "command": "grep -rn \"arbitrary_types_allowed\" . | head -20"
}
{"status": "ok", "stdout": "./tests/test_inherited_custom_class.py:45: model_config = {\"arbitrary_types_allowed\": True}\n./tests/test_inherited_custom_class.p
full
{"status": "ok", "stdout": "./tests/test_inherited_custom_class.py:45:        model_config = {\"arbitrary_types_allowed\": True}\n./tests/test_inherited_custom_class.py:89:            arbitrary_types_allowed = True\n./tests/test_jsonable_encoder.py:248:            model_config = {\"arbitrary_types_allowed\": True}\n./tests/test_jsonable_encoder.py:252:                arbitrary_types_allowed = True\n./tests/test_jsonable_encoder.py:264:            model_config = {\"arbitrary_types_allowed\": True}\n./tests/test_jsonable_encoder.py:268:                arbitrary_types_allowed = True\n./tests/test_jsonable_encoder.py:279:            model_config = {\"arbitrary_types_allowed\": True}\n./tests/test_jsonable_encoder.py:283:                arbitrary_types_allowed = True\n./tests/test_compat.py:87:        model_config = ConfigDict(arbitrary_types_allowed=True)\n./tests/test_compat.py:92:            arbitrary_types_allowed=True,\n", "stderr": "", "exit_code": 0}
2run_command
{
 "command": "grep -rn \"arbitrary_types_allowed\" fastapi | head -20"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
3run_command
{
 "command": "grep -rn \"arbitrary_types_allowed\" ."
}
{"status": "ok", "stdout": "./tests/test_inherited_custom_class.py:45: model_config = {\"arbitrary_types_allowed\": True}\n./tests/test_inherited_custom_class.p
full
{"status": "ok", "stdout": "./tests/test_inherited_custom_class.py:45:        model_config = {\"arbitrary_types_allowed\": True}\n./tests/test_inherited_custom_class.py:89:            arbitrary_types_allowed = True\n./tests/test_jsonable_encoder.py:248:            model_config = {\"arbitrary_types_allowed\": True}\n./tests/test_jsonable_encoder.py:252:                arbitrary_types_allowed = True\n./tests/test_jsonable_encoder.py:264:            model_config = {\"arbitrary_types_allowed\": True}\n./tests/test_jsonable_encoder.py:268:                arbitrary_types_allowed = True\n./tests/test_jsonable_encoder.py:279:            model_config = {\"arbitrary_types_allowed\": True}\n./tests/test_jsonable_encoder.py:283:                arbitrary_types_allowed = True\n./tests/test_compat.py:87:        model_config = ConfigDict(arbitrary_types_allowed=True)\n./tests/test_compat.py:92:            arbitrary_types_allowed=True,\n", "stderr": "", "exit_code": 0}
4run_command
{
 "command": "grep -rn \"arbitrary_types_allowed\" . | grep \"fastapi/\""
}
{"status": "error", "error_type": "CommandError", "error_message": "", "details": {"stdout": "", "stderr": "", "exit_code": 1}}
full
{"status": "error", "error_type": "CommandError", "error_message": "", "details": {"stdout": "", "stderr": "", "exit_code": 1}}
5run_command
{
 "command": "find . -name \"*.py\" | xargs grep -l \"arbitrary_types_allowed\""
}
{"status": "ok", "stdout": "./tests/test_inherited_custom_class.py\n./tests/test_jsonable_encoder.py\n./tests/test_compat.py\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "./tests/test_inherited_custom_class.py\n./tests/test_jsonable_encoder.py\n./tests/test_compat.py\n", "stderr": "", "exit_code": 0}
6run_command
{
 "command": "ls -R fastapi/"
}
{"status": "ok", "stdout": "__init__.py\n__main__.py\n_compat\napplications.py\nbackground.py\ncli.py\nconcurrency.py\ndatastructures.py\ndependencies\nencoders
full
{"status": "ok", "stdout": "__init__.py\n__main__.py\n_compat\napplications.py\nbackground.py\ncli.py\nconcurrency.py\ndatastructures.py\ndependencies\nencoders.py\nexception_handlers.py\nexceptions.py\nlogger.py\nmiddleware\nopenapi\nparam_functions.py\nparams.py\npy.typed\nrequests.py\nresponses.py\nrouting.py\nsecurity\nstaticfiles.py\ntemp_pydantic_v1_params.py\ntemplating.py\ntestclient.py\ntypes.py\nutils.py\nwebsockets.py\n\nfastapi/_compat:\n__init__.py\nmain.py\nmay_v1.py\nmodel_field.py\nshared.py\nv1.py\nv2.py\n\nfastapi/dependencies:\n__init__.py\nmodels.py\nutils.py\n\nfastapi/middleware:\n__init__.py\nasyncexitstack.py\ncors.py\ngzip.py\nhttpsredirect.py\ntrustedhost.py\nwsgi.py\n\nfastapi/openapi:\n__init__.py\nconstants.py\ndocs.py\nmodels.py\nutils.py\n\nfastapi/security:\n__init__.py\napi_key.py\nbase.py\nhttp.py\noauth2.py\nopen_id_connect_url.py\nutils.py\n", "stderr": "", "exit_code": 0}
7run_command
{
 "command": "grep -rn \"jsonable_encoder\" fastapi/"
}
{"status": "ok", "stdout": "fastapi/exception_handlers.py:1:from fastapi.encoders import jsonable_encoder\nfastapi/exception_handlers.py:25: content={\"detail\"
full
{"status": "ok", "stdout": "fastapi/exception_handlers.py:1:from fastapi.encoders import jsonable_encoder\nfastapi/exception_handlers.py:25:        content={\"detail\": jsonable_encoder(exc.errors())},\nfastapi/exception_handlers.py:33:        code=WS_1008_POLICY_VIOLATION, reason=jsonable_encoder(exc.errors())\nfastapi/encoders.py:114:def jsonable_encoder(\nfastapi/encoders.py:247:        return jsonable_encoder(\nfastapi/encoders.py:258:        return jsonable_encoder(\nfastapi/encoders.py:294:                encoded_key = jsonable_encoder(\nfastapi/encoders.py:302:                encoded_value = jsonable_encoder(\nfastapi/encoders.py:316:                jsonable_encoder(\nfastapi/encoders.py:346:    return jsonable_encoder(\nfastapi/openapi/docs.py:5:from fastapi.encoders import jsonable_encoder\nfastapi/openapi/docs.py:137:        html += f\"{json.dumps(key)}: {json.dumps(jsonable_encoder(value))},\\n\"\nfastapi/openapi/docs.py:151:        ui.initOAuth({json.dumps(jsonable_encoder(init_oauth))})\nfastapi/openapi/utils.py:23:from fastapi.encoders import jsonable_encoder\nfastapi/openapi/utils.py:85:        security_definition = jsonable_encoder(\nfastapi/openapi/utils.py:168:                parameter[\"examples\"] = jsonable_encoder(openapi_examples)\nfastapi/openapi/utils.py:170:                parameter[\"example\"] = jsonable_encoder(example)\nfastapi/openapi/utils.py:203:        request_media_content[\"examples\"] = jsonable_encoder(\nfastapi/openapi/utils.py:207:        request_media_content[\"example\"] = jsonable_encoder(field_info.example)\nfastapi/openapi/utils.py:567:    return jsonable_encoder(OpenAPI(**output), by_alias=True, exclude_none=True)  # type: ignore\nfastapi/routing.py:47:from fastapi.encoders import jsonable_encoder\nfastapi/routing.py:295:        return jsonable_encoder(\nfastapi/routing.py:305:        return jsonable_encoder(response_content)\n", "stderr": "", "exit_code": 0}
8run_command
{
 "command": "sed -n '114,350p' fastapi/encoders.py"
}
{"status": "ok", "stdout": "def jsonable_encoder(\n obj: Annotated[\n Any,\n Doc(\n \"\"\"\n The input object to convert to JSON.\n \"\"\"\n ),\n ],\n include:
full
{"status": "ok", "stdout": "def jsonable_encoder(\n    obj: Annotated[\n        Any,\n        Doc(\n            \"\"\"\n            The input object to convert to JSON.\n            \"\"\"\n        ),\n    ],\n    include: Annotated[\n        Optional[IncEx],\n        Doc(\n            \"\"\"\n            Pydantic's `include` parameter, passed to Pydantic models to set the\n            fields to include.\n            \"\"\"\n        ),\n    ] = None,\n    exclude: Annotated[\n        Optional[IncEx],\n        Doc(\n            \"\"\"\n            Pydantic's `exclude` parameter, passed to Pydantic models to set the\n            fields to exclude.\n            \"\"\"\n        ),\n    ] = None,\n    by_alias: Annotated[\n        bool,\n        Doc(\n            \"\"\"\n            Pydantic's `by_alias` parameter, passed to Pydantic models to define if\n            the output should use the alias names (when provided) or the Python\n            attribute names. In an API, if you set an alias, it's probably because you\n            want to use it in the result, so you probably want to leave this set to\n            `True`.\n            \"\"\"\n        ),\n    ] = True,\n    exclude_unset: Annotated[\n        bool,\n        Doc(\n            \"\"\"\n            Pydantic's `exclude_unset` parameter, passed to Pydantic models to define\n            if it should exclude from the output the fields that were not explicitly\n            set (and that only had their default values).\n            \"\"\"\n        ),\n    ] = False,\n    exclude_defaults: Annotated[\n        bool,\n        Doc(\n            \"\"\"\n            Pydantic's `exclude_defaults` parameter, passed to Pydantic models to define\n            if it should exclude from the output the fields that had the same default\n            value, even when they were explicitly set.\n            \"\"\"\n        ),\n    ] = False,\n    exclude_none: Annotated[\n        bool,\n        Doc(\n            \"\"\"\n            P
9run_command
{
 "command": "sed -n '240,350p' fastapi/encoders.py"
}
{"status": "ok", "stdout": " by_alias=by_alias,\n exclude_unset=exclude_unset,\n exclude_none=exclude_none,\n exclude_defaults=exclude_defaults,\n )\n if \"__ro
full
{"status": "ok", "stdout": "            by_alias=by_alias,\n            exclude_unset=exclude_unset,\n            exclude_none=exclude_none,\n            exclude_defaults=exclude_defaults,\n        )\n        if \"__root__\" in obj_dict:\n            obj_dict = obj_dict[\"__root__\"]\n        return jsonable_encoder(\n            obj_dict,\n            exclude_none=exclude_none,\n            exclude_defaults=exclude_defaults,\n            # TODO: remove when deprecating Pydantic v1\n            custom_encoder=encoders,\n            sqlalchemy_safe=sqlalchemy_safe,\n        )\n    if dataclasses.is_dataclass(obj):\n        assert not isinstance(obj, type)\n        obj_dict = dataclasses.asdict(obj)\n        return jsonable_encoder(\n            obj_dict,\n            include=include,\n            exclude=exclude,\n            by_alias=by_alias,\n            exclude_unset=exclude_unset,\n            exclude_defaults=exclude_defaults,\n            exclude_none=exclude_none,\n            custom_encoder=custom_encoder,\n            sqlalchemy_safe=sqlalchemy_safe,\n        )\n    if isinstance(obj, Enum):\n        return obj.value\n    if isinstance(obj, PurePath):\n        return str(obj)\n    if isinstance(obj, (str, int, float, type(None))):\n        return obj\n    if _is_undefined(obj):\n        return None\n    if isinstance(obj, dict):\n        encoded_dict = {}\n        allowed_keys = set(obj.keys())\n        if include is not None:\n            allowed_keys &= set(include)\n        if exclude is not None:\n            allowed_keys -= set(exclude)\n        for key, value in obj.items():\n            if (\n                (\n                    not sqlalchemy_safe\n                    or (not isinstance(key, str))\n                    or (not key.startswith(\"_sa\"))\n                )\n                and (value is not None or not exclude_none)\n                and key in allowed_keys\n            ):\n                encoded_key = jsonable_encoder(\n             
10run_command
{
 "command": "cat tests/test_jsonable_encoder.py | sed -n '240,290p'"
}
{"status": "ok", "stdout": " assert encoded_instance == custom_enum_encoder(instance)\n\n\ndef test_encode_model_with_pure_path():\n class ModelWithPath(BaseMod
full
{"status": "ok", "stdout": "    assert encoded_instance == custom_enum_encoder(instance)\n\n\ndef test_encode_model_with_pure_path():\n    class ModelWithPath(BaseModel):\n        path: PurePath\n\n        if PYDANTIC_V2:\n            model_config = {\"arbitrary_types_allowed\": True}\n        else:\n\n            class Config:\n                arbitrary_types_allowed = True\n\n    test_path = PurePath(\"/foo\", \"bar\")\n    obj = ModelWithPath(path=test_path)\n    assert jsonable_encoder(obj) == {\"path\": str(test_path)}\n\n\ndef test_encode_model_with_pure_posix_path():\n    class ModelWithPath(BaseModel):\n        path: PurePosixPath\n\n        if PYDANTIC_V2:\n            model_config = {\"arbitrary_types_allowed\": True}\n        else:\n\n            class Config:\n                arbitrary_types_allowed = True\n\n    obj = ModelWithPath(path=PurePosixPath(\"/foo\", \"bar\"))\n    assert jsonable_encoder(obj) == {\"path\": \"/foo/bar\"}\n\n\ndef test_encode_model_with_pure_windows_path():\n    class ModelWithPath(BaseModel):\n        path: PureWindowsPath\n\n        if PYDANTIC_V2:\n            model_config = {\"arbitrary_types_allowed\": True}\n        else:\n\n            class Config:\n                arbitrary_types_allowed = True\n\n    obj = ModelWithPath(path=PureWindowsPath(\"/foo\", \"bar\"))\n    assert jsonable_encoder(obj) == {\"path\": \"\\\\foo\\\\bar\"}\n\n\n@needs_pydanticv1\ndef test_encode_root():\n", "stderr": "", "exit_code": 0}
11run_command
{
 "command": "cat tests/test_inherited_custom_class.py"
}
{"status": "ok", "stdout": "import uuid\n\nimport pytest\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel
full
{"status": "ok", "stdout": "import uuid\n\nimport pytest\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel\n\nfrom .utils import needs_pydanticv1, needs_pydanticv2\n\n\nclass MyUuid:\n    def __init__(self, uuid_string: str):\n        self.uuid = uuid_string\n\n    def __str__(self):\n        return self.uuid\n\n    @property  # type: ignore\n    def __class__(self):\n        return uuid.UUID\n\n    @property\n    def __dict__(self):\n        \"\"\"Spoof a missing __dict__ by raising TypeError, this is how\n        asyncpg.pgroto.pgproto.UUID behaves\"\"\"\n        raise TypeError(\"vars() argument must have __dict__ attribute\")\n\n\n@needs_pydanticv2\ndef test_pydanticv2():\n    from pydantic import field_serializer\n\n    app = FastAPI()\n\n    @app.get(\"/fast_uuid\")\n    def return_fast_uuid():\n        asyncpg_uuid = MyUuid(\"a10ff360-3b1e-4984-a26f-d3ab460bdb51\")\n        assert isinstance(asyncpg_uuid, uuid.UUID)\n        assert type(asyncpg_uuid) is not uuid.UUID\n        with pytest.raises(TypeError):\n            vars(asyncpg_uuid)\n        return {\"fast_uuid\": asyncpg_uuid}\n\n    class SomeCustomClass(BaseModel):\n        model_config = {\"arbitrary_types_allowed\": True}\n\n        a_uuid: MyUuid\n\n        @field_serializer(\"a_uuid\")\n        def serialize_a_uuid(self, v):\n            return str(v)\n\n    @app.get(\"/get_custom_class\")\n    def return_some_user():\n        # Test that the fix also works for custom pydantic classes\n        return SomeCustomClass(a_uuid=MyUuid(\"b8799909-f914-42de-91bc-95c819218d01\"))\n\n    client = TestClient(app)\n\n    with client:\n        response_simple = client.get(\"/fast_uuid\")\n        response_pydantic = client.get(\"/get_custom_class\")\n\n    assert response_simple.json() == {\n        \"fast_uuid\": \"a10ff360-3b1e-4984-a26f-d3ab460bdb51\"\n    }\n\n    assert response_pydantic.json() == {\n        \"a_uuid\": \"b8799909-f914-42de-91bc-95c81
12run_command
{
 "command": "python3 -m pytest tests/test_inherited_custom_class.py"
}
{"status": "ok", "stdout": "============================= test session starts ==============================\nplatform darwin -- Python 3.13.15, pytest-9.1.1, p
full
{"status": "ok", "stdout": "============================= test session starts ==============================\nplatform darwin -- Python 3.13.15, pytest-9.1.1, pluggy-1.6.0\ncodspeed: 5.0.3 (disabled, mode: walltime, callgraph: not supported, timer_resolution: 41.7ns)\nrootdir: /private/workspace\nconfigfile: pytest.ini (WARNING: ignoring pytest config in pyproject.toml!)\nplugins: cov-7.1.0, xdist-3.8.0, timeout-2.4.0, codspeed-5.0.3, sugar-1.1.1, anyio-4.15.1, inline-snapshot-0.35.4\ncollected 2 items\n\ntests/test_inherited_custom_class.py .s                                  [100%]\n\n=============================== warnings summary ===============================\n../../../../../../../Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-0.50.0-py3-none-any/starlette/testclient.py:45\n  /Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-0.50.0-py3-none-any/starlette/testclient.py:45: DeprecationWarning: The anyio.abc.BlockingPortal alias is deprecated, use anyio.from_thread.BlockingPortal instead.\n    _PortalFactoryType = Callable[[], AbstractContextManager[anyio.abc.BlockingPortal]]\n\n-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html\n=================== 1 passed, 1 skipped, 1 warning in 0.43s ====================\n", "stderr": "", "exit_code": 0}
13run_command
{
 "command": "python3 -m pytest tests/test_jsonable_encoder.py -k \"encode_model_with_pure_path\""
}
{"status": "ok", "stdout": "============================= test session starts ==============================\nplatform darwin -- Python 3.13.15, pytest-9.1.1, p
full
{"status": "ok", "stdout": "============================= test session starts ==============================\nplatform darwin -- Python 3.13.15, pytest-9.1.1, pluggy-1.6.0\ncodspeed: 5.0.3 (disabled, mode: walltime, callgraph: not supported, timer_resolution: 41.7ns)\nrootdir: /private/workspace\nconfigfile: pytest.ini (WARNING: ignoring pytest config in pyproject.toml!)\nplugins: cov-7.1.0, xdist-3.8.0, timeout-2.4.0, codspeed-5.0.3, sugar-1.1.1, anyio-4.15.1, inline-snapshot-0.35.4\ncollected 23 items / 22 deselected / 1 selected\n\ntests/test_jsonable_encoder.py .                                         [100%]\n\n======================= 1 passed, 22 deselected in 0.29s =======================\n", "stderr": "", "exit_code": 0}
14run_command
{
 "command": "cat > /tmp/repro.py <<'PY'\nfrom pydantic import BaseModel, ConfigDict\nfrom fastapi.encoders import jsonable_encoder\n\nclass MyCustomType:\n    def __init__(self, value):\n        self.value = value\n    def __repr__(self):\n        return f\"MyCustomType({self.value})\"\n\nclass Model(BaseModel):\n    model_config = ConfigDict(arbitrary_types_allowed=True)\n    custom: MyCustomType\n\ncustom_obj = MyCustomType(\"hello\")\nmodel = Model(custom=custom_obj)\n\ntry:\n    encoded = jsonable_encoder(model)\n    print(f\"Encoded: {encoded}\")\nexcept Exception as e:\n    print(f\"Error: {e}\")\nPY\npython3 /tmp/repro.py\n"
}
{"status": "ok", "stdout": "Error: Unable to serialize unknown type: <class '__main__.MyCustomType'>\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "Error: Unable to serialize unknown type: <class '__main__.MyCustomType'>\n", "stderr": "", "exit_code": 0}
15run_command
{
 "command": "python3 -c \"from pydantic import BaseModel, ConfigDict; print(BaseModel.model_dump)\""
}
{"status": "ok", "stdout": "<function BaseModel.model_dump at 0x102130ea0>\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "<function BaseModel.model_dump at 0x102130ea0>\n", "stderr": "", "exit_code": 0}
16run_command
{
 "command": "python3 -c \"from pydantic import BaseModel, ConfigDict; class M(BaseModel): model_config = ConfigDict(arbitrary_types_allowed=True); m = M(a=1); print(m.model_dump(mode='json'))\""
}
{"status": "error", "error_type": "CommandError", "error_message": " File \"<string>\", line 1\n from pydantic import BaseModel, ConfigDict; class M(BaseModel):
full
{"status": "error", "error_type": "CommandError", "error_message": "  File \"<string>\", line 1\n    from pydantic import BaseModel, ConfigDict; class M(BaseModel): model_config = ConfigDict(arbitrary_types_allowed=True); m = M(a=1); print(m.model_dump(mode='json'))\n                                                ^^^^^\nSyntaxError: invalid syntax\n", "details": {"stdout": "", "stderr": "  File \"<string>\", line 1\n    from pydantic import BaseModel, ConfigDict; class M(BaseModel): model_config = ConfigDict(arbitrary_types_allowed=True); m = M(a=1); print(m.model_dump(mode='json'))\n                                                ^^^^^\nSyntaxError: invalid syntax\n", "exit_code": 1}}
17run_command
{
 "command": "python3 - <<'PY'\nfrom pydantic import BaseModel, ConfigDict\nclass M(BaseModel):\n    model_config = ConfigDict(arbitrary_types_allowed=True)\n    a: int\nm = M(a=1)\nprint(m.model_dump(mode='json'))\nPY\n"
}
{"status": "ok", "stdout": "{'a': 1}\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "{'a': 1}\n", "stderr": "", "exit_code": 0}
18run_command
{
 "command": "python3 - <<'PY'\nfrom pydantic import BaseModel, ConfigDict\nclass MyCustomType:\n    def __init__(self, value):\n        self.value = value\nclass M(BaseModel):\n    model_config = ConfigDict(arbitrary_types_allowed=True)\n    a: MyCustomType\nm = M(a=MyCustomType(\"hello\"))\ntry:\n    print(m.model_dump(mode='json'))\nexcept Exception as e:\n    print(f\"Error: {e}\")\nPY\n"
}
{"status": "ok", "stdout": "Error: Unable to serialize unknown type: <class '__main__.MyCustomType'>\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "Error: Unable to serialize unknown type: <class '__main__.MyCustomType'>\n", "stderr": "", "exit_code": 0}
19run_command
{
 "command": "python3 - <<'PY'\nfrom pydantic import BaseModel, ConfigDict\nclass MyCustomType:\n    def __init__(self, value):\n        self.value = value\nclass M(BaseModel):\n    model_config = ConfigDict(arbitrary_types_allowed=True)\n    a: MyCustomType\nm = M(a=MyCustomType(\"hello\"))\ntry:\n    print(m.model_dump(mode='python'))\nexcept Exception as e:\n    print(f\"Error: {e}\")\nPY\n"
}
{"status": "ok", "stdout": "{'a': <__main__.MyCustomType object at 0x1040f9a90>}\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "{'a': <__main__.MyCustomType object at 0x1040f9a90>}\n", "stderr": "", "exit_code": 0}
20run_command
{
 "command": "python3 - <<'PY'\nfrom pydantic import BaseModel, ConfigDict\nclass MyCustomType:\n    def __init__(self, value):\n        self.value = value\nclass M(BaseModel):\n    model_config = ConfigDict(arbitrary_types_allowed=True)\n    a: MyCustomType\nm = M(a=MyCustomType(\"hello\"))\nprint(m.model_dump(mode='python'))\nfrom fastapi.encoders import jsonable_encoder\nprint(jsonable_encoder(m))\nPY\n"
}
{"status": "error", "error_type": "CommandError", "error_message": "Traceback (most recent call last):\n File \"<stdin>\", line 11, in <module>\n File \"/privat
full
{"status": "error", "error_type": "CommandError", "error_message": "Traceback (most recent call last):\n  File \"<stdin>\", line 11, in <module>\n  File \"/private/workspace/fastapi/encoders.py\", line 235, in jsonable_encoder\n    obj_dict = _model_dump(\n        obj,\n    ...<6 lines>...\n        exclude_defaults=exclude_defaults,\n    )\n  File \"/private/workspace/fastapi/_compat/main.py\", line 95, in _model_dump\n    return v2._model_dump(model, mode=mode, **kwargs)\n           ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/private/workspace/fastapi/_compat/v2.py\", line 167, in _model_dump\n    return model.model_dump(mode=mode, **kwargs)\n           ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^\n  File \"/Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/fastapi/lib/python3.13/site-packages/pydantic/main.py\", line 475, in model_dump\n    return self.__pydantic_serializer__.to_python(\n           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^\n        self,\n        ^^^^^\n    ...<13 lines>...\n        polymorphic_serialization=polymorphic_serialization,\n        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n    )\n    ^\npydantic_core._pydantic_core.PydanticSerializationError: Unable to serialize unknown type: <class '__main__.MyCustomType'>\n", "details": {"stdout": "{'a': <__main__.MyCustomType object at 0x1029d5a90>}\n", "stderr": "Traceback (most recent call last):\n  File \"<stdin>\", line 11, in <module>\n  File \"/private/workspace/fastapi/encoders.py\", line 235, in jsonable_encoder\n    obj_dict = _model_dump(\n        obj,\n    ...<6 lines>...\n        exclude_defaults=exclude_defaults,\n    )\n  File \"/private/workspace/fastapi/_compat/main.py\", line 95, in _model_dump\n    return v2._model_dump(model, mode=mode, **kwargs)\n           ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/private/workspace/fastapi/_compat/v2.py\", line 167, in _model_dump\n    return model.model_dump(mode=mode, **kwargs)\n           ~~~~~~~~~~~~~~~~^
21run_command
{
 "command": "python3 - <<'PY'\nfrom pydantic import BaseModel, ConfigDict\nclass MyCustomType:\n    def __init__(self, value):\n        self.value = value\nclass M(BaseModel):\n    model_config = ConfigDict(arbitrary_types_allowed=True)\n    a: MyCustomType\nm = M(a=MyCustomType(\"hello\"))\nprint(m.model_dump(mode='python'))\nfrom fastapi.encoders import jsonable_encoder\ntry:\n    print(jsonable_encoder(m))\nexcept Exception as e:\n    print(f\"Error: {e}\")\nPY\n"
}
{"status": "ok", "stdout": "{'a': <__main__.MyCustomType object at 0x1068a5a90>}\nError: Unable to serialize unknown type: <class '__main__.MyCustomType'>\n", "
full
{"status": "ok", "stdout": "{'a': <__main__.MyCustomType object at 0x1068a5a90>}\nError: Unable to serialize unknown type: <class '__main__.MyCustomType'>\n", "stderr": "", "exit_code": 0}
22run_command
{
 "command": "sed -n '230,245p' fastapi/encoders.py"
}
{"status": "ok", "stdout": " encoders: Dict[Any, Any] = {}\n if isinstance(obj, may_v1.BaseModel):\n encoders = getattr(obj.__config__, \"json_encoders\", {}) #
full
{"status": "ok", "stdout": "        encoders: Dict[Any, Any] = {}\n        if isinstance(obj, may_v1.BaseModel):\n            encoders = getattr(obj.__config__, \"json_encoders\", {})  # type: ignore[attr-defined]\n            if custom_encoder:\n                encoders = {**encoders, **custom_encoder}\n        obj_dict = _model_dump(\n            obj,\n            mode=\"json\",\n            include=include,\n            exclude=exclude,\n            by_alias=by_alias,\n            exclude_unset=exclude_unset,\n            exclude_none=exclude_none,\n            exclude_defaults=exclude_defaults,\n        )\n        if \"__root__\" in obj_dict:\n", "stderr": "", "exit_code": 0}
23run_command
{
 "command": "python3 - <<'PY'\nfrom pydantic import BaseModel, ConfigDict\nclass MyCustomType:\n    def __init__(self, value):\n        self.value = value\nclass M(BaseModel):\n    model_config = ConfigDict(arbitrary_types_allowed=True)\n    a: MyCustomType\nm = M(a=MyCustomType(\"hello\"))\nprint(m.model_dump(mode='python'))\nfrom fastapi.encoders import jsonable_encoder\n# If we use mode='python' in _model_dump, it should work.\n# But jsonable_encoder is supposed to return something JSON serializable.\n# If we use mode='python', we get the MyCustomType object, which is not JSON serializable.\n# However, jsonable_encoder then recursively calls itself on the result.\n# So if we get the MyCustomType object, the recursive call to jsonable_encoder(MyCustomType object)\n# should handle it.\nPY\n"
}
{"status": "ok", "stdout": "{'a': <__main__.MyCustomType object at 0x1060dda90>}\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "{'a': <__main__.MyCustomType object at 0x1060dda90>}\n", "stderr": "", "exit_code": 0}
24run_command
{
 "command": "python3 - <<'PY'\nfrom pydantic import BaseModel, ConfigDict\nclass MyCustomType:\n    def __init__(self, value):\n        self.value = value\nclass M(BaseModel):\n    model_config = ConfigDict(arbitrary_types_allowed=True)\n    a: MyCustomType\nm = M(a=MyCustomType(\"hello\"))\nfrom fastapi.encoders import jsonable_encoder\n# Let's see what happens if we call jsonable_encoder on the custom object directly\ntry:\n    print(jsonable_encoder(m.a))\nexcept Exception as e:\n    print(f\"Error: {e}\")\nPY\n"
}
{"status": "ok", "stdout": "{'value': 'hello'}\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "{'value': 'hello'}\n", "stderr": "", "exit_code": 0}
25run_command
{
 "command": "python3 - <<'PY'\nfrom pydantic import BaseModel, ConfigDict\nclass MyCustomType:\n    def __init__(self, value):\n        self.value = value\nclass M(BaseModel):\n    model_config = ConfigDict(arbitrary_types_allowed=True)\n    a: MyCustomType\nm = M(a=MyCustomType(\"hello\"))\nfrom fastapi.encoders import jsonable_encoder\n# If we use mode='python', we get the object, then jsonable_encoder(obj) handles it.\n# If we use mode='json', pydantic tries to serialize it and fails if it doesn't know how.\n# So the fix is to use mode='python' in _model_dump for Pydantic v2 models.\nPY\n"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
26run_command
{
 "command": "python3 - <<'PY'\nfrom pathlib import Path\np = Path(\"fastapi/encoders.py\"); s = p.read_text()\nold = \"\"\"        obj_dict = _model_dump(\n            obj,\n            mode=\"json\",\n            include=include,\"\"\"\nnew = \"\"\"        obj_dict = _model_dump(\n            obj,\n            mode=\"python\",\n            include=include,\"\"\"\nassert s.count(old) == 1, (\"old text found this many times:\", s.count(old))\nt = s.replace(old, new); p.write_text(t)\nPY\n"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
27run_command
{
 "command": "python3 /tmp/repro.py"
}
{"status": "ok", "stdout": "Encoded: {'custom': {'value': 'hello'}}\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "Encoded: {'custom': {'value': 'hello'}}\n", "stderr": "", "exit_code": 0}
28run_command
{
 "command": "python3 -m pytest tests/test_inherited_custom_class.py"
}
{"status": "ok", "stdout": "============================= test session starts ==============================\nplatform darwin -- Python 3.13.15, pytest-9.1.1, p
full
{"status": "ok", "stdout": "============================= test session starts ==============================\nplatform darwin -- Python 3.13.15, pytest-9.1.1, pluggy-1.6.0\ncodspeed: 5.0.3 (disabled, mode: walltime, callgraph: not supported, timer_resolution: 41.7ns)\nrootdir: /private/workspace\nconfigfile: pytest.ini (WARNING: ignoring pytest config in pyproject.toml!)\nplugins: cov-7.1.0, xdist-3.8.0, timeout-2.4.0, codspeed-5.0.3, sugar-1.1.1, anyio-4.15.1, inline-snapshot-0.35.4\ncollected 2 items\n\ntests/test_inherited_custom_class.py .s                                  [100%]\n\n=============================== warnings summary ===============================\n../../../../../../../Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-0.50.0-py3-none-any/starlette/testclient.py:45\n  /Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-0.50.0-py3-none-any/starlette/testclient.py:45: DeprecationWarning: The anyio.abc.BlockingPortal alias is deprecated, use anyio.from_thread.BlockingPortal instead.\n    _PortalFactoryType = Callable[[], AbstractContextManager[anyio.abc.BlockingPortal]]\n\n-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html\n=================== 1 passed, 1 skipped, 1 warning in 0.40s ====================\n", "stderr": "", "exit_code": 0}
29run_command
{
 "command": "python3 -m pytest tests/test_jsonable_encoder.py -k \"encode_model_with_pure_path\""
}
{"status": "ok", "stdout": "============================= test session starts ==============================\nplatform darwin -- Python 3.13.15, pytest-9.1.1, p
full
{"status": "ok", "stdout": "============================= test session starts ==============================\nplatform darwin -- Python 3.13.15, pytest-9.1.1, pluggy-1.6.0\ncodspeed: 5.0.3 (disabled, mode: walltime, callgraph: not supported, timer_resolution: 41.7ns)\nrootdir: /private/workspace\nconfigfile: pytest.ini (WARNING: ignoring pytest config in pyproject.toml!)\nplugins: cov-7.1.0, xdist-3.8.0, timeout-2.4.0, codspeed-5.0.3, sugar-1.1.1, anyio-4.15.1, inline-snapshot-0.35.4\ncollected 23 items / 22 deselected / 1 selected\n\ntests/test_jsonable_encoder.py .                                         [100%]\n\n======================= 1 passed, 22 deselected in 0.33s =======================\n", "stderr": "", "exit_code": 0}
30run_command
{
 "command": "python3 -m pytest tests/test_jsonable_encoder.py"
}
{"status": "ok", "stdout": "============================= test session starts ==============================\nplatform darwin -- Python 3.13.15, pytest-9.1.1, p
full
{"status": "ok", "stdout": "============================= test session starts ==============================\nplatform darwin -- Python 3.13.15, pytest-9.1.1, pluggy-1.6.0\ncodspeed: 5.0.3 (disabled, mode: walltime, callgraph: not supported, timer_resolution: 41.7ns)\nrootdir: /private/workspace\nconfigfile: pytest.ini (WARNING: ignoring pytest config in pyproject.toml!)\nplugins: cov-7.1.0, xdist-3.8.0, timeout-2.4.0, codspeed-5.0.3, sugar-1.1.1, anyio-4.15.1, inline-snapshot-0.35.4\ncollected 23 items\n\ntests/test_jsonable_encoder.py ......s....s....s......                   [100%]\n\n======================== 20 passed, 3 skipped in 0.30s =========================\n", "stderr": "", "exit_code": 0}
31run_command
{
 "command": "python3 -m pytest tests/test_compat.py"
}
{"status": "ok", "stdout": "============================= test session starts ==============================\nplatform darwin -- Python 3.13.15, pytest-9.1.1, p
full
{"status": "ok", "stdout": "============================= test session starts ==============================\nplatform darwin -- Python 3.13.15, pytest-9.1.1, pluggy-1.6.0\ncodspeed: 5.0.3 (disabled, mode: walltime, callgraph: not supported, timer_resolution: 41.7ns)\nrootdir: /private/workspace\nconfigfile: pytest.ini (WARNING: ignoring pytest config in pyproject.toml!)\nplugins: cov-7.1.0, xdist-3.8.0, timeout-2.4.0, codspeed-5.0.3, sugar-1.1.1, anyio-4.15.1, inline-snapshot-0.35.4\ncollected 13 items\n\ntests/test_compat.py .s.........ss                                       [100%]\n\n=============================== warnings summary ===============================\n../../../../../../../Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-0.50.0-py3-none-any/starlette/testclient.py:45\n  /Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-0.50.0-py3-none-any/starlette/testclient.py:45: DeprecationWarning: The anyio.abc.BlockingPortal alias is deprecated, use anyio.from_thread.BlockingPortal instead.\n    _PortalFactoryType = Callable[[], AbstractContextManager[anyio.abc.BlockingPortal]]\n\n-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html\n=================== 10 passed, 3 skipped, 1 warning in 0.38s ===================\n", "stderr": "", "exit_code": 0}
32run_command
{
 "command": "git diff"
}
{"status": "ok", "stdout": "diff --git a/fastapi/encoders.py b/fastapi/encoders.py\nindex 79395108..ec754986 100644\n--- a/fastapi/encoders.py\n+++ b/fastapi/en
full
{"status": "ok", "stdout": "diff --git a/fastapi/encoders.py b/fastapi/encoders.py\nindex 79395108..ec754986 100644\n--- a/fastapi/encoders.py\n+++ b/fastapi/encoders.py\n@@ -234,7 +234,7 @@ def jsonable_encoder(\n                 encoders = {**encoders, **custom_encoder}\n         obj_dict = _model_dump(\n             obj,\n-            mode=\"json\",\n+            mode=\"python\",\n             include=include,\n             exclude=exclude,\n             by_alias=by_alias,\n", "stderr": "", "exit_code": 0}
33run_command
{
 "command": "python3 - <<'PY'\nfrom pydantic import BaseModel, ConfigDict\nclass MyCustomType:\n    def __init__(self, value):\n        self.value = value\nclass M(BaseModel):\n    model_config = ConfigDict(arbitrary_types_allowed=True)\n    a: MyCustomType\nm = M(a=MyCustomType(\"hello\"))\nfrom fastapi.encoders import jsonable_encoder\nencoded = jsonable_encoder(m)\nprint(f\"Encoded: {encoded}\")\n# Verify that it is actually JSON serializable (e.g. by using json.dumps)\nimport json\ntry:\n    json.dumps(encoded)\n    print(\"Successfully dumped to JSON\")\nexcept Exception as e:\n    print(f\"JSON dump failed: {e}\")\nPY\n"
}
{"status": "ok", "stdout": "Encoded: {'a': {'value': 'hello'}}\nSuccessfully dumped to JSON\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "Encoded: {'a': {'value': 'hello'}}\nSuccessfully dumped to JSON\n", "stderr": "", "exit_code": 0}
34run_command
{
 "command": "submit_patch"
}
{"status": "error", "error_type": "CommandError", "error_message": "/bin/bash: submit_patch: command not found\n", "details": {"stdout": "", "stderr": "/bin/bas
full
{"status": "error", "error_type": "CommandError", "error_message": "/bin/bash: submit_patch: command not found\n", "details": {"stdout": "", "stderr": "/bin/bash: submit_patch: command not found\n", "exit_code": 127}}
35submit_patch
{}
{"status": "ok", "patch_size": 437, "files_changed": 1}
full
{"status": "ok", "patch_size": 437, "files_changed": 1}

Patch

diff --git a/fastapi/encoders.py b/fastapi/encoders.py
index 79395108..ec754986 100644
--- a/fastapi/encoders.py
+++ b/fastapi/encoders.py
@@ -234,7 +234,7 @@ def jsonable_encoder(
                 encoders = {**encoders, **custom_encoder}
         obj_dict = _model_dump(
             obj,
-            mode="json",
+            mode="python",
             include=include,
             exclude=exclude,
             by_alias=by_alias,

Test output

show
ite-packages/pydantic/_internal/_generate_schema.py:1022: in _generate_schema_inner
    return self._annotated_schema(obj)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
/Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/fastapi/lib/python3.13/site-packages/pydantic/_internal/_generate_schema.py:2202: in _annotated_schema
    schema = self._apply_annotations(source_type, annotations)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/fastapi/lib/python3.13/site-packages/pydantic/_internal/_generate_schema.py:2252: in _apply_annotations
    schema = get_inner_schema(source_type)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/fastapi/lib/python3.13/site-packages/pydantic/_internal/_schema_generation_shared.py:83: in __call__
    schema = self._handler(source_type)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
/Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/fastapi/lib/python3.13/site-packages/pydantic/_internal/_generate_schema.py:2425: in new_handler
    schema = get_inner_schema(source)
             ^^^^^^^^^^^^^^^^^^^^^^^^
/Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/fastapi/lib/python3.13/site-packages/pydantic/_internal/_schema_generation_shared.py:83: in __call__
    schema = self._handler(source_type)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
/Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/fastapi/lib/python3.13/site-packages/pydantic/_internal/_generate_schema.py:2423: in new_handler
    schema = annotation_get_schema(source, get_inner_schema)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/fastapi/lib/python3.13/site-packages/pydantic/functional_serializers.py:64: in __get_pydantic_core_schema__
    schema = handler(source_type)
             ^^^^^^^^^^^^^^^^^^^^
/Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/fastapi/lib/python3.13/site-packages/pydantic/_internal/_schema_generation_shared.py:83: in __call__
    schema = self._handler(source_type)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
/Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/fastapi/lib/python3.13/site-packages/pydantic/_internal/_generate_schema.py:2425: in new_handler
    schema = get_inner_schema(source)
             ^^^^^^^^^^^^^^^^^^^^^^^^
/Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/fastapi/lib/python3.13/site-packages/pydantic/_internal/_schema_generation_shared.py:83: in __call__
    schema = self._handler(source_type)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
/Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/fastapi/lib/python3.13/site-packages/pydantic/_internal/_generate_schema.py:2231: in inner_handler
    schema = self._generate_schema_inner(obj)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/fastapi/lib/python3.13/site-packages/pydantic/_internal/_generate_schema.py:1043: in _generate_schema_inner
    return self.match_type(obj)
           ^^^^^^^^^^^^^^^^^^^^
/Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/fastapi/lib/python3.13/site-packages/pydantic/_internal/_generate_schema.py:1165: in match_type
    return self._unknown_type_schema(obj)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <pydantic._internal._generate_schema.GenerateSchema object at 0x110e72b10>
obj = <class 'tests.test_arbitrary_types.get_client.<locals>.FakeNumpyArray'>

    def _unknown_type_schema(self, obj: Any) -> CoreSchema:
>       raise PydanticSchemaGenerationError(
            f'Unable to generate pydantic-core schema for {obj!r}. '
            'Set `arbitrary_types_allowed=True` in the model_config to ignore this error'
            ' or implement `__get_pydantic_core_schema__` on your type to fully support it.'
            '\n\nIf you got this error by calling handler(<some type>) within'
            ' `__get_pydantic_core_schema__` then you likely need to call'
            ' `handler.generate_schema(<some type>)` since we do not call'
            ' `__get_pydantic_core_schema__` on `<some type>` otherwise to avoid infinite recursion.'
        )
E       pydantic.errors.PydanticSchemaGenerationError: Unable to generate pydantic-core schema for <class 'tests.test_arbitrary_types.get_client.<locals>.FakeNumpyArray'>. Set `arbitrary_types_allowed=True` in the model_config to ignore this error or implement `__get_pydantic_core_schema__` on your type to fully support it.
E       
E       If you got this error by calling handler(<some type>) within `__get_pydantic_core_schema__` then you likely need to call `handler.generate_schema(<some type>)` since we do not call `__get_pydantic_core_schema__` on `<some type>` otherwise to avoid infinite recursion.
E       
E       For further information visit https://errors.pydantic.dev/2.13/u/schema-for-unknown-type

/Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/fastapi/lib/python3.13/site-packages/pydantic/_internal/_generate_schema.py:674: PydanticSchemaGenerationError
=============================== warnings summary ===============================
../../../../../../../Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-0.50.0-py3-none-any/starlette/testclient.py:45
  /Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-0.50.0-py3-none-any/starlette/testclient.py:45: 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, 2 passed, 1 warning in 0.68s