]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
♻️ Make the result of `Depends()` and `Security()` hashable, as a workaround for...
authorSebastián Ramírez <tiangolo@gmail.com>
Wed, 19 Nov 2025 16:50:18 +0000 (17:50 +0100)
committerGitHub <noreply@github.com>
Wed, 19 Nov 2025 16:50:18 +0000 (17:50 +0100)
fastapi/dependencies/utils.py
fastapi/params.py
tests/test_depends_hashable.py [new file with mode: 0644]

index 4b69e39a15a106234596b66cea08148ae3084591..1e92c1ba2a2fb8dca9f3a7ccee6d41bd2cdbadcd 100644 (file)
@@ -1,3 +1,4 @@
+import dataclasses
 import inspect
 from contextlib import AsyncExitStack, contextmanager
 from copy import copy, deepcopy
@@ -428,7 +429,7 @@ def analyze_param(
     if depends is not None and depends.dependency is None:
         # Copy `depends` before mutating it
         depends = copy(depends)
-        depends.dependency = type_annotation
+        depends = dataclasses.replace(depends, dependency=type_annotation)
 
     # Handle non-param type annotations like Request
     if lenient_issubclass(
index 6a58d5808e006c806eaafc61c6f0f7aec4730c40..6d07df35e1fd6ae400ee97da01da06d5f64478ec 100644 (file)
@@ -762,13 +762,13 @@ class File(Form):  # type: ignore[misc]
         )
 
 
-@dataclass
+@dataclass(frozen=True)
 class Depends:
     dependency: Optional[Callable[..., Any]] = None
     use_cache: bool = True
     scope: Union[Literal["function", "request"], None] = None
 
 
-@dataclass
+@dataclass(frozen=True)
 class Security(Depends):
     scopes: Optional[Sequence[str]] = None
diff --git a/tests/test_depends_hashable.py b/tests/test_depends_hashable.py
new file mode 100644 (file)
index 0000000..d57f272
--- /dev/null
@@ -0,0 +1,25 @@
+# This is more or less a workaround to make Depends and Security hashable
+# as other tools that use them depend on that
+# Ref: https://github.com/fastapi/fastapi/pull/14320
+
+from fastapi import Depends, Security
+
+
+def dep():
+    pass
+
+
+def test_depends_hashable():
+    dep()  # just for coverage
+    d1 = Depends(dep)
+    d2 = Depends(dep)
+    d3 = Depends(dep, scope="function")
+    d4 = Depends(dep, scope="function")
+
+    s1 = Security(dep)
+    s2 = Security(dep)
+
+    assert hash(d1) == hash(d2)
+    assert hash(s1) == hash(s2)
+    assert hash(d1) != hash(d3)
+    assert hash(d3) == hash(d4)