fastapi/_compat/shared.py PYTHON 223 lines View on github.com → Search inside
1import types2import typing3import warnings4from collections import deque5from collections.abc import Mapping, Sequence6from dataclasses import is_dataclass7from typing import (8    Annotated,9    Any,10    TypeGuard,11    TypeVar,12    Union,13    get_args,14    get_origin,15)1617from fastapi.types import UnionType18from pydantic import BaseModel19from pydantic.version import VERSION as PYDANTIC_VERSION20from starlette.datastructures import UploadFile2122_T = TypeVar("_T")2324# Copy from Pydantic: pydantic/_internal/_typing_extra.py25WithArgsTypes: tuple[Any, ...] = (26    typing._GenericAlias,  # type: ignore[attr-defined]  # ty: ignore[unresolved-attribute]27    types.GenericAlias,28    types.UnionType,29)  # pyright: ignore[reportAttributeAccessIssue]3031PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(".")[:2])323334sequence_annotation_to_type = {35    Sequence: list,36    list: list,37    tuple: tuple,38    set: set,39    frozenset: frozenset,40    deque: deque,41}4243sequence_types: tuple[type[Any], ...] = tuple(sequence_annotation_to_type.keys())444546# Copy of Pydantic: pydantic/_internal/_utils.py with added TypeGuard47def lenient_issubclass(48    cls: Any, class_or_tuple: type[_T] | tuple[type[_T], ...] | None49) -> TypeGuard[type[_T]]:50    try:51        return isinstance(cls, type) and issubclass(cls, class_or_tuple)  # type: ignore[arg-type]  # ty: ignore[invalid-argument-type]52    except TypeError:  # pragma: no cover53        if isinstance(cls, WithArgsTypes):54            return False55        raise  # pragma: no cover565758def _annotation_is_sequence(annotation: type[Any] | None) -> bool:59    if lenient_issubclass(annotation, (str, bytes)):60        return False61    return lenient_issubclass(annotation, sequence_types)626364def field_annotation_is_sequence(annotation: type[Any] | None) -> bool:65    origin = get_origin(annotation)6667    if origin is Annotated:68        return field_annotation_is_sequence(get_args(annotation)[0])6970    if origin is Union or origin is UnionType:71        for arg in get_args(annotation):72            if field_annotation_is_sequence(arg):73                return True74        return False75    return _annotation_is_sequence(annotation) or _annotation_is_sequence(76        get_origin(annotation)77    )787980def value_is_sequence(value: Any) -> bool:81    return isinstance(value, sequence_types) and not isinstance(value, (str, bytes))828384def _annotation_is_complex(annotation: type[Any] | None) -> bool:85    return (86        lenient_issubclass(annotation, (BaseModel, Mapping, UploadFile))87        or _annotation_is_sequence(annotation)88        or is_dataclass(annotation)89    )909192def field_annotation_is_complex(annotation: type[Any] | None) -> bool:93    origin = get_origin(annotation)94    if origin is Union or origin is UnionType:95        return any(field_annotation_is_complex(arg) for arg in get_args(annotation))9697    if origin is Annotated:98        return field_annotation_is_complex(get_args(annotation)[0])99100    return (101        _annotation_is_complex(annotation)102        or _annotation_is_complex(origin)103        or hasattr(origin, "__pydantic_core_schema__")104        or hasattr(origin, "__get_pydantic_core_schema__")105    )106107108def field_annotation_is_scalar(annotation: Any) -> bool:109    # handle Ellipsis here to make tuple[int, ...] work nicely110    return annotation is Ellipsis or not field_annotation_is_complex(annotation)111112113def field_annotation_is_scalar_sequence(annotation: type[Any] | None) -> bool:114    origin = get_origin(annotation)115116    if origin is Annotated:117        return field_annotation_is_scalar_sequence(get_args(annotation)[0])118119    if origin is Union or origin is UnionType:120        at_least_one_scalar_sequence = False121        for arg in get_args(annotation):122            if field_annotation_is_scalar_sequence(arg):123                at_least_one_scalar_sequence = True124                continue125            elif not field_annotation_is_scalar(arg):126                return False127        return at_least_one_scalar_sequence128    return field_annotation_is_sequence(annotation) and all(129        field_annotation_is_scalar(sub_annotation)130        for sub_annotation in get_args(annotation)131    )132133134def is_bytes_or_nonable_bytes_annotation(annotation: Any) -> bool:135    if lenient_issubclass(annotation, bytes):136        return True137    origin = get_origin(annotation)138    if origin is Union or origin is UnionType:139        for arg in get_args(annotation):140            if lenient_issubclass(arg, bytes):141                return True142    return False143144145def is_uploadfile_or_nonable_uploadfile_annotation(annotation: Any) -> bool:146    if lenient_issubclass(annotation, UploadFile):147        return True148    origin = get_origin(annotation)149    if origin is Union or origin is UnionType:150        for arg in get_args(annotation):151            if lenient_issubclass(arg, UploadFile):152                return True153    return False154155156def is_bytes_sequence_annotation(annotation: Any) -> bool:157    origin = get_origin(annotation)158    if origin is Union or origin is UnionType:159        at_least_one = False160        for arg in get_args(annotation):161            if is_bytes_sequence_annotation(arg):162                at_least_one = True163                continue164        return at_least_one165    return field_annotation_is_sequence(annotation) and all(166        is_bytes_or_nonable_bytes_annotation(sub_annotation)167        for sub_annotation in get_args(annotation)168    )169170171def is_uploadfile_sequence_annotation(annotation: Any) -> bool:172    origin = get_origin(annotation)173    if origin is Union or origin is UnionType:174        at_least_one = False175        for arg in get_args(annotation):176            if is_uploadfile_sequence_annotation(arg):177                at_least_one = True178                continue179        return at_least_one180    return field_annotation_is_sequence(annotation) and all(181        is_uploadfile_or_nonable_uploadfile_annotation(sub_annotation)182        for sub_annotation in get_args(annotation)183    )184185186def is_pydantic_v1_model_instance(obj: Any) -> bool:187    # TODO: remove this function once the required version of Pydantic fully188    # removes pydantic.v1189    try:190        with warnings.catch_warnings():191            warnings.simplefilter("ignore", UserWarning)192            from pydantic import v1193    except ImportError:  # pragma: no cover194        return False195    return isinstance(obj, v1.BaseModel)196197198def is_pydantic_v1_model_class(cls: Any) -> bool:199    # TODO: remove this function once the required version of Pydantic fully200    # removes pydantic.v1201    try:202        with warnings.catch_warnings():203            warnings.simplefilter("ignore", UserWarning)204            from pydantic import v1205    except ImportError:  # pragma: no cover206        return False207    return lenient_issubclass(cls, v1.BaseModel)208209210def annotation_is_pydantic_v1(annotation: Any) -> bool:211    if is_pydantic_v1_model_class(annotation):212        return True213    origin = get_origin(annotation)214    if origin is Union or origin is UnionType:215        for arg in get_args(annotation):216            if is_pydantic_v1_model_class(arg):217                return True218    if field_annotation_is_sequence(annotation):219        for sub_annotation in get_args(annotation):220            if annotation_is_pydantic_v1(sub_annotation):221                return True222    return False

