| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- import re
- import warnings
- from typing import (
- TYPE_CHECKING,
- Any,
- Literal,
- )
- import fastapi
- from fastapi._compat import (
- ModelField,
- PydanticSchemaGenerationError,
- Undefined,
- annotation_is_pydantic_v1,
- )
- from fastapi.datastructures import DefaultPlaceholder, DefaultType
- from fastapi.exceptions import FastAPIDeprecationWarning, PydanticV1NotSupportedError
- from pydantic.fields import FieldInfo
- from ._compat import v2
- if TYPE_CHECKING: # pragma: nocover
- from .routing import APIRoute
- def is_body_allowed_for_status_code(status_code: int | str | None) -> bool:
- if status_code is None:
- return True
- # Ref: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#patterned-fields-1
- if status_code in {
- "default",
- "1XX",
- "2XX",
- "3XX",
- "4XX",
- "5XX",
- }:
- return True
- current_status_code = int(status_code)
- return not (current_status_code < 200 or current_status_code in {204, 205, 304})
- def get_path_param_names(path: str) -> set[str]:
- return set(re.findall("{(.*?)}", path))
- _invalid_args_message = (
- "Invalid args for response field! Hint: "
- "check that {type_} is a valid Pydantic field type. "
- "If you are using a return type annotation that is not a valid Pydantic "
- "field (e.g. Union[Response, dict, None]) you can disable generating the "
- "response model from the type annotation with the path operation decorator "
- "parameter response_model=None. Read more: "
- "https://fastapi.tiangolo.com/tutorial/response-model/"
- )
- def create_model_field(
- name: str,
- type_: Any,
- default: Any | None = Undefined,
- field_info: FieldInfo | None = None,
- alias: str | None = None,
- mode: Literal["validation", "serialization"] = "validation",
- ) -> ModelField:
- if annotation_is_pydantic_v1(type_):
- raise PydanticV1NotSupportedError(
- "pydantic.v1 models are no longer supported by FastAPI."
- f" Please update the response model {type_!r}."
- )
- field_info = field_info or FieldInfo(annotation=type_, default=default, alias=alias)
- try:
- return v2.ModelField(mode=mode, name=name, field_info=field_info)
- except PydanticSchemaGenerationError:
- raise fastapi.exceptions.FastAPIError(
- _invalid_args_message.format(type_=type_)
- ) from None
- def generate_operation_id_for_path(
- *, name: str, path: str, method: str
- ) -> str: # pragma: nocover
- warnings.warn(
- message="fastapi.utils.generate_operation_id_for_path() was deprecated, "
- "it is not used internally, and will be removed soon",
- category=FastAPIDeprecationWarning,
- stacklevel=2,
- )
- operation_id = f"{name}{path}"
- operation_id = re.sub(r"\W", "_", operation_id)
- operation_id = f"{operation_id}_{method.lower()}"
- return operation_id
- def generate_unique_id(route: "APIRoute") -> str:
- operation_id = f"{route.name}{route.path_format}"
- operation_id = re.sub(r"\W", "_", operation_id)
- assert route.methods
- operation_id = f"{operation_id}_{list(route.methods)[0].lower()}"
- return operation_id
- def deep_dict_update(main_dict: dict[Any, Any], update_dict: dict[Any, Any]) -> None:
- for key, value in update_dict.items():
- if (
- key in main_dict
- and isinstance(main_dict[key], dict)
- and isinstance(value, dict)
- ):
- deep_dict_update(main_dict[key], value)
- elif (
- key in main_dict
- and isinstance(main_dict[key], list)
- and isinstance(update_dict[key], list)
- ):
- main_dict[key] = main_dict[key] + update_dict[key]
- else:
- main_dict[key] = value
- def get_value_or_default(
- first_item: DefaultPlaceholder | DefaultType,
- *extra_items: DefaultPlaceholder | DefaultType,
- ) -> DefaultPlaceholder | DefaultType:
- """
- Pass items or `DefaultPlaceholder`s by descending priority.
- The first one to _not_ be a `DefaultPlaceholder` will be returned.
- Otherwise, the first item (a `DefaultPlaceholder`) will be returned.
- """
- items = (first_item,) + extra_items
- for item in items:
- if not isinstance(item, DefaultPlaceholder):
- return item
- return first_item
|