← eval_submission_analyzer

fastapi_13920

failed WRONG_FIX wrong_fix · 14 tool calls · 76 s · fastapi/fastapi

Task input

✨ Add support for PEP695 `TypeAliasType`

This is a continuation of #11140 with the comment by @Viicos fixed by vendoring a copy of `is_typealiastype` from [`typing-inspection`](https://github.com/pydantic/typing-inspection).

Tool calls (15)

#ToolArgumentsResult
1run_command
{
 "command": "grep -rn \"TypeAlias\" . | head -20"
}
{"status": "ok", "stdout": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "exit_code": 0}
2run_command
{
 "command": "grep -rn \"get_type_hints\" . | head -20"
}
{"status": "ok", "stdout": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "exit_code": 0}
3run_command
{
 "command": "find . -maxdepth 3 -type d"
}
{"status": "ok", "stdout": ".\n./fastapi\n./fastapi/dependencies\n./fastapi/_compat\n./fastapi/security\n./fastapi/middleware\n./fastapi/openapi\n./scripts\n./s
full
{"status": "ok", "stdout": ".\n./fastapi\n./fastapi/dependencies\n./fastapi/_compat\n./fastapi/security\n./fastapi/middleware\n./fastapi/openapi\n./scripts\n./scripts/tests\n./scripts/tests/test_translation_fixer\n./scripts/playwright\n./scripts/playwright/cookie_param_models\n./scripts/playwright/query_param_models\n./scripts/playwright/sql_databases\n./scripts/playwright/separate_openapi_schemas\n./scripts/playwright/header_param_models\n./scripts/playwright/request_form_models\n./tests\n./tests/test_request_params\n./tests/test_request_params/test_file\n./tests/test_request_params/test_form\n./tests/test_request_params/test_cookie\n./tests/test_request_params/test_path\n./tests/test_request_params/test_body\n./tests/test_request_params/test_query\n./tests/test_request_params/test_header\n./tests/test_modules_same_name_body\n./tests/test_modules_same_name_body/app\n./tests/benchmarks\n./tests/test_validate_response_recursive\n./tests/test_tutorial\n./tests/test_tutorial/test_request_forms_and_files\n./tests/test_tutorial/test_header_param_models\n./tests/test_tutorial/test_cookie_params\n./tests/test_tutorial/test_schema_extra_example\n./tests/test_tutorial/test_response_model\n./tests/test_tutorial/test_encoder\n./tests/test_tutorial/test_middleware\n./tests/test_tutorial/test_response_change_status_code\n./tests/test_tutorial/test_body_updates\n./tests/test_tutorial/test_body_multiple_params\n./tests/test_tutorial/test_events\n./tests/test_tutorial/test_openapi_webhooks\n./tests/test_tutorial/test_request_files\n./tests/test_tutorial/test_async_tests\n./tests/test_tutorial/test_settings\n./tests/test_tutorial/test_security\n./tests/test_tutorial/test_python_types\n./tests/test_tutorial/test_additional_status_codes\n./tests/test_tutorial/test_body_nested_models\n./tests/test_tutorial/test_path_operation_configurations\n./tests/test_tutorial/test_conditional_openapi\n./tests/test_tutorial/test_dependencies\n./tests/test_tutorial/test_header_params\n./tests/test_tu
4run_command
{
 "command": "grep -rn \"typing\" fastapi | head -20"
}
{"status": "ok", "stdout": "fastapi/datastructures.py:2:from typing import (\nfastapi/datastructures.py:39: from typing import Annotated\nfastapi/dependencies/m
full
{"status": "ok", "stdout": "fastapi/datastructures.py:2:from typing import (\nfastapi/datastructures.py:39:    from typing import Annotated\nfastapi/dependencies/models.py:5:from typing import Any, Callable, Optional, Union\nfastapi/dependencies/models.py:10:from typing_extensions import Literal\nfastapi/dependencies/utils.py:8:from typing import (\nfastapi/dependencies/utils.py:68:from typing_extensions import Literal, get_args, get_origin\nfastapi/dependencies/utils.py:838:    # Check if it's a Union type (covers both typing.Union and types.UnionType in Python 3.10+)\nfastapi/_compat/shared.py:3:import typing\nfastapi/_compat/shared.py:8:from typing import (\nfastapi/_compat/shared.py:18:from typing_extensions import get_args, get_origin\nfastapi/_compat/shared.py:20:# Copy from Pydantic: pydantic/_internal/_typing_extra.py\nfastapi/_compat/shared.py:22:    WithArgsTypes: tuple[Any, ...] = (typing._GenericAlias, types.GenericAlias)  # type: ignore[attr-defined]\nfastapi/_compat/shared.py:25:        typing._GenericAlias,  # type: ignore[attr-defined]\nfastapi/_compat/v2.py:8:from typing import (\nfastapi/_compat/v2.py:25:from pydantic._internal._typing_extra import eval_type_lenient\nfastapi/_compat/v2.py:33:from typing_extensions import Literal, get_args, get_origin\nfastapi/applications.py:3:from typing import (\nfastapi/applications.py:43:from typing_extensions import deprecated\nfastapi/applications.py:4602:        from typing import Awaitable, Callable\nfastapi/exceptions.py:2:from typing import Annotated, Any, Optional, TypedDict, Union\n", "exit_code": 0}
5read_file
{
 "filepath": "fastapi/_compat/shared.py",
 "start_line": 1,
 "end_line": 40
}
{"status": "ok", "filepath": "fastapi/_compat/shared.py", "content": "import sys\nimport types\nimport typing\nimport warnings\nfrom collections import deque\nf
full
{"status": "ok", "filepath": "fastapi/_compat/shared.py", "content": "import sys\nimport types\nimport typing\nimport warnings\nfrom collections import deque\nfrom collections.abc import Mapping, Sequence\nfrom dataclasses import is_dataclass\nfrom typing import (\n    Annotated,\n    Any,\n    Union,\n)\n\nfrom fastapi.types import UnionType\nfrom pydantic import BaseModel\nfrom pydantic.version import VERSION as PYDANTIC_VERSION\nfrom starlette.datastructures import UploadFile\nfrom typing_extensions import get_args, get_origin\n\n# Copy from Pydantic: pydantic/_internal/_typing_extra.py\nif sys.version_info < (3, 10):\n    WithArgsTypes: tuple[Any, ...] = (typing._GenericAlias, types.GenericAlias)  # type: ignore[attr-defined]\nelse:\n    WithArgsTypes: tuple[Any, ...] = (\n        typing._GenericAlias,  # type: ignore[attr-defined]\n        types.GenericAlias,\n        types.UnionType,\n    )  # pyright: ignore[reportAttributeAccessIssue]\n\nPYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\nPYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2\n\n\nsequence_annotation_to_type = {\n    Sequence: list,\n    list: list,\n    tuple: tuple,\n    set: set,\n    frozenset: frozenset,\n    deque: deque,\n", "start_line": 1, "end_line": 40, "total_lines": 206, "is_truncated": false}
6run_command
{
 "command": "grep -rn \"get_origin\" fastapi | head -20"
}
{"status": "ok", "stdout": "fastapi/dependencies/utils.py:68:from typing_extensions import Literal, get_args, get_origin\nfastapi/dependencies/utils.py:377: if
full
{"status": "ok", "stdout": "fastapi/dependencies/utils.py:68:from typing_extensions import Literal, get_args, get_origin\nfastapi/dependencies/utils.py:377:    if get_origin(use_annotation) is Annotated:\nfastapi/dependencies/utils.py:836:    origin = get_origin(field_type)\nfastapi/_compat/shared.py:18:from typing_extensions import get_args, get_origin\nfastapi/_compat/shared.py:67:    origin = get_origin(annotation)\nfastapi/_compat/shared.py:74:        get_origin(annotation)\nfastapi/_compat/shared.py:91:    origin = get_origin(annotation)\nfastapi/_compat/shared.py:112:    origin = get_origin(annotation)\nfastapi/_compat/shared.py:131:    origin = get_origin(annotation)\nfastapi/_compat/shared.py:142:    origin = get_origin(annotation)\nfastapi/_compat/shared.py:151:    origin = get_origin(annotation)\nfastapi/_compat/shared.py:166:    origin = get_origin(annotation)\nfastapi/_compat/shared.py:197:    origin = get_origin(annotation)\nfastapi/_compat/v2.py:33:from typing_extensions import Literal, get_args, get_origin\nfastapi/_compat/v2.py:432:    origin_type = get_origin(field.field_info.annotation) or field.field_info.annotation\nfastapi/_compat/v2.py:438:            origin_type = get_origin(union_arg) or union_arg\nfastapi/_compat/v2.py:525:    origin = get_origin(annotation)\n", "exit_code": 0}
7read_file
{
 "end_line": 206,
 "filepath": "fastapi/_compat/shared.py",
 "start_line": 41
}
{"status": "ok", "filepath": "fastapi/_compat/shared.py", "content": "}\n\nsequence_types = tuple(sequence_annotation_to_type.keys())\n\nUrl: type[Any]\n\n\n# C
full
{"status": "ok", "filepath": "fastapi/_compat/shared.py", "content": "}\n\nsequence_types = tuple(sequence_annotation_to_type.keys())\n\nUrl: type[Any]\n\n\n# Copy of Pydantic: pydantic/_internal/_utils.py\ndef lenient_issubclass(\n    cls: Any, class_or_tuple: Union[type[Any], tuple[type[Any], ...], None]\n) -> bool:\n    try:\n        return isinstance(cls, type) and issubclass(cls, class_or_tuple)  # type: ignore[arg-type]\n    except TypeError:  # pragma: no cover\n        if isinstance(cls, WithArgsTypes):\n            return False\n        raise  # pragma: no cover\n\n\ndef _annotation_is_sequence(annotation: Union[type[Any], None]) -> bool:\n    if lenient_issubclass(annotation, (str, bytes)):\n        return False\n    return lenient_issubclass(annotation, sequence_types)\n\n\ndef field_annotation_is_sequence(annotation: Union[type[Any], None]) -> bool:\n    origin = get_origin(annotation)\n    if origin is Union or origin is UnionType:\n        for arg in get_args(annotation):\n            if field_annotation_is_sequence(arg):\n                return True\n        return False\n    return _annotation_is_sequence(annotation) or _annotation_is_sequence(\n        get_origin(annotation)\n    )\n\n\ndef value_is_sequence(value: Any) -> bool:\n    return isinstance(value, sequence_types) and not isinstance(value, (str, bytes))\n\n\ndef _annotation_is_complex(annotation: Union[type[Any], None]) -> bool:\n    return (\n        lenient_issubclass(annotation, (BaseModel, Mapping, UploadFile))\n        or _annotation_is_sequence(annotation)\n        or is_dataclass(annotation)\n    )\n\n\ndef field_annotation_is_complex(annotation: Union[type[Any], None]) -> bool:\n    origin = get_origin(annotation)\n    if origin is Union or origin is UnionType:\n        return any(field_annotation_is_complex(arg) for arg in get_args(annotation))\n\n    if origin is Annotated:\n        return field_annotation_is_complex(get_args(annotation)[0])\n\n    return (\n        _annotation_i
8run_command
{
 "command": "grep -rn \"is_typealiastype\" ."
}
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "", "stderr": "", "exit_code": 1}}
full
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "", "stderr": "", "exit_code": 1}}
9run_command
{
 "command": "grep -rn \"is_typealias\" ."
}
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "", "stderr": "", "exit_code": 1}}
full
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "", "stderr": "", "exit_code": 1}}
10read_file
{
 "filepath": "fastapi/_compat/shared.py"
}
{"status": "ok", "filepath": "fastapi/_compat/shared.py", "content": "import sys\nimport types\nimport typing\nimport warnings\nfrom collections import deque\nf
full
{"status": "ok", "filepath": "fastapi/_compat/shared.py", "content": "import sys\nimport types\nimport typing\nimport warnings\nfrom collections import deque\nfrom collections.abc import Mapping, Sequence\nfrom dataclasses import is_dataclass\nfrom typing import (\n    Annotated,\n    Any,\n    Union,\n)\n\nfrom fastapi.types import UnionType\nfrom pydantic import BaseModel\nfrom pydantic.version import VERSION as PYDANTIC_VERSION\nfrom starlette.datastructures import UploadFile\nfrom typing_extensions import get_args, get_origin\n\n# Copy from Pydantic: pydantic/_internal/_typing_extra.py\nif sys.version_info < (3, 10):\n    WithArgsTypes: tuple[Any, ...] = (typing._GenericAlias, types.GenericAlias)  # type: ignore[attr-defined]\nelse:\n    WithArgsTypes: tuple[Any, ...] = (\n        typing._GenericAlias,  # type: ignore[attr-defined]\n        types.GenericAlias,\n        types.UnionType,\n    )  # pyright: ignore[reportAttributeAccessIssue]\n\nPYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\nPYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2\n\n\nsequence_annotation_to_type = {\n    Sequence: list,\n    list: list,\n    tuple: tuple,\n    set: set,\n    frozenset: frozenset,\n    deque: deque,\n}\n\nsequence_types = tuple(sequence_annotation_to_type.keys())\n\nUrl: type[Any]\n\n\n# Copy of Pydantic: pydantic/_internal/_utils.py\ndef lenient_issubclass(\n    cls: Any, class_or_tuple: Union[type[Any], tuple[type[Any], ...], None]\n) -> bool:\n    try:\n        return isinstance(cls, type) and issubclass(cls, class_or_tuple)  # type: ignore[arg-type]\n    except TypeError:  # pragma: no cover\n        if isinstance(cls, WithArgsTypes):\n            return False\n        raise  # pragma: no cover\n\n\ndef _annotation_is_sequence(annotation: Union[type[Any], None]) -> bool:\n    if lenient_issubclass(annotation, (str, bytes)):\n        return False\n    return lenient_issubclass(annotation, sequence_types)\n\n\ndef field_annotati
11edit_file
{
 "filepath": "fastapi/_compat/shared.py",
 "new_string": "else:\n    WithArgsTypes: tuple[Any, ...] = (\n        typing._GenericAlias,  # type: ignore[attr-defined]\n        types.GenericAlias,\n        types.UnionType,\n        getattr(types, \"TypeAliasType\", types.GenericAlias),\n    )  # pyright: ignore[reportAttributeAccessIssue]",
 "old_string": "else:\n    WithArgsTypes: tuple[Any, ...] = (\n        typing._GenericAlias,  # type: ignore[attr-defined]\n        types.GenericAlias,\n        types.UnionType,\n    )  # pyright: ignore[reportAttributeAccessIssue]"
}
{"status": "ok", "filepath": "fastapi/_compat/shared.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/_compat/shared.py\n+++ b/fastapi/_compat
full
{"status": "ok", "filepath": "fastapi/_compat/shared.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/_compat/shared.py\n+++ b/fastapi/_compat/shared.py\n@@ -25,6 +25,7 @@\n         typing._GenericAlias,  # type: ignore[attr-defined]\n         types.GenericAlias,\n         types.UnionType,\n+        getattr(types, \"TypeAliasType\", types.GenericAlias),\n     )  # pyright: ignore[reportAttributeAccessIssue]\n \n PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\n", "is_truncated": false}
12edit_file
{
 "filepath": "fastapi/_compat/shared.py",
 "new_string": "def is_typealiastype(annotation: Any) -> bool:\n    return isinstance(annotation, getattr(types, \"TypeAliasType\", type(None)))\n\n\n# Copy of Pydantic: pydantic/_internal/_utils.py",
 "old_string": "# Copy of Pydantic: pydantic/_internal/_utils.py"
}
{"status": "ok", "filepath": "fastapi/_compat/shared.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/_compat/shared.py\n+++ b/fastapi/_compat
full
{"status": "ok", "filepath": "fastapi/_compat/shared.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/_compat/shared.py\n+++ b/fastapi/_compat/shared.py\n@@ -46,6 +46,10 @@\n Url: type[Any]\n \n \n+def is_typealiastype(annotation: Any) -> bool:\n+    return isinstance(annotation, getattr(types, \"TypeAliasType\", type(None)))\n+\n+\n # Copy of Pydantic: pydantic/_internal/_utils.py\n def lenient_issubclass(\n     cls: Any, class_or_tuple: Union[type[Any], tuple[type[Any], ...], None]\n", "is_truncated": false}
13edit_file
{
 "filepath": "fastapi/_compat/shared.py",
 "new_string": "def field_annotation_is_sequence(annotation: Union[type[Any], None]) -> bool:\n    if is_typealiastype(annotation):\n        return field_annotation_is_sequence(annotation.__value__)\n    origin = get_origin(annotation)\n    if origin is Union or origin is UnionType:",
 "old_string": "def field_annotation_is_sequence(annotation: Union[type[Any], None]) -> bool:\n    origin = get_origin(annotation)\n    if origin is Union or origin is UnionType:"
}
{"status": "ok", "filepath": "fastapi/_compat/shared.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/_compat/shared.py\n+++ b/fastapi/_compat
full
{"status": "ok", "filepath": "fastapi/_compat/shared.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/_compat/shared.py\n+++ b/fastapi/_compat/shared.py\n@@ -69,6 +69,8 @@\n \n \n def field_annotation_is_sequence(annotation: Union[type[Any], None]) -> bool:\n+    if is_typealiastype(annotation):\n+        return field_annotation_is_sequence(annotation.__value__)\n     origin = get_origin(annotation)\n     if origin is Union or origin is UnionType:\n         for arg in get_args(annotation):\n", "is_truncated": false}
14edit_file
{
 "filepath": "fastapi/_compat/shared.py",
 "new_string": "def field_annotation_is_complex(annotation: Union[type[Any], None]) -> bool:\n    if is_typealiastype(annotation):\n        return field_annotation_is_complex(annotation.__value__)\n    origin = get_origin(annotation)\n    if origin is Union or origin is UnionType:",
 "old_string": "def field_annotation_is_complex(annotation: Union[type[Any], None]) -> bool:\n    origin = get_origin(annotation)\n    if origin is Union or origin is UnionType:"
}
{"status": "ok", "filepath": "fastapi/_compat/shared.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/_compat/shared.py\n+++ b/fastapi/_compat
full
{"status": "ok", "filepath": "fastapi/_compat/shared.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/_compat/shared.py\n+++ b/fastapi/_compat/shared.py\n@@ -95,6 +95,8 @@\n \n \n def field_annotation_is_complex(annotation: Union[type[Any], None]) -> bool:\n+    if is_typealiastype(annotation):\n+        return field_annotation_is_complex(annotation.__value__)\n     origin = get_origin(annotation)\n     if origin is Union or origin is UnionType:\n         return any(field_annotation_is_complex(arg) for arg in get_args(annotation))\n", "is_truncated": false}
15submit_patch
[]
{"status": "ok", "patch_size": 1743, "files_changed": 1}
full
{"status": "ok", "patch_size": 1743, "files_changed": 1}

Patch

diff --git a/fastapi/_compat/shared.py b/fastapi/_compat/shared.py
index 68b9bbdf..9850f5f3 100644
--- a/fastapi/_compat/shared.py
+++ b/fastapi/_compat/shared.py
@@ -25,6 +25,7 @@ else:
         typing._GenericAlias,  # type: ignore[attr-defined]
         types.GenericAlias,
         types.UnionType,
+        getattr(types, "TypeAliasType", types.GenericAlias),
     )  # pyright: ignore[reportAttributeAccessIssue]
 
 PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(".")[:2])
@@ -45,6 +46,10 @@ sequence_types = tuple(sequence_annotation_to_type.keys())
 Url: type[Any]
 
 
+def is_typealiastype(annotation: Any) -> bool:
+    return isinstance(annotation, getattr(types, "TypeAliasType", type(None)))
+
+
 # Copy of Pydantic: pydantic/_internal/_utils.py
 def lenient_issubclass(
     cls: Any, class_or_tuple: Union[type[Any], tuple[type[Any], ...], None]
@@ -64,6 +69,8 @@ def _annotation_is_sequence(annotation: Union[type[Any], None]) -> bool:
 
 
 def field_annotation_is_sequence(annotation: Union[type[Any], None]) -> bool:
+    if is_typealiastype(annotation):
+        return field_annotation_is_sequence(annotation.__value__)
     origin = get_origin(annotation)
     if origin is Union or origin is UnionType:
         for arg in get_args(annotation):
@@ -88,6 +95,8 @@ def _annotation_is_complex(annotation: Union[type[Any], None]) -> bool:
 
 
 def field_annotation_is_complex(annotation: Union[type[Any], None]) -> bool:
+    if is_typealiastype(annotation):
+        return field_annotation_is_complex(annotation.__value__)
     origin = get_origin(annotation)
     if origin is Union or origin is UnionType:
         return any(field_annotation_is_complex(arg) for arg in get_args(annotation))

Test output

show
F
=================================== FAILURES ===================================
________________________ test_pep695_type_dependencies _________________________

    def test_pep695_type_dependencies():
        app = FastAPI()
    
        @app.get("/")
        async def get_with_dep(value: DependedValue) -> str:  # noqa
            return f"value: {value}"
    
        client = TestClient(app)
        response = client.get("/")
>       assert response.status_code == 200
E       assert 422 == 200
E        +  where 422 = <Response [422 Unprocessable Entity]>.status_code

tests/test_dependency_pep695.py:26: AssertionError
=============================== warnings summary ===============================
../../../../../../kaggle/tmp/envs/overlays/starlette-0.50.0-py3-none-any/starlette/testclient.py:45
  /kaggle/tmp/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, 1 warning in 0.73s