Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
8155667
fix handling of duplicate "special" dependencies
volfpeter Oct 8, 2024
bda2863
add tests for duplicate special dependency bug fix
volfpeter Oct 8, 2024
c284cf3
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Oct 8, 2024
cca6735
fix duplicate websocket dependency test
volfpeter Oct 8, 2024
eecdde6
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Oct 9, 2024
398c418
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Oct 12, 2024
582116a
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Oct 13, 2024
eddfed7
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Oct 15, 2024
8b5119f
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Oct 15, 2024
51e23c2
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Oct 16, 2024
5dcb1aa
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Oct 18, 2024
44f03fc
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Oct 21, 2024
709b892
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Oct 22, 2024
c49a257
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Oct 23, 2024
c872fb7
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Oct 25, 2024
5c4b148
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Oct 27, 2024
a11d975
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Oct 27, 2024
9e94cb6
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Oct 28, 2024
e9e58dd
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Oct 29, 2024
c483dde
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Oct 31, 2024
861adb6
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Nov 6, 2024
f78d00b
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Nov 7, 2024
3434cad
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Nov 12, 2024
bca0552
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Nov 23, 2024
61a1ee2
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Dec 15, 2024
4c374d2
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Dec 28, 2024
c0bfb91
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Jan 9, 2025
2b04a5a
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Jan 21, 2025
71dc0fa
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Feb 18, 2025
a3801c9
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Mar 3, 2025
a30043d
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Mar 21, 2025
c827749
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Apr 10, 2025
9e1a745
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Apr 24, 2025
f299c36
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter May 5, 2025
4657136
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter May 14, 2025
69e9eb5
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter May 23, 2025
c7ad438
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Jun 13, 2025
d3662a4
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Jul 22, 2025
6336791
fix: store special dependand names in sets instead of lists
volfpeter Jul 23, 2025
6ae6076
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Sep 12, 2025
685c5a7
Merge branch 'master' into fix-duplicate-special-dependency-handling
svlandeg Nov 4, 2025
2c8e8a5
🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
pre-commit-ci[bot] Nov 4, 2025
60bdcb1
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Nov 4, 2025
3e91c1e
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Nov 20, 2025
eada7d6
Merge remote-tracking branch 'upstream/master' into fix-duplicate-spe…
YuriiMotov Dec 1, 2025
e16f68f
Fix condition
YuriiMotov Dec 1, 2025
2f0d361
Merge branch 'master' into fix-duplicate-special-dependency-handling
YuriiMotov Dec 2, 2025
fff0a93
Merge branch 'master' into fix-duplicate-special-dependency-handling
YuriiMotov Dec 5, 2025
67f9def
fix parameter names in get_flat_dependant
YuriiMotov Dec 5, 2025
dde7ef0
Merge branch 'master' into fix-duplicate-special-dependency-handling
YuriiMotov Dec 8, 2025
836812c
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Dec 18, 2025
d877c7e
Merge branch 'master' into fix-duplicate-special-dependency-handling
YuriiMotov Jan 8, 2026
817c1b8
Merge branch 'master' into fix-duplicate-special-dependency-handling
YuriiMotov Feb 12, 2026
63e5079
Merge branch 'master' into fix-duplicate-special-dependency-handling
volfpeter Mar 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions fastapi/dependencies/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ class Dependant:
dependencies: list["Dependant"] = field(default_factory=list)
name: str | None = None
call: Callable[..., Any] | None = None
request_param_name: str | None = None
websocket_param_name: str | None = None
http_connection_param_name: str | None = None
response_param_name: str | None = None
background_tasks_param_name: str | None = None
security_scopes_param_name: str | None = None
request_param_names: set[str] = field(default_factory=set)
websocket_param_names: set[str] = field(default_factory=set)
http_connection_param_names: set[str] = field(default_factory=set)
response_param_names: set[str] = field(default_factory=set)
background_tasks_param_names: set[str] = field(default_factory=set)
security_scopes_param_names: set[str] = field(default_factory=set)
own_oauth_scopes: list[str] | None = None
parent_oauth_scopes: list[str] | None = None
use_cache: bool = True
Expand Down Expand Up @@ -74,7 +74,7 @@ def cache_key(self) -> DependencyCacheKey:
def _uses_scopes(self) -> bool:
if self.own_oauth_scopes:
return True
if self.security_scopes_param_name is not None:
if self.security_scopes_param_names:
return True
if self._is_security_scheme:
return True
Expand Down
55 changes: 29 additions & 26 deletions fastapi/dependencies/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,12 @@ def get_flat_dependant(
body_params=dependant.body_params.copy(),
name=dependant.name,
call=dependant.call,
request_param_name=dependant.request_param_name,
websocket_param_name=dependant.websocket_param_name,
http_connection_param_name=dependant.http_connection_param_name,
response_param_name=dependant.response_param_name,
background_tasks_param_name=dependant.background_tasks_param_name,
security_scopes_param_name=dependant.security_scopes_param_name,
request_param_names=dependant.request_param_names.copy(),
websocket_param_names=dependant.websocket_param_names.copy(),
http_connection_param_names=dependant.http_connection_param_names.copy(),
response_param_names=dependant.response_param_names.copy(),
background_tasks_param_names=dependant.background_tasks_param_names.copy(),
security_scopes_param_names=dependant.security_scopes_param_names.copy(),
own_oauth_scopes=dependant.own_oauth_scopes,
parent_oauth_scopes=use_parent_oauth_scopes,
use_cache=dependant.use_cache,
Expand Down Expand Up @@ -363,22 +363,22 @@ def add_non_field_param_to_dependency(
*, param_name: str, type_annotation: Any, dependant: Dependant
) -> bool | None:
if lenient_issubclass(type_annotation, Request):
dependant.request_param_name = param_name
dependant.request_param_names.add(param_name)
return True
elif lenient_issubclass(type_annotation, WebSocket):
dependant.websocket_param_name = param_name
dependant.websocket_param_names.add(param_name)
return True
elif lenient_issubclass(type_annotation, HTTPConnection):
dependant.http_connection_param_name = param_name
dependant.http_connection_param_names.add(param_name)
return True
elif lenient_issubclass(type_annotation, Response):
dependant.response_param_name = param_name
dependant.response_param_names.add(param_name)
return True
elif lenient_issubclass(type_annotation, StarletteBackgroundTasks):
dependant.background_tasks_param_name = param_name
dependant.background_tasks_param_names.add(param_name)
return True
elif lenient_issubclass(type_annotation, SecurityScopes):
dependant.security_scopes_param_name = param_name
dependant.security_scopes_param_names.add(param_name)
return True
return None

Expand Down Expand Up @@ -710,22 +710,25 @@ async def solve_dependencies(
)
values.update(body_values)
errors.extend(body_errors)
if dependant.http_connection_param_name:
values[dependant.http_connection_param_name] = request
if dependant.request_param_name and isinstance(request, Request):
values[dependant.request_param_name] = request
elif dependant.websocket_param_name and isinstance(request, WebSocket):
values[dependant.websocket_param_name] = request
if dependant.background_tasks_param_name:
for name in dependant.http_connection_param_names:
values[name] = request
if isinstance(request, Request):
for name in dependant.request_param_names:
values[name] = request
elif isinstance(request, WebSocket):
for name in dependant.websocket_param_names:
values[name] = request
if dependant.background_tasks_param_names:
if background_tasks is None:
background_tasks = BackgroundTasks()
values[dependant.background_tasks_param_name] = background_tasks
if dependant.response_param_name:
values[dependant.response_param_name] = response
if dependant.security_scopes_param_name:
values[dependant.security_scopes_param_name] = SecurityScopes(
scopes=dependant.oauth_scopes
)
for name in dependant.background_tasks_param_names:
values[name] = background_tasks
for name in dependant.response_param_names:
values[name] = response
if dependant.security_scopes_param_names:
security_scope = SecurityScopes(scopes=dependant.oauth_scopes)
for name in dependant.security_scopes_param_names:
values[name] = security_scope
return SolvedDependency(
values=values,
errors=errors,
Expand Down
61 changes: 61 additions & 0 deletions tests/test_duplicate_special_dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import pytest
from fastapi import BackgroundTasks, FastAPI, Request, Response, WebSocket
from fastapi.security import SecurityScopes
from fastapi.testclient import TestClient

app = FastAPI()


@app.get("/request")
def request(r1: Request, r2: Request) -> str:
assert r1 is not None
assert r1 is r2
return "success"


@app.get("/response")
def response(r1: Response, r2: Response) -> str:
assert r1 is not None
assert r1 is r2
return "success"


@app.get("/background-tasks")
def background_tasks(t1: BackgroundTasks, t2: BackgroundTasks) -> str:
assert t1 is not None
assert t1 is t2
return "success"


@app.get("/security-scopes")
def security_scopes(sc1: SecurityScopes, sc2: SecurityScopes) -> str:
assert sc1 is not None
assert sc1 is sc2
return "success"


@app.websocket("/websocket")
async def websocket(ws1: WebSocket, ws2: WebSocket) -> str:
assert ws1 is ws2
await ws1.accept()
await ws1.send_text("success")
await ws1.close()


@pytest.mark.parametrize(
"url",
(
"/request",
"/response",
"/background-tasks",
"/security-scopes",
),
)
def test_duplicate_special_dependency(url: str) -> None:
assert TestClient(app).get(url).text == '"success"'


def test_duplicate_websocket_dependency() -> None:
with TestClient(app).websocket_connect("/websocket") as ws:
text = ws.receive_text()
assert text == "success"
Loading