Browse Source

Vendor a copy of is_typealiastype from typing-inspection

pull/13920/head
Albin Skott 1 week ago
parent
commit
50b9bd5d8b
Failed to extract signature
  1. 35
      fastapi/dependencies/utils.py
  2. 1
      pyproject.toml
  3. 4
      tests/conftest.py
  4. 10
      tests/test_dependency_pep695.py
  5. 3
      tests/utils.py

35
fastapi/dependencies/utils.py

@ -1,4 +1,6 @@
import inspect
import sys
import typing
from contextlib import AsyncExitStack, contextmanager
from copy import copy, deepcopy
from dataclasses import dataclass
@ -19,6 +21,7 @@ from typing import (
)
import anyio
import typing_extensions
from fastapi import params
from fastapi._compat import (
PYDANTIC_V2,
@ -71,13 +74,12 @@ from starlette.datastructures import (
from starlette.requests import HTTPConnection, Request
from starlette.responses import Response
from starlette.websockets import WebSocket
from typing_extensions import Annotated, get_args, get_origin
from typing_extensions import Annotated, TypeAliasType, TypeGuard, get_args, get_origin
try:
from typing_extensions import TypeAliasType
from types import GenericAlias
except ImportError: # pragma: no cover
TypeAliasType = None # type: ignore[misc,assignment]
GenericAlias = None # type: ignore[misc,assignment]
multipart_not_installed_error = (
'Form data requires "python-multipart" to be installed. \n'
@ -362,7 +364,7 @@ def analyze_param(
depends = None
type_annotation: Any = Any
use_annotation: Any = Any
if TypeAliasType is not None and isinstance(annotation, TypeAliasType):
if _is_typealiastype(annotation):
# unpack in case py3.12 type syntax is used
annotation = annotation.__value__
if annotation is not inspect.Signature.empty:
@ -1008,3 +1010,26 @@ def get_body_field(
field_info=BodyFieldInfo(**BodyFieldInfo_kwargs),
)
return final_field
def _is_typealiastype(tp: Any, /) -> TypeGuard[TypeAliasType]:
in_typing = hasattr(typing, "TypeAliasType")
in_typing_extensions = hasattr(typing_extensions, "TypeAliasType")
is_typealiastype = False
if in_typing and in_typing_extensions:
if getattr(typing, "TypeAliasType", None) is getattr(
typing_extensions, "TypeAliasType", None
): # pragma: no cover
is_typealiastype = isinstance(tp, typing.TypeAliasType) # type: ignore [attr-defined]
else:
is_typealiastype = isinstance(
tp,
(typing.TypeAliasType, typing_extensions.TypeAliasType), # type: ignore [attr-defined]
)
elif in_typing and not in_typing_extensions: # pragma: no cover
is_typealiastype = isinstance(tp, typing.TypeAliasType) # type: ignore [attr-defined]
elif not in_typing and in_typing_extensions:
is_typealiastype = isinstance(tp, typing_extensions.TypeAliasType)
if sys.version_info[:2] == (3, 10):
return type(tp) is not GenericAlias and is_typealiastype
return is_typealiastype

1
pyproject.toml

@ -199,7 +199,6 @@ dynamic_context = "test_function"
omit = [
"docs_src/response_model/tutorial003_04.py",
"docs_src/response_model/tutorial003_04_py310.py",
"tests/test_dependency_pep695_py312.py" # syntax error for version < py312
]
[tool.coverage.report]

4
tests/conftest.py

@ -1,4 +0,0 @@
import sys
if sys.version_info < (3, 12):
collect_ignore_glob = ["*_py312.py"]

10
tests/test_dependency_pep695_py312.py → tests/test_dependency_pep695.py

@ -1,21 +1,19 @@
from __future__ import annotations
from typing import Annotated
from fastapi import Depends, FastAPI
from fastapi.testclient import TestClient
from .utils import needs_py312
from typing_extensions import Annotated, TypeAliasType
async def some_value() -> int:
return 123
type DependedValue = Annotated[int, Depends(some_value)]
DependedValue = TypeAliasType(
"DependedValue", Annotated[int, Depends(some_value)], type_params=()
)
@needs_py312
def test_pep695_type_dependencies():
app = FastAPI()

3
tests/utils.py

@ -8,9 +8,6 @@ needs_py39 = pytest.mark.skipif(sys.version_info < (3, 9), reason="requires pyth
needs_py310 = pytest.mark.skipif(
sys.version_info < (3, 10), reason="requires python3.10+"
)
needs_py312 = pytest.mark.skipif(
sys.version_info < (3, 12), reason="requires python3.12+"
)
needs_pydanticv2 = pytest.mark.skipif(not PYDANTIC_V2, reason="requires Pydantic v2")
needs_pydanticv1 = pytest.mark.skipif(PYDANTIC_V2, reason="requires Pydantic v1")

Loading…
Cancel
Save