Code quality findings 13

Ensure functions have docstrings for documentation
info maintainability missing-docstring
def lenient_issubclass(
Ensure functions have docstrings for documentation
info maintainability missing-docstring
def field_annotation_is_sequence(annotation: type[Any] | None) -> bool:
Ensure functions have docstrings for documentation
info maintainability missing-docstring
def value_is_sequence(value: Any) -> bool:
Ensure functions have docstrings for documentation
info maintainability missing-docstring
def field_annotation_is_complex(annotation: type[Any] | None) -> bool:
Ensure functions have docstrings for documentation
info maintainability missing-docstring
def field_annotation_is_scalar(annotation: Any) -> bool:
Ensure functions have docstrings for documentation
info maintainability missing-docstring
def field_annotation_is_scalar_sequence(annotation: type[Any] | None) -> bool:
Ensure functions have docstrings for documentation
info maintainability missing-docstring
def is_bytes_or_nonable_bytes_annotation(annotation: Any) -> bool:
Ensure functions have docstrings for documentation
info maintainability missing-docstring
def is_uploadfile_or_nonable_uploadfile_annotation(annotation: Any) -> bool:
Ensure functions have docstrings for documentation
info maintainability missing-docstring
def is_bytes_sequence_annotation(annotation: Any) -> bool:
Ensure functions have docstrings for documentation
info maintainability missing-docstring
def is_uploadfile_sequence_annotation(annotation: Any) -> bool:
Ensure functions have docstrings for documentation
info maintainability missing-docstring
def is_pydantic_v1_model_instance(obj: Any) -> bool:
Ensure functions have docstrings for documentation
info maintainability missing-docstring
def is_pydantic_v1_model_class(cls: Any) -> bool:
Ensure functions have docstrings for documentation
info maintainability missing-docstring
def annotation_is_pydantic_v1(annotation: Any) -> bool:

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.

Generated by searchcode.com · powered by code_get_file + code_get_findings