From 581aacc4a9f3bbb872b082ee55535fe60655de2e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= <tiangolo@gmail.com>
Date: Sat, 31 Aug 2024 22:19:30 +0200
Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20and=20simplify?=
 =?UTF-8?q?=20dependencies=20data=20structures=20with=20dataclasses=20(#12?=
 =?UTF-8?q?098)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 fastapi/dependencies/models.py | 75 ++++++++++++----------------------
 fastapi/dependencies/utils.py  |  2 +-
 2 files changed, 28 insertions(+), 49 deletions(-)

diff --git a/fastapi/dependencies/models.py b/fastapi/dependencies/models.py
index 61ef00638..418c11725 100644
--- a/fastapi/dependencies/models.py
+++ b/fastapi/dependencies/models.py
@@ -1,58 +1,37 @@
-from typing import Any, Callable, List, Optional, Sequence
+from dataclasses import dataclass, field
+from typing import Any, Callable, List, Optional, Sequence, Tuple
 
 from fastapi._compat import ModelField
 from fastapi.security.base import SecurityBase
 
 
+@dataclass
 class SecurityRequirement:
-    def __init__(
-        self, security_scheme: SecurityBase, scopes: Optional[Sequence[str]] = None
-    ):
-        self.security_scheme = security_scheme
-        self.scopes = scopes
+    security_scheme: SecurityBase
+    scopes: Optional[Sequence[str]] = None
 
 
+@dataclass
 class Dependant:
-    def __init__(
-        self,
-        *,
-        path_params: Optional[List[ModelField]] = None,
-        query_params: Optional[List[ModelField]] = None,
-        header_params: Optional[List[ModelField]] = None,
-        cookie_params: Optional[List[ModelField]] = None,
-        body_params: Optional[List[ModelField]] = None,
-        dependencies: Optional[List["Dependant"]] = None,
-        security_schemes: Optional[List[SecurityRequirement]] = None,
-        name: Optional[str] = None,
-        call: Optional[Callable[..., Any]] = None,
-        request_param_name: Optional[str] = None,
-        websocket_param_name: Optional[str] = None,
-        http_connection_param_name: Optional[str] = None,
-        response_param_name: Optional[str] = None,
-        background_tasks_param_name: Optional[str] = None,
-        security_scopes_param_name: Optional[str] = None,
-        security_scopes: Optional[List[str]] = None,
-        use_cache: bool = True,
-        path: Optional[str] = None,
-    ) -> None:
-        self.path_params = path_params or []
-        self.query_params = query_params or []
-        self.header_params = header_params or []
-        self.cookie_params = cookie_params or []
-        self.body_params = body_params or []
-        self.dependencies = dependencies or []
-        self.security_requirements = security_schemes or []
-        self.request_param_name = request_param_name
-        self.websocket_param_name = websocket_param_name
-        self.http_connection_param_name = http_connection_param_name
-        self.response_param_name = response_param_name
-        self.background_tasks_param_name = background_tasks_param_name
-        self.security_scopes = security_scopes
-        self.security_scopes_param_name = security_scopes_param_name
-        self.name = name
-        self.call = call
-        self.use_cache = use_cache
-        # Store the path to be able to re-generate a dependable from it in overrides
-        self.path = path
-        # Save the cache key at creation to optimize performance
+    path_params: List[ModelField] = field(default_factory=list)
+    query_params: List[ModelField] = field(default_factory=list)
+    header_params: List[ModelField] = field(default_factory=list)
+    cookie_params: List[ModelField] = field(default_factory=list)
+    body_params: List[ModelField] = field(default_factory=list)
+    dependencies: List["Dependant"] = field(default_factory=list)
+    security_requirements: List[SecurityRequirement] = field(default_factory=list)
+    name: Optional[str] = None
+    call: Optional[Callable[..., Any]] = None
+    request_param_name: Optional[str] = None
+    websocket_param_name: Optional[str] = None
+    http_connection_param_name: Optional[str] = None
+    response_param_name: Optional[str] = None
+    background_tasks_param_name: Optional[str] = None
+    security_scopes_param_name: Optional[str] = None
+    security_scopes: Optional[List[str]] = None
+    use_cache: bool = True
+    path: Optional[str] = None
+    cache_key: Tuple[Optional[Callable[..., Any]], Tuple[str, ...]] = field(init=False)
+
+    def __post_init__(self) -> None:
         self.cache_key = (self.call, tuple(sorted(set(self.security_scopes or []))))
diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py
index 3e8e7b410..85703c9e9 100644
--- a/fastapi/dependencies/utils.py
+++ b/fastapi/dependencies/utils.py
@@ -175,7 +175,7 @@ def get_flat_dependant(
         header_params=dependant.header_params.copy(),
         cookie_params=dependant.cookie_params.copy(),
         body_params=dependant.body_params.copy(),
-        security_schemes=dependant.security_requirements.copy(),
+        security_requirements=dependant.security_requirements.copy(),
         use_cache=dependant.use_cache,
         path=dependant.path,
     )