โ† eval_submission_analyzer

fastapi_14485

failed WRONG_FIX wrong_fix ยท 28 tool calls ยท 129 s ยท fastapi/fastapi

Task input

๐Ÿ› Fix support for `if TYPE_CHECKING`,  non-evaluated stringified annotations

๐Ÿ› Fix support for `if TYPE_CHECKING`,  non-evaluated stringified annotations

Related to https://github.com/fastapi/fastapi/discussions/14464, https://github.com/fastapi/fastapi/issues/14484, https://github.com/fastapi/fastapi/pull/11355

Tool calls (29)

#ToolArgumentsResult
1run_command
{
 "command": "grep -rn \"get_type_hints\" . | head -20"
}
{"status": "ok", "stdout": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "exit_code": 0}
2run_command
{
 "command": "grep -rn \"ForwardRef\" . | head -20"
}
{"status": "ok", "stdout": "./fastapi/dependencies/utils.py:12: ForwardRef,\n./fastapi/dependencies/utils.py:234: annotation = ForwardRef(annotation)\n./tests/f
full
{"status": "ok", "stdout": "./fastapi/dependencies/utils.py:12:    ForwardRef,\n./fastapi/dependencies/utils.py:234:        annotation = ForwardRef(annotation)\n./tests/forward_reference_type.py:4:def forwardref_method(input: \"ForwardRefModel\") -> \"ForwardRefModel\":\n./tests/forward_reference_type.py:5:    return ForwardRefModel(x=input.x + 1)\n./tests/forward_reference_type.py:8:class ForwardRefModel(BaseModel):\n", "exit_code": 0}
3read_file
{
 "end_line": 240,
 "filepath": "fastapi/dependencies/utils.py",
 "start_line": 1
}
{"status": "ok", "filepath": "fastapi/dependencies/utils.py", "content": "import dataclasses\nimport inspect\nimport sys\nfrom contextlib import AsyncExitStack,
full
{"status": "ok", "filepath": "fastapi/dependencies/utils.py", "content": "import dataclasses\nimport inspect\nimport sys\nfrom contextlib import AsyncExitStack, contextmanager\nfrom copy import copy, deepcopy\nfrom dataclasses import dataclass\nfrom typing import (\n    Any,\n    Callable,\n    Coroutine,\n    Dict,\n    ForwardRef,\n    List,\n    Mapping,\n    Optional,\n    Sequence,\n    Tuple,\n    Type,\n    Union,\n    cast,\n)\n\nimport anyio\nfrom fastapi import params\nfrom fastapi._compat import (\n    PYDANTIC_V2,\n    ModelField,\n    RequiredParam,\n    Undefined,\n    _is_error_wrapper,\n    _is_model_class,\n    copy_field_info,\n    create_body_model,\n    evaluate_forwardref,\n    field_annotation_is_scalar,\n    get_annotation_from_field_info,\n    get_cached_model_fields,\n    get_missing_field_error,\n    is_bytes_field,\n    is_bytes_sequence_field,\n    is_scalar_field,\n    is_scalar_sequence_field,\n    is_sequence_field,\n    is_uploadfile_or_nonable_uploadfile_annotation,\n    is_uploadfile_sequence_annotation,\n    lenient_issubclass,\n    may_v1,\n    sequence_types,\n    serialize_sequence_value,\n    value_is_sequence,\n)\nfrom fastapi._compat.shared import annotation_is_pydantic_v1\nfrom fastapi.background import BackgroundTasks\nfrom fastapi.concurrency import (\n    asynccontextmanager,\n    contextmanager_in_threadpool,\n)\nfrom fastapi.dependencies.models import Dependant\nfrom fastapi.exceptions import DependencyScopeError\nfrom fastapi.logger import logger\nfrom fastapi.security.oauth2 import SecurityScopes\nfrom fastapi.types import DependencyCacheKey\nfrom fastapi.utils import create_model_field, get_path_param_names\nfrom pydantic import BaseModel\nfrom pydantic.fields import FieldInfo\nfrom starlette.background import BackgroundTasks as StarletteBackgroundTasks\nfrom starlette.concurrency import run_in_threadpool\nfrom starlette.datastructures import (\n    FormData,\n    Headers,\n    ImmutableMultiDict,\n    QueryParams,\n
4read_file
{
 "end_line": 250,
 "filepath": "fastapi/dependencies/utils.py",
 "start_line": 230
}
{"status": "ok", "filepath": "fastapi/dependencies/utils.py", "content": "\n\ndef get_typed_annotation(annotation: Any, globalns: Dict[str, Any]) -> Any:\n if i
full
{"status": "ok", "filepath": "fastapi/dependencies/utils.py", "content": "\n\ndef get_typed_annotation(annotation: Any, globalns: Dict[str, Any]) -> Any:\n    if isinstance(annotation, str):\n        annotation = ForwardRef(annotation)\n        annotation = evaluate_forwardref(annotation, globalns, globalns)\n        if annotation is type(None):\n            return None\n    return annotation\n\n\ndef get_typed_return_annotation(call: Callable[..., Any]) -> Any:\n    if sys.version_info >= (3, 10):\n        signature = inspect.signature(call, eval_str=True)\n    else:\n        signature = inspect.signature(call)\n    unwrapped = inspect.unwrap(call)\n    annotation = signature.return_annotation\n\n    if annotation is inspect.Signature.empty:\n        return None\n", "start_line": 230, "end_line": 250, "total_lines": 1057, "is_truncated": false}
5run_command
{
 "command": "grep -rn \"evaluate_forwardref\" ."
}
{"status": "ok", "stdout": "./fastapi/dependencies/utils.py:34: evaluate_forwardref,\n./fastapi/dependencies/utils.py:235: annotation = evaluate_forwardref(anno
full
{"status": "ok", "stdout": "./fastapi/dependencies/utils.py:34:    evaluate_forwardref,\n./fastapi/dependencies/utils.py:235:        annotation = evaluate_forwardref(annotation, globalns, globalns)\n./fastapi/_compat/__init__.py:17:from .main import evaluate_forwardref as evaluate_forwardref\n./fastapi/_compat/v1.py:69:    from pydantic.typing import evaluate_forwardref as evaluate_forwardref\n./fastapi/_compat/v1.py:122:    from pydantic.v1.typing import evaluate_forwardref as evaluate_forwardref\n./fastapi/_compat/main.py:29:    from .v2 import evaluate_forwardref as evaluate_forwardref\n./fastapi/_compat/main.py:45:    from .v1 import evaluate_forwardref as evaluate_forwardref\n./fastapi/_compat/v2.py:50:evaluate_forwardref = eval_type_lenient\n", "exit_code": 0}
6read_file
{
 "end_line": 60,
 "filepath": "fastapi/_compat/v2.py",
 "start_line": 30
}
{"status": "ok", "filepath": "fastapi/_compat/v2.py", "content": "from pydantic.fields import FieldInfo as FieldInfo\nfrom pydantic.json_schema import GenerateJ
full
{"status": "ok", "filepath": "fastapi/_compat/v2.py", "content": "from pydantic.fields import FieldInfo as FieldInfo\nfrom pydantic.json_schema import GenerateJsonSchema as GenerateJsonSchema\nfrom pydantic.json_schema import JsonSchemaValue as JsonSchemaValue\nfrom pydantic_core import CoreSchema as CoreSchema\nfrom pydantic_core import PydanticUndefined, PydanticUndefinedType\nfrom pydantic_core import Url as Url\nfrom typing_extensions import Annotated, Literal, get_args, get_origin\n\ntry:\n    from pydantic_core.core_schema import (\n        with_info_plain_validator_function as with_info_plain_validator_function,\n    )\nexcept ImportError:  # pragma: no cover\n    from pydantic_core.core_schema import (\n        general_plain_validator_function as with_info_plain_validator_function,  # noqa: F401\n    )\n\nRequiredParam = PydanticUndefined\nUndefined = PydanticUndefined\nUndefinedType = PydanticUndefinedType\nevaluate_forwardref = eval_type_lenient\nValidator = Any\n\n\nclass BaseConfig:\n    pass\n\n\nclass ErrorWrapper(Exception):\n    pass\n\n", "start_line": 30, "end_line": 60, "total_lines": 517, "is_truncated": false}
7read_file
{
 "end_line": 100,
 "filepath": "fastapi/_compat/v2.py",
 "start_line": 1
}
{"status": "ok", "filepath": "fastapi/_compat/v2.py", "content": "import re\nimport warnings\nfrom copy import copy, deepcopy\nfrom dataclasses import dataclass
full
{"status": "ok", "filepath": "fastapi/_compat/v2.py", "content": "import re\nimport warnings\nfrom copy import copy, deepcopy\nfrom dataclasses import dataclass, is_dataclass\nfrom enum import Enum\nfrom typing import (\n    Any,\n    Dict,\n    List,\n    Sequence,\n    Set,\n    Tuple,\n    Type,\n    Union,\n    cast,\n)\n\nfrom fastapi._compat import may_v1, shared\nfrom fastapi.openapi.constants import REF_TEMPLATE\nfrom fastapi.types import IncEx, ModelNameMap, UnionType\nfrom pydantic import BaseModel, ConfigDict, TypeAdapter, create_model\nfrom pydantic import PydanticSchemaGenerationError as PydanticSchemaGenerationError\nfrom pydantic import PydanticUndefinedAnnotation as PydanticUndefinedAnnotation\nfrom pydantic import ValidationError as ValidationError\nfrom pydantic._internal._schema_generation_shared import (  # type: ignore[attr-defined]\n    GetJsonSchemaHandler as GetJsonSchemaHandler,\n)\nfrom pydantic._internal._typing_extra import eval_type_lenient\nfrom pydantic._internal._utils import lenient_issubclass as lenient_issubclass\nfrom pydantic.fields import FieldInfo as FieldInfo\nfrom pydantic.json_schema import GenerateJsonSchema as GenerateJsonSchema\nfrom pydantic.json_schema import JsonSchemaValue as JsonSchemaValue\nfrom pydantic_core import CoreSchema as CoreSchema\nfrom pydantic_core import PydanticUndefined, PydanticUndefinedType\nfrom pydantic_core import Url as Url\nfrom typing_extensions import Annotated, Literal, get_args, get_origin\n\ntry:\n    from pydantic_core.core_schema import (\n        with_info_plain_validator_function as with_info_plain_validator_function,\n    )\nexcept ImportError:  # pragma: no cover\n    from pydantic_core.core_schema import (\n        general_plain_validator_function as with_info_plain_validator_function,  # noqa: F401\n    )\n\nRequiredParam = PydanticUndefined\nUndefined = PydanticUndefined\nUndefinedType = PydanticUndefinedType\nevaluate_forwardref = eval_type_lenient\nValidator = Any\n\n\nclass Bas
8run_command
{
 "command": "grep -rn \"TYPE_CHECKING\" . | head -20"
}
{"status": "ok", "stdout": "./fastapi/utils.py:5: TYPE_CHECKING,\n./fastapi/utils.py:35:if TYPE_CHECKING: # pragma: nocover\n", "exit_code": 0}
full
{"status": "ok", "stdout": "./fastapi/utils.py:5:    TYPE_CHECKING,\n./fastapi/utils.py:35:if TYPE_CHECKING:  # pragma: nocover\n", "exit_code": 0}
9read_file
{
 "end_line": 100,
 "filepath": "fastapi/utils.py",
 "start_line": 1
}
{"status": "ok", "filepath": "fastapi/utils.py", "content": "import re\nimport warnings\nfrom dataclasses import is_dataclass\nfrom typing import (\n TYPE_CHECK
full
{"status": "ok", "filepath": "fastapi/utils.py", "content": "import re\nimport warnings\nfrom dataclasses import is_dataclass\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    Dict,\n    MutableMapping,\n    Optional,\n    Set,\n    Type,\n    Union,\n    cast,\n)\nfrom weakref import WeakKeyDictionary\n\nimport fastapi\nfrom fastapi._compat import (\n    PYDANTIC_V2,\n    BaseConfig,\n    ModelField,\n    PydanticSchemaGenerationError,\n    Undefined,\n    UndefinedType,\n    Validator,\n    annotation_is_pydantic_v1,\n    lenient_issubclass,\n    may_v1,\n)\nfrom fastapi.datastructures import DefaultPlaceholder, DefaultType\nfrom pydantic import BaseModel\nfrom pydantic.fields import FieldInfo\nfrom typing_extensions import Literal\n\nif TYPE_CHECKING:  # pragma: nocover\n    from .routing import APIRoute\n\n# Cache for `create_cloned_field`\n_CLONED_TYPES_CACHE: MutableMapping[Type[BaseModel], Type[BaseModel]] = (\n    WeakKeyDictionary()\n)\n\n\ndef is_body_allowed_for_status_code(status_code: Union[int, str, None]) -> bool:\n    if status_code is None:\n        return True\n    # Ref: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#patterned-fields-1\n    if status_code in {\n        \"default\",\n        \"1XX\",\n        \"2XX\",\n        \"3XX\",\n        \"4XX\",\n        \"5XX\",\n    }:\n        return True\n    current_status_code = int(status_code)\n    return not (current_status_code < 200 or current_status_code in {204, 205, 304})\n\n\ndef get_path_param_names(path: str) -> Set[str]:\n    return set(re.findall(\"{(.*?)}\", path))\n\n\n_invalid_args_message = (\n    \"Invalid args for response field! Hint: \"\n    \"check that {type_} is a valid Pydantic field type. \"\n    \"If you are using a return type annotation that is not a valid Pydantic \"\n    \"field (e.g. Union[Response, dict, None]) you can disable generating the \"\n    \"response model from the type annotation with the path operation decorator \"\n    \"pa
10run_command
{
 "command": "grep -rn \"get_type_hints\" ."
}
{"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}}
11run_command
{
 "command": "grep -rn \"inspect.signature\" . | head -20"
}
{"status": "ok", "stdout": "./fastapi/dependencies/utils.py:214: signature = inspect.signature(call, eval_str=True)\n./fastapi/dependencies/utils.py:216: signat
full
{"status": "ok", "stdout": "./fastapi/dependencies/utils.py:214:        signature = inspect.signature(call, eval_str=True)\n./fastapi/dependencies/utils.py:216:        signature = inspect.signature(call)\n./fastapi/dependencies/utils.py:243:        signature = inspect.signature(call, eval_str=True)\n./fastapi/dependencies/utils.py:245:        signature = inspect.signature(call)\n./fastapi/openapi/utils.py:347:                response_signature = inspect.signature(current_response_class.__init__)\n./tests/test_operations_signatures.py:9:    base_sig = inspect.signature(APIRouter.get)\n./tests/test_operations_signatures.py:13:        router_sig = inspect.signature(router_method)\n./tests/test_operations_signatures.py:14:        app_sig = inspect.signature(app_method)\n./tests/test_local_docs.py:7:    sig = inspect.signature(get_swagger_ui_html)\n./tests/test_local_docs.py:36:    sig = inspect.signature(get_redoc_html)\n", "exit_code": 0}
12read_file
{
 "filepath": "fastapi/dependencies/utils.py",
 "start_line": 200,
 "end_line": 250
}
{"status": "ok", "filepath": "fastapi/dependencies/utils.py", "content": " return fields\n\n\ndef get_flat_params(dependant: Dependant) -> List[ModelField]:\n f
full
{"status": "ok", "filepath": "fastapi/dependencies/utils.py", "content": "    return fields\n\n\ndef get_flat_params(dependant: Dependant) -> List[ModelField]:\n    flat_dependant = get_flat_dependant(dependant, skip_repeats=True)\n    path_params = _get_flat_fields_from_params(flat_dependant.path_params)\n    query_params = _get_flat_fields_from_params(flat_dependant.query_params)\n    header_params = _get_flat_fields_from_params(flat_dependant.header_params)\n    cookie_params = _get_flat_fields_from_params(flat_dependant.cookie_params)\n    return path_params + query_params + header_params + cookie_params\n\n\ndef get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:\n    if sys.version_info >= (3, 10):\n        signature = inspect.signature(call, eval_str=True)\n    else:\n        signature = inspect.signature(call)\n    unwrapped = inspect.unwrap(call)\n    globalns = getattr(unwrapped, \"__globals__\", {})\n    typed_params = [\n        inspect.Parameter(\n            name=param.name,\n            kind=param.kind,\n            default=param.default,\n            annotation=get_typed_annotation(param.annotation, globalns),\n        )\n        for param in signature.parameters.values()\n    ]\n    typed_signature = inspect.Signature(typed_params)\n    return typed_signature\n\n\ndef get_typed_annotation(annotation: Any, globalns: Dict[str, Any]) -> Any:\n    if isinstance(annotation, str):\n        annotation = ForwardRef(annotation)\n        annotation = evaluate_forwardref(annotation, globalns, globalns)\n        if annotation is type(None):\n            return None\n    return annotation\n\n\ndef get_typed_return_annotation(call: Callable[..., Any]) -> Any:\n    if sys.version_info >= (3, 10):\n        signature = inspect.signature(call, eval_str=True)\n    else:\n        signature = inspect.signature(call)\n    unwrapped = inspect.unwrap(call)\n    annotation = signature.return_annotation\n\n    if annotation is inspect.Signature.empty:\n      
13read_file
{
 "end_line": 100,
 "filepath": "fastapi/_compat/main.py",
 "start_line": 1
}
{"status": "ok", "filepath": "fastapi/_compat/main.py", "content": "import sys\nfrom functools import lru_cache\nfrom typing import (\n Any,\n Dict,\n List,\n S
full
{"status": "ok", "filepath": "fastapi/_compat/main.py", "content": "import sys\nfrom functools import lru_cache\nfrom typing import (\n    Any,\n    Dict,\n    List,\n    Sequence,\n    Tuple,\n    Type,\n)\n\nfrom fastapi._compat import may_v1\nfrom fastapi._compat.shared import PYDANTIC_V2, lenient_issubclass\nfrom fastapi.types import ModelNameMap\nfrom pydantic import BaseModel\nfrom typing_extensions import Literal\n\nfrom .model_field import ModelField\n\nif PYDANTIC_V2:\n    from .v2 import BaseConfig as BaseConfig\n    from .v2 import FieldInfo as FieldInfo\n    from .v2 import PydanticSchemaGenerationError as PydanticSchemaGenerationError\n    from .v2 import RequiredParam as RequiredParam\n    from .v2 import Undefined as Undefined\n    from .v2 import UndefinedType as UndefinedType\n    from .v2 import Url as Url\n    from .v2 import Validator as Validator\n    from .v2 import evaluate_forwardref as evaluate_forwardref\n    from .v2 import get_missing_field_error as get_missing_field_error\n    from .v2 import (\n        with_info_plain_validator_function as with_info_plain_validator_function,\n    )\nelse:\n    from .v1 import BaseConfig as BaseConfig  # type: ignore[assignment]\n    from .v1 import FieldInfo as FieldInfo\n    from .v1 import (  # type: ignore[assignment]\n        PydanticSchemaGenerationError as PydanticSchemaGenerationError,\n    )\n    from .v1 import RequiredParam as RequiredParam\n    from .v1 import Undefined as Undefined\n    from .v1 import UndefinedType as UndefinedType\n    from .v1 import Url as Url  # type: ignore[assignment]\n    from .v1 import Validator as Validator\n    from .v1 import evaluate_forwardref as evaluate_forwardref\n    from .v1 import get_missing_field_error as get_missing_field_error\n    from .v1 import (  # type: ignore[assignment]\n        with_info_plain_validator_function as with_info_plain_validator_function,\n    )\n\n\n@lru_cache\ndef get_cached_model_fields(model: Type[BaseModel]) -> List[ModelFiel
14read_file
{
 "end_line": 100,
 "filepath": "fastapi/_compat/v2.py",
 "start_line": 1
}
{"status": "ok", "filepath": "fastapi/_compat/v2.py", "content": "import re\nimport warnings\nfrom copy import copy, deepcopy\nfrom dataclasses import dataclass
full
{"status": "ok", "filepath": "fastapi/_compat/v2.py", "content": "import re\nimport warnings\nfrom copy import copy, deepcopy\nfrom dataclasses import dataclass, is_dataclass\nfrom enum import Enum\nfrom typing import (\n    Any,\n    Dict,\n    List,\n    Sequence,\n    Set,\n    Tuple,\n    Type,\n    Union,\n    cast,\n)\n\nfrom fastapi._compat import may_v1, shared\nfrom fastapi.openapi.constants import REF_TEMPLATE\nfrom fastapi.types import IncEx, ModelNameMap, UnionType\nfrom pydantic import BaseModel, ConfigDict, TypeAdapter, create_model\nfrom pydantic import PydanticSchemaGenerationError as PydanticSchemaGenerationError\nfrom pydantic import PydanticUndefinedAnnotation as PydanticUndefinedAnnotation\nfrom pydantic import ValidationError as ValidationError\nfrom pydantic._internal._schema_generation_shared import (  # type: ignore[attr-defined]\n    GetJsonSchemaHandler as GetJsonSchemaHandler,\n)\nfrom pydantic._internal._typing_extra import eval_type_lenient\nfrom pydantic._internal._utils import lenient_issubclass as lenient_issubclass\nfrom pydantic.fields import FieldInfo as FieldInfo\nfrom pydantic.json_schema import GenerateJsonSchema as GenerateJsonSchema\nfrom pydantic.json_schema import JsonSchemaValue as JsonSchemaValue\nfrom pydantic_core import CoreSchema as CoreSchema\nfrom pydantic_core import PydanticUndefined, PydanticUndefinedType\nfrom pydantic_core import Url as Url\nfrom typing_extensions import Annotated, Literal, get_args, get_origin\n\ntry:\n    from pydantic_core.core_schema import (\n        with_info_plain_validator_function as with_info_plain_validator_function,\n    )\nexcept ImportError:  # pragma: no cover\n    from pydantic_core.core_schema import (\n        general_plain_validator_function as with_info_plain_validator_function,  # noqa: F401\n    )\n\nRequiredParam = PydanticUndefined\nUndefined = PydanticUndefined\nUndefinedType = PydanticUndefinedType\nevaluate_forwardref = eval_type_lenient\nValidator = Any\n\n\nclass Bas
15write_file
{
 "content": "\nfrom typing import TYPE_CHECKING, Any, Dict\nfrom fastapi.dependencies.utils import get_typed_annotation\n\nif TYPE_CHECKING:\n    # This is only available during type checking\n    class SecretModel:\n        def __init__(self, x: int):\n            self.x = x\n\ndef test_forward_ref_type_checking():\n    # Simulate a function with a forward reference to a type only in TYPE_CHECKING\n    # In a real scenario, this would be in a module.\n    # We use a string annotation to simulate the forward reference.\n    \n    # We need a namespace that would normally contain SecretModel if it wasn't in TYPE_CHECKING\n    # But since it's in TYPE_CHECKING, it's NOT in the namespace at runtime.\n    globalns = {} \n    \n    # This should normally fail or return the string if it can't be resolved.\n    # The issue is that FastAPI tries to evaluate it and might fail or not handle it as expected.\n    annotation = \"SecretModel\"\n    result = get_typed_annotation(annotation, globalns)\n    \n    print(f\"Annotation: {annotation}, Result: {result}\")\n    # If it can't be resolved, it should probably remain a ForwardRef or the string, \n    # rather than crashing or returning None (unless it's actually None).\n    \n    # According to the issue, the goal is to \"Fix support for if TYPE_CHECKING, non-evaluated stringified annotations\"\n    # This often means that if it can't be resolved, it should be handled gracefully.\n\nif __name__ == \"__main__\":\n    test_forward_ref_type_checking()\n",
 "filepath": "/tmp/test_repro.py"
}
{"status": "ok", "filepath": "/tmp/test_repro.py", "size": 1461}
full
{"status": "ok", "filepath": "/tmp/test_repro.py", "size": 1461}
16run_command
{
 "command": "python3 /tmp/test_repro.py"
}
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 2", "details": {"stdout": "", "stderr": "python3: can't open f
full
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 2", "details": {"stdout": "", "stderr": "python3: can't open file '/tmp/swe_work/eval_submission_analyzer/fastapi_14485/a/tmp/test_repro.py': [Errno 2] No such file or directory\n", "exit_code": 2}}
17run_command
{
 "command": "python3 /workspace/tmp/test_repro.py"
}
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 2", "details": {"stdout": "", "stderr": "python3: can't open f
full
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 2", "details": {"stdout": "", "stderr": "python3: can't open file '/tmp/swe_work/eval_submission_analyzer/fastapi_14485/a/workspace/tmp/test_repro.py': [Errno 2] No such file or directory\n", "exit_code": 2}}
18run_command
{
 "command": "ls -R /workspace"
}
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 2", "details": {"stdout": "", "stderr": "ls: cannot access '/t
full
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 2", "details": {"stdout": "", "stderr": "ls: cannot access '/tmp/swe_work/eval_submission_analyzer/fastapi_14485/a/workspace': No such file or directory\n", "exit_code": 2}}
19run_command
{
 "command": "ls -R ."
}
{"status": "ok", "stdout": ".:\nCITATION.cff\nCONTRIBUTING.md\nLICENSE\nREADME.md\nSECURITY.md\ndocs\ndocs_src\nfastapi\npdm_build.py\npyproject.toml\npytest.in
full
{"status": "ok", "stdout": ".:\nCITATION.cff\nCONTRIBUTING.md\nLICENSE\nREADME.md\nSECURITY.md\ndocs\ndocs_src\nfastapi\npdm_build.py\npyproject.toml\npytest.ini\nrequirements-docs-tests.txt\nrequirements-docs.txt\nrequirements-github-actions.txt\nrequirements-tests.txt\nrequirements-translations.txt\nrequirements.txt\nscripts\ntests\ntmp\n\n./docs:\nde\nem\nen\nes\nfa\nfr\nja\nko\nlanguage_names.yml\nmissing-translation.md\npt\nru\ntr\nuk\nvi\nzh\nzh-hant\n\n./docs/de:\ndocs\nllm-prompt.md\nmkdocs.yml\n\n./docs/de/docs:\n_llm-test.md\nabout\nadvanced\nalternatives.md\nasync.md\nbenchmarks.md\ndeployment\nenvironment-variables.md\nfastapi-cli.md\nfeatures.md\nhelp-fastapi.md\nhistory-design-future.md\nhow-to\nindex.md\nlearn\nproject-generation.md\npython-types.md\nresources\ntutorial\nvirtual-environments.md\n\n./docs/de/docs/about:\nindex.md\n\n./docs/de/docs/advanced:\nadditional-responses.md\nadditional-status-codes.md\nadvanced-dependencies.md\nasync-tests.md\nbehind-a-proxy.md\ncustom-response.md\ndataclasses.md\nevents.md\ngenerate-clients.md\nindex.md\nmiddleware.md\nopenapi-callbacks.md\nopenapi-webhooks.md\npath-operation-advanced-configuration.md\nresponse-change-status-code.md\nresponse-cookies.md\nresponse-directly.md\nresponse-headers.md\nsecurity\nsettings.md\nsub-applications.md\ntemplates.md\ntesting-dependencies.md\ntesting-events.md\ntesting-websockets.md\nusing-request-directly.md\nwebsockets.md\nwsgi.md\n\n./docs/de/docs/advanced/security:\nhttp-basic-auth.md\nindex.md\noauth2-scopes.md\n\n./docs/de/docs/deployment:\ncloud.md\nconcepts.md\ndocker.md\nfastapicloud.md\nhttps.md\nindex.md\nmanually.md\nserver-workers.md\nversions.md\n\n./docs/de/docs/how-to:\nauthentication-error-status-code.md\nconditional-openapi.md\nconfigure-swagger-ui.md\ncustom-docs-ui-assets.md\ncustom-request-and-route.md\nextending-openapi.md\ngeneral.md\ngraphql.md\nindex.md\nmigrate-from-pydantic-v1-to-pydantic-v2.md\nseparate-openapi-schemas.md\ntesting-database.md\n\n.
20run_command
{
 "command": "python3 tmp/test_repro.py"
}
{"status": "ok", "stdout": "Annotation: SecretModel, Result: ForwardRef('SecretModel')\n", "exit_code": 0}
full
{"status": "ok", "stdout": "Annotation: SecretModel, Result: ForwardRef('SecretModel')\n", "exit_code": 0}
21read_file
{
 "end_line": 245,
 "filepath": "fastapi/dependencies/utils.py",
 "start_line": 230
}
{"status": "ok", "filepath": "fastapi/dependencies/utils.py", "content": "\n\ndef get_typed_annotation(annotation: Any, globalns: Dict[str, Any]) -> Any:\n if i
full
{"status": "ok", "filepath": "fastapi/dependencies/utils.py", "content": "\n\ndef get_typed_annotation(annotation: Any, globalns: Dict[str, Any]) -> Any:\n    if isinstance(annotation, str):\n        annotation = ForwardRef(annotation)\n        annotation = evaluate_forwardref(annotation, globalns, globalns)\n        if annotation is type(None):\n            return None\n    return annotation\n\n\ndef get_typed_return_annotation(call: Callable[..., Any]) -> Any:\n    if sys.version_info >= (3, 10):\n        signature = inspect.signature(call, eval_str=True)\n    else:\n        signature = inspect.signature(call)\n", "start_line": 230, "end_line": 245, "total_lines": 1057, "is_truncated": false}
22read_file
{
 "end_line": 100,
 "filepath": "fastapi/_compat/v1.py",
 "start_line": 1
}
{"status": "ok", "filepath": "fastapi/_compat/v1.py", "content": "from copy import copy\nfrom dataclasses import dataclass, is_dataclass\nfrom enum import Enum\
full
{"status": "ok", "filepath": "fastapi/_compat/v1.py", "content": "from copy import copy\nfrom dataclasses import dataclass, is_dataclass\nfrom enum import Enum\nfrom typing import (\n    Any,\n    Callable,\n    Dict,\n    List,\n    Sequence,\n    Set,\n    Tuple,\n    Type,\n    Union,\n)\n\nfrom fastapi._compat import shared\nfrom fastapi.openapi.constants import REF_PREFIX as REF_PREFIX\nfrom fastapi.types import ModelNameMap\nfrom pydantic.version import VERSION as PYDANTIC_VERSION\nfrom typing_extensions import Literal\n\nPYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\nPYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2\n# Keeping old \"Required\" functionality from Pydantic V1, without\n# shadowing typing.Required.\nRequiredParam: Any = Ellipsis\n\nif not PYDANTIC_V2:\n    from pydantic import BaseConfig as BaseConfig\n    from pydantic import BaseModel as BaseModel\n    from pydantic import ValidationError as ValidationError\n    from pydantic import create_model as create_model\n    from pydantic.class_validators import Validator as Validator\n    from pydantic.color import Color as Color\n    from pydantic.error_wrappers import ErrorWrapper as ErrorWrapper\n    from pydantic.errors import MissingError\n    from pydantic.fields import (  # type: ignore[attr-defined]\n        SHAPE_FROZENSET,\n        SHAPE_LIST,\n        SHAPE_SEQUENCE,\n        SHAPE_SET,\n        SHAPE_SINGLETON,\n        SHAPE_TUPLE,\n        SHAPE_TUPLE_ELLIPSIS,\n    )\n    from pydantic.fields import FieldInfo as FieldInfo\n    from pydantic.fields import ModelField as ModelField  # type: ignore[attr-defined]\n    from pydantic.fields import Undefined as Undefined  # type: ignore[attr-defined]\n    from pydantic.fields import (  # type: ignore[attr-defined]\n        UndefinedType as UndefinedType,\n    )\n    from pydantic.networks import AnyUrl as AnyUrl\n    from pydantic.networks import NameEmail as NameEmail\n    from pydantic.schema import 
23read_file
{
 "end_line": 312,
 "filepath": "fastapi/_compat/v1.py",
 "start_line": 200
}
{"status": "ok", "filepath": "fastapi/_compat/v1.py", "content": " ):\n return False\n if field.sub_fields:\n if not all(is_pv1_scalar_field(f) for f in field.s
full
{"status": "ok", "filepath": "fastapi/_compat/v1.py", "content": "    ):\n        return False\n    if field.sub_fields:\n        if not all(is_pv1_scalar_field(f) for f in field.sub_fields):\n            return False\n    return True\n\n\ndef is_pv1_scalar_sequence_field(field: ModelField) -> bool:\n    if (field.shape in sequence_shapes) and not lenient_issubclass(\n        field.type_, BaseModel\n    ):\n        if field.sub_fields is not None:\n            for sub_field in field.sub_fields:\n                if not is_pv1_scalar_field(sub_field):\n                    return False\n        return True\n    if shared._annotation_is_sequence(field.type_):\n        return True\n    return False\n\n\ndef _model_rebuild(model: Type[BaseModel]) -> None:\n    model.update_forward_refs()\n\n\ndef _model_dump(\n    model: BaseModel, mode: Literal[\"json\", \"python\"] = \"json\", **kwargs: Any\n) -> Any:\n    return model.dict(**kwargs)\n\n\ndef _get_model_config(model: BaseModel) -> Any:\n    return model.__config__  # type: ignore[attr-defined]\n\n\ndef get_schema_from_model_field(\n    *,\n    field: ModelField,\n    model_name_map: ModelNameMap,\n    field_mapping: Dict[\n        Tuple[ModelField, Literal[\"validation\", \"serialization\"]], JsonSchemaValue\n    ],\n    separate_input_output_schemas: bool = True,\n) -> Dict[str, Any]:\n    return field_schema(  # type: ignore[no-any-return]\n        field, model_name_map=model_name_map, ref_prefix=REF_PREFIX\n    )[0]\n\n\n# def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap:\n#     models = get_flat_models_from_fields(fields, known_models=set())\n#     return get_model_name_map(models)  # type: ignore[no-any-return]\n\n\ndef get_definitions(\n    *,\n    fields: List[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
24read_file
{
 "end_line": 100,
 "filepath": "fastapi/_compat/v1.py",
 "start_line": 1
}
{"status": "ok", "filepath": "fastapi/_compat/v1.py", "content": "from copy import copy\nfrom dataclasses import dataclass, is_dataclass\nfrom enum import Enum\
full
{"status": "ok", "filepath": "fastapi/_compat/v1.py", "content": "from copy import copy\nfrom dataclasses import dataclass, is_dataclass\nfrom enum import Enum\nfrom typing import (\n    Any,\n    Callable,\n    Dict,\n    List,\n    Sequence,\n    Set,\n    Tuple,\n    Type,\n    Union,\n)\n\nfrom fastapi._compat import shared\nfrom fastapi.openapi.constants import REF_PREFIX as REF_PREFIX\nfrom fastapi.types import ModelNameMap\nfrom pydantic.version import VERSION as PYDANTIC_VERSION\nfrom typing_extensions import Literal\n\nPYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\nPYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2\n# Keeping old \"Required\" functionality from Pydantic V1, without\n# shadowing typing.Required.\nRequiredParam: Any = Ellipsis\n\nif not PYDANTIC_V2:\n    from pydantic import BaseConfig as BaseConfig\n    from pydantic import BaseModel as BaseModel\n    from pydantic import ValidationError as ValidationError\n    from pydantic import create_model as create_model\n    from pydantic.class_validators import Validator as Validator\n    from pydantic.color import Color as Color\n    from pydantic.error_wrappers import ErrorWrapper as ErrorWrapper\n    from pydantic.errors import MissingError\n    from pydantic.fields import (  # type: ignore[attr-defined]\n        SHAPE_FROZENSET,\n        SHAPE_LIST,\n        SHAPE_SEQUENCE,\n        SHAPE_SET,\n        SHAPE_SINGLETON,\n        SHAPE_TUPLE,\n        SHAPE_TUPLE_ELLIPSIS,\n    )\n    from pydantic.fields import FieldInfo as FieldInfo\n    from pydantic.fields import ModelField as ModelField  # type: ignore[attr-defined]\n    from pydantic.fields import Undefined as Undefined  # type: ignore[attr-defined]\n    from pydantic.fields import (  # type: ignore[attr-defined]\n        UndefinedType as UndefinedType,\n    )\n    from pydantic.networks import AnyUrl as AnyUrl\n    from pydantic.networks import NameEmail as NameEmail\n    from pydantic.schema import 
25edit_file
{
 "filepath": "fastapi/dependencies/utils.py",
 "new_string": "def get_typed_annotation(annotation: Any, globalns: Dict[str, Any]) -> Any:\n    if isinstance(annotation, str):\n        try:\n            annotation = ForwardRef(annotation)\n            annotation = evaluate_forwardref(annotation, globalns, globalns)\n            if annotation is type(None):\n                return None\n        except NameError:\n            return annotation\n    return annotation",
 "old_string": "def get_typed_annotation(annotation: Any, globalns: Dict[str, Any]) -> Any:\n    if isinstance(annotation, str):\n        annotation = ForwardRef(annotation)\n        annotation = evaluate_forwardref(annotation, globalns, globalns)\n        if annotation is type(None):\n            return None\n    return annotation"
}
{"status": "ok", "filepath": "fastapi/dependencies/utils.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/dependencies/utils.py\n+++ b/fastapi
full
{"status": "ok", "filepath": "fastapi/dependencies/utils.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/dependencies/utils.py\n+++ b/fastapi/dependencies/utils.py\n@@ -231,10 +231,13 @@\n \n def get_typed_annotation(annotation: Any, globalns: Dict[str, Any]) -> Any:\n     if isinstance(annotation, str):\n-        annotation = ForwardRef(annotation)\n-        annotation = evaluate_forwardref(annotation, globalns, globalns)\n-        if annotation is type(None):\n-            return None\n+        try:\n+            annotation = ForwardRef(annotation)\n+            annotation = evaluate_forwardref(annotation, globalns, globalns)\n+            if annotation is type(None):\n+                return None\n+        except NameError:\n+            return annotation\n     return annotation\n \n \n", "is_truncated": false}
26run_command
{
 "command": "python3 tmp/test_repro.py"
}
{"status": "ok", "stdout": "Annotation: SecretModel, Result: ForwardRef('SecretModel')\n", "exit_code": 0}
full
{"status": "ok", "stdout": "Annotation: SecretModel, Result: ForwardRef('SecretModel')\n", "exit_code": 0}
27write_file
{
 "content": "\nfrom typing import TYPE_CHECKING, Any, Dict, ForwardRef\nfrom fastapi.dependencies.utils import get_typed_annotation\n\nif TYPE_CHECKING:\n    class SecretModel:\n        def __init__(self, x: int):\n            self.x = x\n\ndef test_forward_ref_type_checking():\n    globalns = {} \n    annotation = \"SecretModel\"\n    result = get_typed_annotation(annotation, globalns)\n    print(f\"Annotation: {annotation}, Result: {result}\")\n\nif __name__ == \"__main__\":\n    test_forward_ref_type_checking()\n",
 "filepath": "tmp/test_repro.py"
}
{"status": "ok", "filepath": "tmp/test_repro.py", "size": 485}
full
{"status": "ok", "filepath": "tmp/test_repro.py", "size": 485}
28run_command
{
 "command": "python3 tmp/test_repro.py"
}
{"status": "ok", "stdout": "Annotation: SecretModel, Result: ForwardRef('SecretModel')\n", "exit_code": 0}
full
{"status": "ok", "stdout": "Annotation: SecretModel, Result: ForwardRef('SecretModel')\n", "exit_code": 0}
29submit_patch
[]
{"status": "ok", "patch_size": 1522, "files_changed": 2}
full
{"status": "ok", "patch_size": 1522, "files_changed": 2}

Patch

diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py
index 23bca6f2..da590021 100644
--- a/fastapi/dependencies/utils.py
+++ b/fastapi/dependencies/utils.py
@@ -231,10 +231,13 @@ def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
 
 def get_typed_annotation(annotation: Any, globalns: Dict[str, Any]) -> Any:
     if isinstance(annotation, str):
-        annotation = ForwardRef(annotation)
-        annotation = evaluate_forwardref(annotation, globalns, globalns)
-        if annotation is type(None):
-            return None
+        try:
+            annotation = ForwardRef(annotation)
+            annotation = evaluate_forwardref(annotation, globalns, globalns)
+            if annotation is type(None):
+                return None
+        except NameError:
+            return annotation
     return annotation
 
 
diff --git a/tmp/test_repro.py b/tmp/test_repro.py
new file mode 100644
index 00000000..3ab817cd
--- /dev/null
+++ b/tmp/test_repro.py
@@ -0,0 +1,17 @@
+
+from typing import TYPE_CHECKING, Any, Dict, ForwardRef
+from fastapi.dependencies.utils import get_typed_annotation
+
+if TYPE_CHECKING:
+    class SecretModel:
+        def __init__(self, x: int):
+            self.x = x
+
+def test_forward_ref_type_checking():
+    globalns = {} 
+    annotation = "SecretModel"
+    result = get_typed_annotation(annotation, globalns)
+    print(f"Annotation: {annotation}, Result: {result}")
+
+if __name__ == "__main__":
+    test_forward_ref_type_checking()

Test output

show
E
==================================== ERRORS ====================================
__________________________ ERROR at setup of test_get __________________________

    @pytest.fixture(name="client")
    def client_fixture() -> TestClient:
        app = FastAPI()
    
>       @app.get("/")
         ^^^^^^^^^^^^

tests/test_stringified_annotation_dependency.py:36: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
fastapi/routing.py:1128: in decorator
    self.add_api_route(
fastapi/routing.py:1067: in add_api_route
    route = route_class(
fastapi/routing.py:686: in __init__
    self.dependant = get_dependant(
fastapi/dependencies/utils.py:306: in get_dependant
    sub_dependant = get_dependant(
fastapi/dependencies/utils.py:280: in get_dependant
    endpoint_signature = get_typed_signature(call)
                         ^^^^^^^^^^^^^^^^^^^^^^^^^
fastapi/dependencies/utils.py:214: in get_typed_signature
    signature = inspect.signature(call, eval_str=True)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/root/.local/share/uv/python/cpython-3.13.14-linux-x86_64-gnu/lib/python3.13/inspect.py:3389: in signature
    return Signature.from_callable(obj, follow_wrapped=follow_wrapped,
/root/.local/share/uv/python/cpython-3.13.14-linux-x86_64-gnu/lib/python3.13/inspect.py:3112: in from_callable
    return _signature_from_callable(obj, sigcls=cls,
/root/.local/share/uv/python/cpython-3.13.14-linux-x86_64-gnu/lib/python3.13/inspect.py:2600: in _signature_from_callable
    return _signature_from_function(sigcls, obj,
/root/.local/share/uv/python/cpython-3.13.14-linux-x86_64-gnu/lib/python3.13/inspect.py:2423: in _signature_from_function
    annotations = get_annotations(func, globals=globals, locals=locals, eval_str=eval_str)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/root/.local/share/uv/python/cpython-3.13.14-linux-x86_64-gnu/lib/python3.13/inspect.py:294: in get_annotations
    else eval(_rewrite_star_unpack(value), globals, locals)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???
E   NameError: name 'AsyncGenerator' is not defined

<string>:1: NameError
=============================== 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 warning, 1 error in 0.79s