Browse Source

♻️ Refactor types for lenient_issubclass

pull/14860/head
Sebastián Ramírez 5 months ago
parent
commit
ee707dd54b
  1. 13
      fastapi/_compat/shared.py
  2. 12
      fastapi/_compat/v2.py

13
fastapi/_compat/shared.py

@ -8,6 +8,7 @@ from dataclasses import is_dataclass
from typing import ( from typing import (
Annotated, Annotated,
Any, Any,
TypeVar,
Union, Union,
) )
@ -15,7 +16,9 @@ from fastapi.types import UnionType
from pydantic import BaseModel from pydantic import BaseModel
from pydantic.version import VERSION as PYDANTIC_VERSION from pydantic.version import VERSION as PYDANTIC_VERSION
from starlette.datastructures import UploadFile from starlette.datastructures import UploadFile
from typing_extensions import get_args, get_origin from typing_extensions import TypeGuard, get_args, get_origin
_T = TypeVar("_T")
# Copy from Pydantic: pydantic/_internal/_typing_extra.py # Copy from Pydantic: pydantic/_internal/_typing_extra.py
if sys.version_info < (3, 10): if sys.version_info < (3, 10):
@ -39,13 +42,13 @@ sequence_annotation_to_type = {
deque: deque, deque: deque,
} }
sequence_types = tuple(sequence_annotation_to_type.keys()) sequence_types: tuple[type[Any], ...] = tuple(sequence_annotation_to_type.keys())
# Copy of Pydantic: pydantic/_internal/_utils.py # Copy of Pydantic: pydantic/_internal/_utils.py with added TypeGuard
def lenient_issubclass( def lenient_issubclass(
cls: Any, class_or_tuple: Union[type[Any], tuple[type[Any], ...], None] cls: Any, class_or_tuple: Union[type[_T], tuple[type[_T], ...], None]
) -> bool: ) -> TypeGuard[type[_T]]:
try: try:
return isinstance(cls, type) and issubclass(cls, class_or_tuple) # type: ignore[arg-type] return isinstance(cls, type) and issubclass(cls, class_or_tuple) # type: ignore[arg-type]
except TypeError: # pragma: no cover except TypeError: # pragma: no cover

12
fastapi/_compat/v2.py

@ -12,7 +12,7 @@ from typing import (
cast, cast,
) )
from fastapi._compat import shared from fastapi._compat import lenient_issubclass, shared
from fastapi.openapi.constants import REF_TEMPLATE from fastapi.openapi.constants import REF_TEMPLATE
from fastapi.types import IncEx, ModelNameMap, UnionType from fastapi.types import IncEx, ModelNameMap, UnionType
from pydantic import BaseModel, ConfigDict, Field, TypeAdapter, create_model from pydantic import BaseModel, ConfigDict, Field, TypeAdapter, create_model
@ -23,7 +23,6 @@ from pydantic._internal._schema_generation_shared import ( # type: ignore[attr-
GetJsonSchemaHandler as GetJsonSchemaHandler, GetJsonSchemaHandler as GetJsonSchemaHandler,
) )
from pydantic._internal._typing_extra import eval_type_lenient from pydantic._internal._typing_extra import eval_type_lenient
from pydantic._internal._utils import lenient_issubclass as lenient_issubclass
from pydantic.fields import FieldInfo as FieldInfo from pydantic.fields import FieldInfo as FieldInfo
from pydantic.json_schema import GenerateJsonSchema as GenerateJsonSchema from pydantic.json_schema import GenerateJsonSchema as GenerateJsonSchema
from pydantic.json_schema import JsonSchemaValue as JsonSchemaValue from pydantic.json_schema import JsonSchemaValue as JsonSchemaValue
@ -416,10 +415,11 @@ def get_flat_models_from_annotation(
origin = get_origin(annotation) origin = get_origin(annotation)
if origin is not None: if origin is not None:
for arg in get_args(annotation): for arg in get_args(annotation):
if lenient_issubclass(arg, (BaseModel, Enum)) and arg not in known_models: if lenient_issubclass(arg, (BaseModel, Enum)):
known_models.add(arg) if arg not in known_models:
if lenient_issubclass(arg, BaseModel): known_models.add(arg) # type: ignore[arg-type]
get_flat_models_from_model(arg, known_models=known_models) if lenient_issubclass(arg, BaseModel):
get_flat_models_from_model(arg, known_models=known_models)
else: else:
get_flat_models_from_annotation(arg, known_models=known_models) get_flat_models_from_annotation(arg, known_models=known_models)
return known_models return known_models

Loading…
Cancel
Save