Coverage for tests / test_dependency_yield_scope_websockets.py: 100%
119 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-04-06 01:24 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-04-06 01:24 +0000
1from contextvars import ContextVar 1abcd
2from typing import Annotated, Any 1abcd
4import pytest 1abcd
5from fastapi import Depends, FastAPI, WebSocket 1abcd
6from fastapi.exceptions import FastAPIError 1abcd
7from fastapi.testclient import TestClient 1abcd
9global_context: ContextVar[dict[str, Any]] = ContextVar("global_context", default={}) # noqa: B039 1abcd
12class Session: 1abcd
13 def __init__(self) -> None: 1abcd
14 self.open = True 1shkteouvwilxfpyjmzgq
17async def dep_session() -> Any: 1abcd
18 s = Session() 1shkteouvwilxfpyjmzgq
19 yield s 1shkteouvwilxfpyjmzgq
20 s.open = False 1shkteouvwilxfpyjmzgq
21 global_state = global_context.get() 1shkteouvwilxfpyjmzgq
22 global_state["session_closed"] = True 1shkteouvwilxfpyjmzgq
25SessionFuncDep = Annotated[Session, Depends(dep_session, scope="function")] 1abcd
26SessionRequestDep = Annotated[Session, Depends(dep_session, scope="request")] 1abcd
27SessionDefaultDep = Annotated[Session, Depends(dep_session)] 1abcd
30class NamedSession: 1abcd
31 def __init__(self, name: str = "default") -> None: 1abcd
32 self.name = name 1hkeAnilfjmg
33 self.open = True 1hkeAnilfjmg
36def get_named_session(session: SessionRequestDep, session_b: SessionDefaultDep) -> Any: 1abcd
37 assert session is session_b 1enfg
38 named_session = NamedSession(name="named") 1enfg
39 yield named_session, session_b 1enfg
40 named_session.open = False 1enfg
41 global_state = global_context.get() 1enfg
42 global_state["named_session_closed"] = True 1enfg
45NamedSessionsDep = Annotated[tuple[NamedSession, Session], Depends(get_named_session)] 1abcd
48def get_named_func_session(session: SessionFuncDep) -> Any: 1abcd
49 named_session = NamedSession(name="named") 1hrij
50 yield named_session, session 1hrij
51 named_session.open = False 1hrij
52 global_state = global_context.get() 1hrij
53 global_state["named_func_session_closed"] = True 1hrij
56def get_named_regular_func_session(session: SessionFuncDep) -> Any: 1abcd
57 named_session = NamedSession(name="named") 1kAlm
58 return named_session, session 1kAlm
61BrokenSessionsDep = Annotated[ 1abcd
62 tuple[NamedSession, Session], Depends(get_named_func_session)
63]
64NamedSessionsFuncDep = Annotated[ 1abcd
65 tuple[NamedSession, Session], Depends(get_named_func_session, scope="function")
66]
68RegularSessionsDep = Annotated[ 1abcd
69 tuple[NamedSession, Session], Depends(get_named_regular_func_session)
70]
72app = FastAPI() 1abcd
75@app.websocket("/function-scope") 1abcd
76async def function_scope(websocket: WebSocket, session: SessionFuncDep) -> Any: 1abcd
77 await websocket.accept() 1suwy
78 await websocket.send_json({"is_open": session.open}) 1suwy
81@app.websocket("/request-scope") 1abcd
82async def request_scope(websocket: WebSocket, session: SessionRequestDep) -> Any: 1abcd
83 await websocket.accept() 1tvxz
84 await websocket.send_json({"is_open": session.open}) 1tvxz
87@app.websocket("/two-scopes") 1abcd
88async def get_stream_session( 1abcd
89 websocket: WebSocket,
90 function_session: SessionFuncDep,
91 request_session: SessionRequestDep,
92) -> Any:
93 await websocket.accept() 1oBpq
94 await websocket.send_json( 1oBpq
95 {"func_is_open": function_session.open, "req_is_open": request_session.open}
96 )
99@app.websocket("/sub") 1abcd
100async def get_sub(websocket: WebSocket, sessions: NamedSessionsDep) -> Any: 1abcd
101 await websocket.accept() 1enfg
102 await websocket.send_json( 1enfg
103 {"named_session_open": sessions[0].open, "session_open": sessions[1].open}
104 )
107@app.websocket("/named-function-scope") 1abcd
108async def get_named_function_scope( 1abcd
109 websocket: WebSocket, sessions: NamedSessionsFuncDep
110) -> Any:
111 await websocket.accept() 1hrij
112 await websocket.send_json( 1hrij
113 {"named_session_open": sessions[0].open, "session_open": sessions[1].open}
114 )
117@app.websocket("/regular-function-scope") 1abcd
118async def get_regular_function_scope( 1abcd
119 websocket: WebSocket, sessions: RegularSessionsDep
120) -> Any:
121 await websocket.accept() 1kAlm
122 await websocket.send_json( 1kAlm
123 {"named_session_open": sessions[0].open, "session_open": sessions[1].open}
124 )
127client = TestClient(app) 1abcd
130def test_function_scope() -> None: 1abcd
131 global_context.set({}) 1suwy
132 global_state = global_context.get() 1suwy
133 with client.websocket_connect("/function-scope") as websocket: 1suwy
134 data = websocket.receive_json() 1suwy
135 assert data["is_open"] is True 1suwy
136 assert global_state["session_closed"] is True 1suwy
139def test_request_scope() -> None: 1abcd
140 global_context.set({}) 1tvxz
141 global_state = global_context.get() 1tvxz
142 with client.websocket_connect("/request-scope") as websocket: 1tvxz
143 data = websocket.receive_json() 1tvxz
144 assert data["is_open"] is True 1tvxz
145 assert global_state["session_closed"] is True 1tvxz
148def test_two_scopes() -> None: 1abcd
149 global_context.set({}) 1oBpq
150 global_state = global_context.get() 1oBpq
151 with client.websocket_connect("/two-scopes") as websocket: 1oBpq
152 data = websocket.receive_json() 1oBpq
153 assert data["func_is_open"] is True 1oBpq
154 assert data["req_is_open"] is True 1oBpq
155 assert global_state["session_closed"] is True 1oBpq
158def test_sub() -> None: 1abcd
159 global_context.set({}) 1enfg
160 global_state = global_context.get() 1enfg
161 with client.websocket_connect("/sub") as websocket: 1enfg
162 data = websocket.receive_json() 1enfg
163 assert data["named_session_open"] is True 1enfg
164 assert data["session_open"] is True 1enfg
165 assert global_state["session_closed"] is True 1enfg
166 assert global_state["named_session_closed"] is True 1enfg
169def test_broken_scope() -> None: 1abcd
170 with pytest.raises( 1CFDE
171 FastAPIError,
172 match='The dependency "get_named_func_session" has a scope of "request", it cannot depend on dependencies with scope "function"',
173 ):
175 @app.websocket("/broken-scope") 1CFDE
176 async def get_broken( 1CFDE
177 websocket: WebSocket, sessions: BrokenSessionsDep 1CDE
178 ) -> Any: # pragma: no cover 1CDE
179 pass
182def test_named_function_scope() -> None: 1abcd
183 global_context.set({}) 1hrij
184 global_state = global_context.get() 1hrij
185 with client.websocket_connect("/named-function-scope") as websocket: 1hrij
186 data = websocket.receive_json() 1hrij
187 assert data["named_session_open"] is True 1hrij
188 assert data["session_open"] is True 1hrij
189 assert global_state["session_closed"] is True 1hrij
190 assert global_state["named_func_session_closed"] is True 1hrij
193def test_regular_function_scope() -> None: 1abcd
194 global_context.set({}) 1kAlm
195 global_state = global_context.get() 1kAlm
196 with client.websocket_connect("/regular-function-scope") as websocket: 1kAlm
197 data = websocket.receive_json() 1kAlm
198 assert data["named_session_open"] is True 1kAlm
199 assert data["session_open"] is True 1kAlm
200 assert global_state["session_closed"] is True 1kAlm