← pod_r5_v1h

fastapi_14964

failed WRONG_FIX wrong_fix · 15 tool calls · 90 s · fastapi/fastapi

Task input

🗑️ Deprecate `ORJSONResponse` and `UJSONResponse`

🗑️ Deprecate `ORJSONResponse` and `UJSONResponse`

Now that there's better performance by default, with response models: https://github.com/fastapi/fastapi/pull/14962

This removes `ujson` and `orjson` from the `"fastapi[all]"` extras.

To use these responses, `ujson` or `orjson` need to be explicitly installed.

Tool calls (16)

#ToolArgumentsResult
1run_command
{
 "command": "grep -rn \"ORJSONResponse\" fastapi | head -20"
}
{"status": "ok", "stdout": "fastapi/responses.py:36:class ORJSONResponse(JSONResponse):\nfastapi/responses.py:45: assert orjson is not None, \"orjson must be in
full
{"status": "ok", "stdout": "fastapi/responses.py:36:class ORJSONResponse(JSONResponse):\nfastapi/responses.py:45:        assert orjson is not None, \"orjson must be installed to use ORJSONResponse\"\nfastapi/applications.py:369:                from fastapi.responses import ORJSONResponse\nfastapi/applications.py:371:                app = FastAPI(default_response_class=ORJSONResponse)\nfastapi/applications.py:1461:                from fastapi.responses import ORJSONResponse\nfastapi/applications.py:1469:                    default_response_class=ORJSONResponse,\n", "stderr": "", "exit_code": 0}
2run_command
{
 "command": "grep -rn \"UJSONResponse\" fastapi | head -20"
}
{"status": "ok", "stdout": "fastapi/responses.py:23:class UJSONResponse(JSONResponse):\nfastapi/responses.py:32: assert ujson is not None, \"ujson must be insta
full
{"status": "ok", "stdout": "fastapi/responses.py:23:class UJSONResponse(JSONResponse):\nfastapi/responses.py:32:        assert ujson is not None, \"ujson must be installed to use UJSONResponse\"\n", "stderr": "", "exit_code": 0}
3run_command
{
 "command": "sed -n '20,50p' fastapi/responses.py"
}
{"status": "ok", "stdout": " orjson = None # type: ignore\n\n\nclass UJSONResponse(JSONResponse):\n \"\"\"\n JSON response using the high-performance ujson libr
full
{"status": "ok", "stdout": "    orjson = None  # type: ignore\n\n\nclass UJSONResponse(JSONResponse):\n    \"\"\"\n    JSON response using the high-performance ujson library to serialize data to JSON.\n\n    Read more about it in the\n    [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/).\n    \"\"\"\n\n    def render(self, content: Any) -> bytes:\n        assert ujson is not None, \"ujson must be installed to use UJSONResponse\"\n        return ujson.dumps(content, ensure_ascii=False).encode(\"utf-8\")\n\n\nclass ORJSONResponse(JSONResponse):\n    \"\"\"\n    JSON response using the high-performance orjson library to serialize data to JSON.\n\n    Read more about it in the\n    [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/).\n    \"\"\"\n\n    def render(self, content: Any) -> bytes:\n        assert orjson is not None, \"orjson must be installed to use ORJSONResponse\"\n        return orjson.dumps(\n            content, option=orjson.OPT_NON_STR_KEYS | orjson.OPT_SERIALIZE_NUMPY\n        )\n", "stderr": "", "exit_code": 0}
4run_command
{
 "command": "grep -rn \"warn\" fastapi | head -20"
}
{"status": "ok", "stdout": "fastapi/params.py:1:import warnings\nfastapi/params.py:76: warnings.warn(\nfastapi/params.py:106: warnings.warn(\nfastapi/params.py:
full
{"status": "ok", "stdout": "fastapi/params.py:1:import warnings\nfastapi/params.py:76:            warnings.warn(\nfastapi/params.py:106:            warnings.warn(\nfastapi/params.py:521:            warnings.warn(\nfastapi/params.py:551:            warnings.warn(\nfastapi/applications.py:910:            logger.warning(\nfastapi/openapi/models.py:30:            logger.warning(\nfastapi/openapi/models.py:38:            logger.warning(\nfastapi/openapi/docs.py:334:                        level: \"warning\",\nfastapi/openapi/utils.py:4:import warnings\nfastapi/openapi/utils.py:218:    warnings.warn(\nfastapi/openapi/utils.py:254:        warnings.warn(message, stacklevel=1)\nfastapi/utils.py:2:import warnings\nfastapi/utils.py:83:    warnings.warn(\nfastapi/exceptions.py:254:    A custom deprecation warning as DeprecationWarning is ignored\nfastapi/exceptions.py:255:    Ref: https://sethmlarson.dev/deprecations-via-warnings-dont-work-for-python-libraries\nfastapi/_compat/shared.py:3:import warnings\nfastapi/_compat/shared.py:182:        with warnings.catch_warnings():\nfastapi/_compat/shared.py:183:            warnings.simplefilter(\"ignore\", UserWarning)\nfastapi/_compat/shared.py:194:        with warnings.catch_warnings():\n", "stderr": "", "exit_code": 0}
5run_command
{
 "command": "grep -rn \"deprecation\" fastapi | head -20"
}
{"status": "ok", "stdout": "fastapi/exceptions.py:254: A custom deprecation warning as DeprecationWarning is ignored\nfastapi/exceptions.py:255: Ref: https://se
full
{"status": "ok", "stdout": "fastapi/exceptions.py:254:    A custom deprecation warning as DeprecationWarning is ignored\nfastapi/exceptions.py:255:    Ref: https://sethmlarson.dev/deprecations-via-warnings-dont-work-for-python-libraries\n", "stderr": "", "exit_code": 0}
6run_command
{
 "command": "sed -n '1,40p' fastapi/responses.py"
}
{"status": "ok", "stdout": "from typing import Any\n\nfrom starlette.responses import FileResponse as FileResponse # noqa\nfrom starlette.responses import HTMLR
full
{"status": "ok", "stdout": "from typing import Any\n\nfrom starlette.responses import FileResponse as FileResponse  # noqa\nfrom starlette.responses import HTMLResponse as HTMLResponse  # noqa\nfrom starlette.responses import JSONResponse as JSONResponse  # noqa\nfrom starlette.responses import PlainTextResponse as PlainTextResponse  # noqa\nfrom starlette.responses import RedirectResponse as RedirectResponse  # noqa\nfrom starlette.responses import Response as Response  # noqa\nfrom starlette.responses import StreamingResponse as StreamingResponse  # noqa\n\ntry:\n    import ujson\nexcept ImportError:  # pragma: nocover\n    ujson = None  # type: ignore\n\n\ntry:\n    import orjson\nexcept ImportError:  # pragma: nocover\n    orjson = None  # type: ignore\n\n\nclass UJSONResponse(JSONResponse):\n    \"\"\"\n    JSON response using the high-performance ujson library to serialize data to JSON.\n\n    Read more about it in the\n    [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/).\n    \"\"\"\n\n    def render(self, content: Any) -> bytes:\n        assert ujson is not None, \"ujson must be installed to use UJSONResponse\"\n        return ujson.dumps(content, ensure_ascii=False).encode(\"utf-8\")\n\n\nclass ORJSONResponse(JSONResponse):\n    \"\"\"\n    JSON response using the high-performance orjson library to serialize data to JSON.\n\n    Read more about it in the\n", "stderr": "", "exit_code": 0}
7run_command
{
 "command": "grep -n \"import warnings\" fastapi/responses.py"
}
{"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}}
8run_command
{
 "command": "cd /workspace && python3 - <<'PY'\nfrom pathlib import Path\np = Path(\"fastapi/responses.py\")\ns = p.read_text()\n\n# Add warnings import at the top\nif \"import warnings\" not in s:\n    # Add it after the first line of imports or at the top\n    # Let's just put it at the top.\n    lines = s.splitlines()\n    lines.insert(0, \"import warnings\")\n    s = \"\\n\".join(lines)\n\n# Deprecate UJSONResponse\nold_ujson = \"\"\"class UJSONResponse(JSONResponse):\"\"\"\nnew_ujson = \"\"\"\nclass UJSONResponse(JSONResponse):\n    def __init__(self, *args, **kwargs):\n        warnings.warn(\n            \"UJSONResponse is deprecated. Use JSONResponse instead.\",\n            DeprecationWarning,\n            stacklevel=2,\n        )\n        super().__init__(*args, **kwargs)\"\"\"\n\n# Deprecate ORJSONResponse\nold_orjson = \"\"\"class ORJSONResponse(JSONResponse):\"\"\"\nnew_orjson = \"\"\"\nclass ORJSONResponse(JSONResponse):\n    def __init__(self, *args, **kwargs):\n        warnings.warn(\n            \"ORJSONResponse is deprecated. Use JSONResponse instead.\",\n            DeprecationWarning,\n            stacklevel=2,\n        )\n        super().__init__(*args, **kwargs)\"\"\"\n\n# Apply changes\n# Note: I should be careful with the double replace if the strings are too similar.\n# Actually, I'll use a more precise replacement for UJSONResponse and ORJSONResponse.\n# But the original strings are exactly as in the file.\n\n# Let's refine the replacements to avoid issues with multiple occurrences or overlapping.\n# I'll replace the class definition line and add the __init__ method.\n\n# For UJSONResponse\ns = s.replace(old_ujson, new_ujson.strip()) # Using strip() to avoid extra leading newline if not wanted, \n# but the way I wrote new_ujson has a leading newline.\n\n# Wait, if I just replace the class line, I need to make sure the indentation is correct.\n# The current code is:\n# class UJSONResponse(JSONResponse):\n#     \"\"\"\n#     ...\n#     \"\"\"\n#\n#     def render(self, content: Any) -> bytes:\n\n# I will do it more carefully.\n\nPY\n"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
9run_command
{
 "command": "cd /workspace && python3 - <<'PY'\nfrom pathlib import Path\np = Path(\"fastapi/responses.py\")\ns = p.read_text()\n\n# Add warnings import\nif \"import warnings\" not in s:\n    lines = s.splitlines()\n    lines.insert(0, \"import warnings\")\n    s = \"\\n\".join(lines)\n\n# Deprecate UJSONResponse\n# We want to insert __init__ after the docstring of UJSONResponse\n# UJSONResponse docstring ends before 'def render(self, content: Any) -> bytes:'\n# But the docstring is multiple lines.\n\n# Let's use a simpler approach. Find the line with 'class UJSONResponse(JSONResponse):'\n# and insert the __init__ after the docstring.\n\n# Actually, the most robust way in a small file is to replace the whole class or parts of it.\n# Let's find the range of UJSONResponse.\n\nimport re\n\n# UJSONResponse\nujson_match = re.search(r\"class UJSONResponse\\(JSONResponse\\):\", s)\nif ujson_match:\n    start = ujson_match.start()\n    # Find the end of the docstring by looking for the first 'def render'\n    render_match = re.search(r\"    def render\\(self, content: Any\\) -> bytes:\", s[start:])\n    if render_match:\n        insert_pos = start + render_match.start()\n        deprecation_init = (\n            \"    def __init__(self, *args, **kwargs):\\n\"\n            \"        warnings.warn(\\n\"\n            \"            \\\"UJSONResponse is deprecated. Use JSONResponse instead.\\\",\\n\"\n            \"            DeprecationWarning,\\n\"\n            \"            stacklevel=2,\\n\"\n            \"        )\\n\"\n            \"        super().__init__(*args, **kwargs)\\n\\n\"\n        )\n        s = s[:insert_pos] + deprecation_init + s[insert_pos:]\n\n# ORJSONResponse\n# Since we modified s, we need to search again.\norjson_match = re.search(r\"class ORJSONResponse\\(JSONResponse\\):\", s)\nif orjson_match:\n    start = orjson_match.start()\n    render_match = re.search(r\"    def render\\(self, content: Any\\) -> bytes:\", s[start:])\n    if render_match:\n        insert_pos = start + render_match.start()\n        deprecation_init = (\n            \"    def __init__(self, *args, **kwargs):\\n\"\n            \"        warnings.warn(\\n\"\n            \"            \\\"ORJSONResponse is deprecated. Use JSONResponse instead.\\\",\\n\"\n            \"            DeprecationWarning,\\n\"\n            \"            stacklevel=2,\\n\"\n            \"        )\\n\"\n            \"        super().__init__(*args, **kwargs)\\n\\n\"\n        )\n        s = s[:insert_pos] + deprecation_init + s[insert_pos:]\n\np.write_text(s)\nPY\n"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
10run_command
{
 "command": "sed -n '20,60p' fastapi/responses.py"
}
{"status": "ok", "stdout": "except ImportError: # pragma: nocover\n orjson = None # type: ignore\n\n\nclass UJSONResponse(JSONResponse):\n \"\"\"\n JSON respons
full
{"status": "ok", "stdout": "except ImportError:  # pragma: nocover\n    orjson = None  # type: ignore\n\n\nclass UJSONResponse(JSONResponse):\n    \"\"\"\n    JSON response using the high-performance ujson library to serialize data to JSON.\n\n    Read more about it in the\n    [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/).\n    \"\"\"\n\n    def __init__(self, *args, **kwargs):\n        warnings.warn(\n            \"UJSONResponse is deprecated. Use JSONResponse instead.\",\n            DeprecationWarning,\n            stacklevel=2,\n        )\n        super().__init__(*args, **kwargs)\n\n    def render(self, content: Any) -> bytes:\n        assert ujson is not None, \"ujson must be installed to use UJSONResponse\"\n        return ujson.dumps(content, ensure_ascii=False).encode(\"utf-8\")\n\n\nclass ORJSONResponse(JSONResponse):\n    \"\"\"\n    JSON response using the high-performance orjson library to serialize data to JSON.\n\n    Read more about it in the\n    [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/).\n    \"\"\"\n\n    def __init__(self, *args, **kwargs):\n        warnings.warn(\n            \"ORJSONResponse is deprecated. Use JSONResponse instead.\",\n            DeprecationWarning,\n            stacklevel=2,\n        )\n        super().__init__(*args, **kwargs)\n\n", "stderr": "", "exit_code": 0}
11run_command
{
 "command": "sed -n '60,80p' fastapi/responses.py"
}
{"status": "ok", "stdout": "\n def render(self, content: Any) -> bytes:\n assert orjson is not None, \"orjson must be installed to use ORJSONResponse\"\n return
full
{"status": "ok", "stdout": "\n    def render(self, content: Any) -> bytes:\n        assert orjson is not None, \"orjson must be installed to use ORJSONResponse\"\n        return orjson.dumps(\n            content, option=orjson.OPT_NON_STR_KEYS | orjson.OPT_SERIALIZE_NUMPY\n        )", "stderr": "", "exit_code": 0}
12run_command
{
 "command": "cd /workspace && python3 - <<'PY'\nimport warnings\nfrom fastapi.responses import UJSONResponse, ORJSONResponse\n\n# This should trigger a DeprecationWarning\ntry:\n    # Need to catch warnings to see them in the output\n    with warnings.catch_warnings(record=True) as w:\n        warnings.simplefilter(\"always\")\n        u = UJSONResponse({\"test\": \"ok\"})\n        print(f\"UJSONResponse warning: {w[-1].message}\")\nexcept Exception as e:\n    print(f\"UJSONResponse error: {e}\")\n\ntry:\n    with warnings.catch_warnings(record=True) as w:\n        warnings.simplefilter(\"always\")\n        o = ORJSONResponse({\"test\": \"ok\"})\n        print(f\"ORJSONResponse warning: {w[-1].message}\")\nexcept Exception as e:\n    print(f\"ORJSONResponse error: {e}\")\nPY\n"
}
{"status": "ok", "stdout": "UJSONResponse warning: UJSONResponse is deprecated. Use JSONResponse instead.\nORJSONResponse warning: ORJSONResponse is deprecated.
full
{"status": "ok", "stdout": "UJSONResponse warning: UJSONResponse is deprecated. Use JSONResponse instead.\nORJSONResponse warning: ORJSONResponse is deprecated. Use JSONResponse instead.\n", "stderr": "", "exit_code": 0}
13run_command
{
 "command": "python3 -m py_compile fastapi/responses.py"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
14run_command
{
 "command": "git diff"
}
{"status": "ok", "stdout": "diff --git a/fastapi/responses.py b/fastapi/responses.py\nindex 6c8db6f3..bf77a1f2 100644\n--- a/fastapi/responses.py\n+++ b/fastapi
full
{"status": "ok", "stdout": "diff --git a/fastapi/responses.py b/fastapi/responses.py\nindex 6c8db6f3..bf77a1f2 100644\n--- a/fastapi/responses.py\n+++ b/fastapi/responses.py\n@@ -1,3 +1,4 @@\n+import warnings\n from typing import Any\n \n from starlette.responses import FileResponse as FileResponse  # noqa\n@@ -28,6 +29,14 @@ class UJSONResponse(JSONResponse):\n     [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/).\n     \"\"\"\n \n+    def __init__(self, *args, **kwargs):\n+        warnings.warn(\n+            \"UJSONResponse is deprecated. Use JSONResponse instead.\",\n+            DeprecationWarning,\n+            stacklevel=2,\n+        )\n+        super().__init__(*args, **kwargs)\n+\n     def render(self, content: Any) -> bytes:\n         assert ujson is not None, \"ujson must be installed to use UJSONResponse\"\n         return ujson.dumps(content, ensure_ascii=False).encode(\"utf-8\")\n@@ -41,8 +50,16 @@ class ORJSONResponse(JSONResponse):\n     [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/).\n     \"\"\"\n \n+    def __init__(self, *args, **kwargs):\n+        warnings.warn(\n+            \"ORJSONResponse is deprecated. Use JSONResponse instead.\",\n+            DeprecationWarning,\n+            stacklevel=2,\n+        )\n+        super().__init__(*args, **kwargs)\n+\n     def render(self, content: Any) -> bytes:\n         assert orjson is not None, \"orjson must be installed to use ORJSONResponse\"\n         return orjson.dumps(\n             content, option=orjson.OPT_NON_STR_KEYS | orjson.OPT_SERIALIZE_NUMPY\n-        )\n+        )\n\\ No newline at end of file\n", "stderr": "", "exit_code": 0}
15run_command
{
 "command": "git status"
}
{"status": "ok", "stdout": "On branch main\nChanges not staged for commit:\n (use \"git add <file>...\" to update what will be committed)\n (use \"git restore <
full
{"status": "ok", "stdout": "On branch main\nChanges not staged for commit:\n  (use \"git add <file>...\" to update what will be committed)\n  (use \"git restore <file>...\" to discard changes in working directory)\n\tmodified:   fastapi/responses.py\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\n", "stderr": "", "exit_code": 0}
16submit_patch
{}
{"status": "ok", "patch_size": 1656, "files_changed": 1}
full
{"status": "ok", "patch_size": 1656, "files_changed": 1}

Patch

diff --git a/fastapi/responses.py b/fastapi/responses.py
index 6c8db6f3..bf77a1f2 100644
--- a/fastapi/responses.py
+++ b/fastapi/responses.py
@@ -1,3 +1,4 @@
+import warnings
 from typing import Any
 
 from starlette.responses import FileResponse as FileResponse  # noqa
@@ -28,6 +29,14 @@ class UJSONResponse(JSONResponse):
     [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/).
     """
 
+    def __init__(self, *args, **kwargs):
+        warnings.warn(
+            "UJSONResponse is deprecated. Use JSONResponse instead.",
+            DeprecationWarning,
+            stacklevel=2,
+        )
+        super().__init__(*args, **kwargs)
+
     def render(self, content: Any) -> bytes:
         assert ujson is not None, "ujson must be installed to use UJSONResponse"
         return ujson.dumps(content, ensure_ascii=False).encode("utf-8")
@@ -41,8 +50,16 @@ class ORJSONResponse(JSONResponse):
     [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/).
     """
 
+    def __init__(self, *args, **kwargs):
+        warnings.warn(
+            "ORJSONResponse is deprecated. Use JSONResponse instead.",
+            DeprecationWarning,
+            stacklevel=2,
+        )
+        super().__init__(*args, **kwargs)
+
     def render(self, content: Any) -> bytes:
         assert orjson is not None, "orjson must be installed to use ORJSONResponse"
         return orjson.dumps(
             content, option=orjson.OPT_NON_STR_KEYS | orjson.OPT_SERIALIZE_NUMPY
-        )
+        )
\ No newline at end of file

Test output

show
.F
=================================== FAILURES ===================================
________________ test_orjson_response_emits_deprecation_warning ________________

    def test_orjson_response_emits_deprecation_warning():
>       with pytest.warns(FastAPIDeprecationWarning, match="ORJSONResponse is deprecated"):
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       Failed: DID NOT WARN. No warnings of type (<class 'fastapi.exceptions.FastAPIDeprecationWarning'>,) were emitted.
E        Emitted warnings: [DeprecationWarning('ORJSONResponse is deprecated. Use JSONResponse instead.')].

tests/test_deprecated_responses.py:42: Failed
=============================== warnings summary ===============================
../../../../../../../Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-0.52.1-py3-none-any/starlette/testclient.py:45
  /Users/jp/repos/kaggle-gemini-coding-agent-post-training/.envs/overlays/starlette-0.52.1-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]]

tests/test_deprecated_responses.py::test_orjson_response_returns_correct_data
  /private/tmp/swe_work/pod_r5_v1h/fastapi_14964/b/workspace/fastapi/routing.py:475: DeprecationWarning: ORJSONResponse is deprecated. Use JSONResponse instead.
    response = actual_response_class(content, **response_args)

tests/test_deprecated_responses.py::test_orjson_response_emits_deprecation_warning
  /private/tmp/swe_work/pod_r5_v1h/fastapi_14964/b/workspace/tests/test_deprecated_responses.py:43: DeprecationWarning: ORJSONResponse is deprecated. Use JSONResponse instead.
    ORJSONResponse(content={"hello": "world"})

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 1 passed, 3 warnings in 0.84s