mirror of https://github.com/tiangolo/fastapi.git
Merge eb544d5095 into 811fa89875
This commit is contained in:
commit
6086cb3ece
|
|
@ -1,5 +1,7 @@
|
|||
import dataclasses
|
||||
import inspect
|
||||
import sys
|
||||
import typing
|
||||
from contextlib import AsyncExitStack, contextmanager
|
||||
from copy import copy, deepcopy
|
||||
from dataclasses import dataclass
|
||||
|
|
@ -20,6 +22,7 @@ from typing import (
|
|||
)
|
||||
|
||||
import anyio
|
||||
import typing_extensions
|
||||
from fastapi import params
|
||||
from fastapi._compat import (
|
||||
PYDANTIC_V2,
|
||||
|
|
@ -75,7 +78,19 @@ 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, Literal, get_args, get_origin
|
||||
from typing_extensions import (
|
||||
Annotated,
|
||||
Literal,
|
||||
TypeAliasType,
|
||||
TypeGuard,
|
||||
get_args,
|
||||
get_origin,
|
||||
)
|
||||
|
||||
try:
|
||||
from types import GenericAlias
|
||||
except ImportError: # pragma: no cover
|
||||
GenericAlias = None # type: ignore[misc,assignment]
|
||||
|
||||
from .. import temp_pydantic_v1_params
|
||||
|
||||
|
|
@ -352,6 +367,9 @@ def analyze_param(
|
|||
depends = None
|
||||
type_annotation: Any = Any
|
||||
use_annotation: Any = Any
|
||||
if _is_typealiastype(annotation):
|
||||
# unpack in case PEP 695 type syntax is used
|
||||
annotation = annotation.__value__
|
||||
if annotation is not inspect.Signature.empty:
|
||||
use_annotation = annotation
|
||||
type_annotation = annotation
|
||||
|
|
@ -1035,3 +1053,45 @@ def get_body_field(
|
|||
field_info=BodyFieldInfo(**BodyFieldInfo_kwargs),
|
||||
)
|
||||
return final_field
|
||||
|
||||
|
||||
def _is_typealiastype(tp: Any, /) -> TypeGuard[TypeAliasType]:
|
||||
"""
|
||||
This implementation is in line with the implementation of `is_typealiastype` in `typing-inspection`:
|
||||
See:
|
||||
- https://github.com/pydantic/typing-inspection/blob/8db011350942f33ac4b5d7db60d4d9ea83ab480f/src/typing_inspection/typing_objects.py#L488-L499
|
||||
- https://github.com/pydantic/typing-inspection/blob/8db011350942f33ac4b5d7db60d4d9ea83ab480f/src/typing_inspection/typing_objects.py#L105-L134
|
||||
"""
|
||||
|
||||
# Check if TypeAliasType exists in typing and/or typing_extensions.
|
||||
in_typing = hasattr(typing, "TypeAliasType")
|
||||
in_typing_extensions = hasattr(typing_extensions, "TypeAliasType")
|
||||
|
||||
is_typealiastype = False # Default: assume not a TypeAliasType
|
||||
if in_typing and in_typing_extensions:
|
||||
if getattr(typing, "TypeAliasType", None) is getattr(
|
||||
typing_extensions, "TypeAliasType", None
|
||||
): # pragma: no cover
|
||||
# Case 1: Both implementations are the same object.
|
||||
# Checking against one of them.
|
||||
is_typealiastype = isinstance(tp, typing.TypeAliasType) # type: ignore [attr-defined]
|
||||
else:
|
||||
# Case 2: Implementations are different objects.
|
||||
# Need to check against both versions.
|
||||
is_typealiastype = isinstance(
|
||||
tp,
|
||||
(typing.TypeAliasType, typing_extensions.TypeAliasType), # type: ignore [attr-defined]
|
||||
)
|
||||
elif in_typing and not in_typing_extensions: # pragma: no cover
|
||||
# Case 3: Only typing.TypeAliasType exists.
|
||||
is_typealiastype = isinstance(tp, typing.TypeAliasType) # type: ignore [attr-defined]
|
||||
elif not in_typing and in_typing_extensions:
|
||||
# Case 4: Only typing_extensions.TypeAliasType exists.
|
||||
is_typealiastype = isinstance(tp, typing_extensions.TypeAliasType)
|
||||
|
||||
# Special case for Python 3.10:
|
||||
# On Python 3.10, parameterized PEP 695 type aliases are represented as `GenericAlias`
|
||||
# instead of proper TypeAliasType. We must exclude those.
|
||||
if sys.version_info[:2] == (3, 10):
|
||||
return type(tp) is not GenericAlias and is_typealiastype
|
||||
return is_typealiastype
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
from typing_extensions import Annotated, TypeAliasType
|
||||
|
||||
|
||||
async def some_value() -> int:
|
||||
return 123
|
||||
|
||||
|
||||
DependedValue = TypeAliasType(
|
||||
"DependedValue", Annotated[int, Depends(some_value)], type_params=()
|
||||
)
|
||||
|
||||
|
||||
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
|
||||
assert response.text == '"value: 123"'
|
||||
Loading…
Reference in New Issue