]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
⚡ Update `create_cloned_field` to use a global cache and improve startup performance...
authorZanie Adkins <zanie@prefect.io>
Sat, 3 Jun 2023 13:37:41 +0000 (08:37 -0500)
committerGitHub <noreply@github.com>
Sat, 3 Jun 2023 13:37:41 +0000 (13:37 +0000)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
Co-authored-by: Huon Wilson <wilson.huon@gmail.com>
fastapi/utils.py

index d8be53c57e6b7a668471fd1289b7ccd02bb39e7e..9b9ebcb852ee0264300ba1efba68c055ba6db6bf 100644 (file)
@@ -2,7 +2,18 @@ import re
 import warnings
 from dataclasses import is_dataclass
 from enum import Enum
-from typing import TYPE_CHECKING, Any, Dict, Optional, Set, Type, Union, cast
+from typing import (
+    TYPE_CHECKING,
+    Any,
+    Dict,
+    MutableMapping,
+    Optional,
+    Set,
+    Type,
+    Union,
+    cast,
+)
+from weakref import WeakKeyDictionary
 
 import fastapi
 from fastapi.datastructures import DefaultPlaceholder, DefaultType
@@ -16,6 +27,11 @@ from pydantic.utils import lenient_issubclass
 if TYPE_CHECKING:  # pragma: nocover
     from .routing import APIRoute
 
+# Cache for `create_cloned_field`
+_CLONED_TYPES_CACHE: MutableMapping[
+    Type[BaseModel], Type[BaseModel]
+] = WeakKeyDictionary()
+
 
 def is_body_allowed_for_status_code(status_code: Union[int, str, None]) -> bool:
     if status_code is None:
@@ -98,11 +114,13 @@ def create_response_field(
 def create_cloned_field(
     field: ModelField,
     *,
-    cloned_types: Optional[Dict[Type[BaseModel], Type[BaseModel]]] = None,
+    cloned_types: Optional[MutableMapping[Type[BaseModel], Type[BaseModel]]] = None,
 ) -> ModelField:
-    # _cloned_types has already cloned types, to support recursive models
+    # cloned_types caches already cloned types to support recursive models and improve
+    # performance by avoiding unecessary cloning
     if cloned_types is None:
-        cloned_types = {}
+        cloned_types = _CLONED_TYPES_CACHE
+
     original_type = field.type_
     if is_dataclass(original_type) and hasattr(original_type, "__pydantic_model__"):
         original_type = original_type.__pydantic_model__