Coverage for tests/sync/test_depends.py: 100%
268 statements
« prev ^ index » next coverage.py v7.17.3, created at 2026-11-13 05:19 +0000
« prev ^ index » next coverage.py v7.17.3, created at 2026-11-13 05:19 +0000
1import logging 1abcdefghijklmnopqrst
2from collections.abc import Generator 1abcdefghijklmnopqrst
3from contextlib import contextmanager 1abcdefghijklmnopqrst
4from dataclasses import dataclass 1abcdefghijklmnopqrst
5from functools import partial 1abcdefghijklmnopqrst
6from typing import Annotated 1abcdefghijklmnopqrst
7from unittest.mock import Mock 1abcdefghijklmnopqrst
9import pytest 1abcdefghijklmnopqrst
11from fast_depends import Depends, inject 1abcdefghijklmnopqrst
12from fast_depends.exceptions import ValidationError 1abcdefghijklmnopqrst
13from tests.marks import serializer 1abcdefghijklmnopqrst
16def test_depends() -> None: 1abcdefghijklmnopqrst
17 def dep_func(b: int, a: int = 3): 1abcdefghijklmnopqrst
18 return a + b 1abcdefghijklmnopqrst
20 @inject 1abcdefghijklmnopqrst
21 def some_func(b: int, c=Depends(dep_func)): 1abcdefghijklmnopqrst
22 return b + c 1abcdefghijklmnopqrst
24 assert some_func(2) == 7 1abcdefghijklmnopqrst
27def test_empty_main_body() -> None: 1abcdefghijklmnopqrst
28 def dep_func(a): 1abcdefghijklmnopqrst
29 return a 1abcdefghijklmnopqrst
31 @inject 1abcdefghijklmnopqrst
32 def some_func(c=Depends(dep_func)): 1abcdefghijklmnopqrst
33 return c 1abcdefghijklmnopqrst
35 assert some_func(1) == 1 1abcdefghijklmnopqrst
38def test_class_depends() -> None: 1abcdefghijklmnopqrst
39 class MyDep: 1abcdefghijklmnopqrst
40 def __init__(self, a): 1abcdefghijklmnopqrst
41 self.a = a 1abcdefghijklmnopqrst
43 @inject 1abcdefghijklmnopqrst
44 def some_func(a=Depends(MyDep)): 1abcdefghijklmnopqrst
45 assert isinstance(a, MyDep) 1abcdefghijklmnopqrst
46 assert a.a == 3 1abcdefghijklmnopqrst
47 return a 1abcdefghijklmnopqrst
49 some_func(3) 1abcdefghijklmnopqrst
52def test_empty_main_body_multiple_args() -> None: 1abcdefghijklmnopqrst
53 def dep2(b): 1abcdefghijklmnopqrst
54 return b 1abcdefghijklmnopqrst
56 def dep(a): 1abcdefghijklmnopqrst
57 return a 1abcdefghijklmnopqrst
59 @inject() 1abcdefghijklmnopqrst
60 def handler(d=Depends(dep2), c=Depends(dep)): 1abcdefghijklmnopqrst
61 return d, c 1abcdefghijklmnopqrst
63 assert handler(a=1, b=2) == (2, 1) 1abcdefghijklmnopqrst
64 assert handler(1, b=2) == (2, 1) 1abcdefghijklmnopqrst
65 assert handler(1, a=2) == (1, 2) 1abcdefghijklmnopqrst
66 assert handler(1, 2) == (1, 1) # all dependencies takes the first arg 1abcdefghijklmnopqrst
69def test_ignore_depends_if_setted_manual() -> None: 1abcdefghijklmnopqrst
70 mock = Mock() 1abcdefghijklmnopqrst
72 def dep_func(a, b) -> int: 1abcdefghijklmnopqrst
73 mock(a, b) 1abcdefghijklmnopqrst
74 return a + b 1abcdefghijklmnopqrst
76 @inject 1abcdefghijklmnopqrst
77 def some_func(c=Depends(dep_func)) -> int: 1abcdefghijklmnopqrst
78 return c 1abcdefghijklmnopqrst
80 assert some_func(c=2) == 2 1abcdefghijklmnopqrst
81 assert not mock.called 1abcdefghijklmnopqrst
83 assert some_func(1, 2) == 3 1abcdefghijklmnopqrst
84 mock.assert_called_once_with(1, 2) 1abcdefghijklmnopqrst
87def test_depends_annotated_type_str() -> None: 1abcdefghijklmnopqrst
88 def dep_func(a): 1abcdefghijklmnopqrst
89 return a 1abcdefghijklmnopqrst
91 @inject 1abcdefghijklmnopqrst
92 def some_func( 1abcdefghijklmnopqrst
93 a: int,
94 b: int,
95 c: Annotated["int", Depends(dep_func)],
96 ):
97 return a + b + c 1abcdefghijklmnopqrst
99 @inject 1abcdefghijklmnopqrst
100 def another_func( 1abcdefghijklmnopqrst
101 a: int,
102 c: Annotated["int", Depends(dep_func)],
103 ):
104 return a + c 1abcdefghijklmnopqrst
106 assert some_func(1, 2) == 4 1abcdefghijklmnopqrst
107 assert another_func(3) == 6 1abcdefghijklmnopqrst
110def test_cache() -> None: 1abcdefghijklmnopqrst
111 mock = Mock() 1abcdefghijklmnopqrst
113 def nested_dep_func(): 1abcdefghijklmnopqrst
114 mock() 1abcdefghijklmnopqrst
115 return 1000 1abcdefghijklmnopqrst
117 def dep_func(a=Depends(nested_dep_func)): 1abcdefghijklmnopqrst
118 return a 1abcdefghijklmnopqrst
120 @inject 1abcdefghijklmnopqrst
121 def some_func( 1abcdefghijklmnopqrst
122 a=Depends(dep_func),
123 b=Depends(nested_dep_func),
124 ):
125 assert a is b 1abcdefghijklmnopqrst
126 return a + b 1abcdefghijklmnopqrst
128 some_func() 1abcdefghijklmnopqrst
129 mock.assert_called_once() 1abcdefghijklmnopqrst
132def test_not_cache() -> None: 1abcdefghijklmnopqrst
133 mock = Mock() 1abcdefghijklmnopqrst
135 def nested_dep_func(): 1abcdefghijklmnopqrst
136 mock() 1abcdefghijklmnopqrst
137 return 1000 1abcdefghijklmnopqrst
139 def dep_func(a=Depends(nested_dep_func, use_cache=False)): 1abcdefghijklmnopqrst
140 return a 1abcdefghijklmnopqrst
142 @inject 1abcdefghijklmnopqrst
143 def some_func( 1abcdefghijklmnopqrst
144 a=Depends(dep_func, use_cache=False),
145 b=Depends(nested_dep_func, use_cache=False),
146 ):
147 assert a is b 1abcdefghijklmnopqrst
148 return a + b 1abcdefghijklmnopqrst
150 some_func() 1abcdefghijklmnopqrst
151 assert mock.call_count == 2 1abcdefghijklmnopqrst
154def test_yield() -> None: 1abcdefghijklmnopqrst
155 mock = Mock() 1abcdefghijklmnopqrst
157 def dep_func(): 1abcdefghijklmnopqrst
158 mock() 1abcdefghijklmnopqrst
159 yield 1000 1abcdefghijklmnopqrst
160 mock.exit() 1abcdefghijklmnopqrst
162 @inject 1abcdefghijklmnopqrst
163 def some_func(a=Depends(dep_func)): 1abcdefghijklmnopqrst
164 assert mock.called 1abcdefghijklmnopqrst
165 assert not mock.exit.called 1abcdefghijklmnopqrst
166 return a 1abcdefghijklmnopqrst
168 some_func() 1abcdefghijklmnopqrst
169 mock.assert_called_once() 1abcdefghijklmnopqrst
170 mock.exit.assert_called_once() 1abcdefghijklmnopqrst
173def test_nested_yield_with_inject() -> None: 1abcdefghijklmnopqrst
174 def dep_c(): 1abcdefghijklmnopqrst
175 yield ["foo"] 1abcdefghijklmnopqrst
177 @inject 1abcdefghijklmnopqrst
178 def dep_b(c=Depends(dep_c)): 1abcdefghijklmnopqrst
179 yield c 1abcdefghijklmnopqrst
181 @inject 1abcdefghijklmnopqrst
182 def a(b=Depends(dep_b)): 1abcdefghijklmnopqrst
183 return b[0] 1abcdefghijklmnopqrst
185 assert a() == "foo" 1abcdefghijklmnopqrst
188def test_callable_class_depends() -> None: 1abcdefghijklmnopqrst
189 class MyDep: 1abcdefghijklmnopqrst
190 def __init__(self, a: int): 1abcdefghijklmnopqrst
191 self.a = a 1abcdefghijklmnopqrst
193 def __call__(self) -> int: 1abcdefghijklmnopqrst
194 return self.a 1abcdefghijklmnopqrst
196 @inject 1abcdefghijklmnopqrst
197 def some_func(a: int = Depends(MyDep(3))): # noqa: B008 1abcdefghijklmnopqrst
198 assert a == 3 1abcdefghijklmnopqrst
199 return a 1abcdefghijklmnopqrst
201 some_func() 1abcdefghijklmnopqrst
204def test_not_cast_main() -> None: 1abcdefghijklmnopqrst
205 @dataclass 1abcdefghijklmnopqrst
206 class A: 1abcdefghijklmnopqrst
207 a: int 1abcdefghijkls
209 def dep() -> A: 1abcdefghijklmnopqrst
210 return A(a=1) 1abcdefghijklmnopqrst
212 def get_logger() -> logging.Logger: 1abcdefghijklmnopqrst
213 return logging.getLogger(__file__) 1abcdefghijklmnopqrst
215 @inject(cast=False) 1abcdefghijklmnopqrst
216 def some_func( 1abcdefghijklmnopqrst
217 b: str,
218 a: A = Depends(dep),
219 logger: logging.Logger = Depends(get_logger),
220 ) -> str:
221 assert a.a == 1 1abcdefghijklmnopqrst
222 assert logger 1abcdefghijklmnopqrst
223 return b 1abcdefghijklmnopqrst
225 assert some_func(1) == 1 1abcdefghijklmnopqrst
228def test_extra() -> None: 1abcdefghijklmnopqrst
229 mock = Mock() 1abcdefghijklmnopqrst
231 def dep(): 1abcdefghijklmnopqrst
232 mock.sync_call() 1abcdefghijklmnopqrst
234 @inject(extra_dependencies=(Depends(dep),)) 1abcdefghijklmnopqrst
235 def some_func(): 1abcdefghijklmnopqrst
236 mock() 1abcdefghijklmnopqrst
238 some_func() 1abcdefghijklmnopqrst
239 mock.assert_called_once() 1abcdefghijklmnopqrst
240 mock.sync_call.assert_called_once() 1abcdefghijklmnopqrst
243def test_async_extra() -> None: 1abcdefghijklmnopqrst
244 mock = Mock() 1abcdefghijklmnopqrst
246 async def dep(): # pragma: no cover 1abcdefghijklmnopqrst
247 mock.sync_call()
249 with pytest.raises(AssertionError): 1abcdefghijklmnopqrst
251 @inject(extra_dependencies=(Depends(dep),)) 1abcdefghijklmnopqrst
252 def some_func(): # pragma: no cover 1abcdefghijklmnopqrst
253 mock()
256def test_async_depends() -> None: 1abcdefghijklmnopqrst
257 async def dep_func(a: int) -> float: # pragma: no cover 1abcdefghijklmnopqrst
258 return a
260 with pytest.raises(AssertionError): 1abcdefghijklmnopqrst
262 @inject 1abcdefghijklmnopqrst
263 def some_func(a: int, b: int, c=Depends(dep_func)) -> str: # pragma: no cover 1abcdefghijklmnopqrst
264 return a + b + c
267def test_async_extra_depends() -> None: 1abcdefghijklmnopqrst
268 async def dep_func(a: int) -> float: # pragma: no cover 1abcdefghijklmnopqrst
269 return a
271 with pytest.raises(AssertionError): 1abcdefghijklmnopqrst
273 @inject(extra_dependencies=(Depends(dep_func),)) 1abcdefghijklmnopqrst
274 def some_func(a: int, b: int) -> str: # pragma: no cover 1abcdefghijklmnopqrst
275 return a + b
278def test_generator() -> None: 1abcdefghijklmnopqrst
279 mock = Mock() 1abcdefghijklmnopqrst
281 def simple_func(): 1abcdefghijklmnopqrst
282 mock.simple() 1abcdefghijklmnopqrst
284 def func(): 1abcdefghijklmnopqrst
285 mock.start() 1abcdefghijklmnopqrst
286 yield 1abcdefghijklmnopqrst
287 mock.end() 1abcdefghijklmnopqrst
289 @inject 1abcdefghijklmnopqrst
290 def simple_func(a: str, d2=Depends(simple_func), d=Depends(func)): 1abcdefghijklmnopqrst
291 for _ in range(2): 1abcdefghijklmnopqrst
292 yield a 1abcdefghijklmnopqrst
294 for i in simple_func("1"): 1abcdefghijklmnopqrst
295 mock.start.assert_called_once() 1abcdefghijklmnopqrst
296 assert not mock.end.called 1abcdefghijklmnopqrst
297 assert i == "1" 1abcdefghijklmnopqrst
299 mock.simple.assert_called_once() 1abcdefghijklmnopqrst
300 mock.end.assert_called_once() 1abcdefghijklmnopqrst
303def test_partial() -> None: 1abcdefghijklmnopqrst
304 def dep(a): 1abcdefghijklmnopqrst
305 return a 1abcdefghijklmnopqrst
307 @inject 1abcdefghijklmnopqrst
308 def func(a=Depends(partial(dep, 10))): # noqa: B008 1abcdefghijklmnopqrst
309 return a 1abcdefghijklmnopqrst
311 assert func() == 10 1abcdefghijklmnopqrst
314@serializer 1abcdefghijklmnopqrst
315class TestSerializer: 1abcdefghijklmnopqrst
316 def test_not_cast(self) -> None: 1abcdefghijklmnopqrst
317 @dataclass 1abcdefghijklmnopqr
318 class A: 1abcdefghijklmnopqr
319 a: int 1abcdefghijkl
321 def dep1() -> A: 1abcdefghijklmnopqr
322 return {"a": 1} 1abcdefghijklmnopqr
324 def dep2() -> A: 1abcdefghijklmnopqr
325 return {"a": 1} 1abcdefghijklmnopqr
327 def dep3() -> A: 1abcdefghijklmnopqr
328 return 1 1abcdefghijklmnopqr
330 def get_logger() -> logging.Logger: 1abcdefghijklmnopqr
331 return logging.getLogger(__file__) 1abcdefghijklmnopqr
333 @inject 1abcdefghijklmnopqr
334 def some_func( 1abcdefghijklmnopqr
335 b,
336 a1: A = Depends(dep1, cast=False, cast_result=True),
337 a2: A = Depends(dep2, cast=True, cast_result=False),
338 a3: A = Depends(dep3, cast=False, cast_result=False),
339 logger: logging.Logger = Depends(get_logger),
340 ):
341 assert a1.a == 1 1abcdefghijklmnopqr
342 assert a2.a == 1 1abcdefghijklmnopqr
343 assert a3 == 1 1abcdefghijklmnopqr
344 assert logger 1abcdefghijklmnopqr
345 return b 1abcdefghijklmnopqr
347 assert some_func(1) == 1 1abcdefghijklmnopqr
349 def test_depends_error(self) -> None: 1abcdefghijklmnopqrst
350 def dep_func(b: dict, a: int = 3) -> float: # pragma: no cover 1abcdefghijklmnopqr
351 return a + b
353 def another_func(b: int, a: int = 3) -> dict: # pragma: no cover 1abcdefghijklmnopqr
354 return a + b
356 @inject 1abcdefghijklmnopqr
357 def some_func( 1abcdefghijklmnopqr
358 b: int, c=Depends(dep_func), d=Depends(another_func) 1abcdefghijklmnopqr
359 ) -> int: # pragma: no cover 1abcdefghijkl
360 assert c is None
361 return b
363 with pytest.raises(ValidationError): 1abcdefghijklmnopqr
364 assert some_func("2") == 7 1abcdefghijklmnopqr
366 def test_depends_response_cast(self) -> None: 1abcdefghijklmnopqrst
367 def dep_func(a): 1abcdefghijklmnopqr
368 return a 1abcdefghijklmnopqr
370 @inject 1abcdefghijklmnopqr
371 def some_func(a: int, b: int, c: int = Depends(dep_func)) -> float: 1abcdefghijklmnopqr
372 assert isinstance(c, int) 1abcdefghijklmnopqr
373 assert c == a 1abcdefghijklmnopqr
374 return a + b + c 1abcdefghijklmnopqr
376 assert some_func("1", "2") 1abcdefghijklmnopqr
378 def test_depends_annotated_str(self) -> None: 1abcdefghijklmnopqrst
379 def dep_func(a): 1abcdefghijklmnopqr
380 return a 1abcdefghijklmnopqr
382 @inject 1abcdefghijklmnopqr
383 def some_func( 1abcdefghijklmnopqr
384 a: int,
385 b: int,
386 c: "Annotated[int, Depends(dep_func)]",
387 ) -> float:
388 assert isinstance(c, int) 1abcdefghijklmnopqr
389 return a + b + c 1abcdefghijklmnopqr
391 @inject 1abcdefghijklmnopqr
392 def another_func( 1abcdefghijklmnopqr
393 a: int,
394 c: "Annotated[int, Depends(dep_func)]",
395 ):
396 return a + c 1abcdefghijklmnopqr
398 assert some_func("1", "2") 1abcdefghijklmnopqr
399 assert another_func("3") == 6.0 1abcdefghijklmnopqr
402def test_default_key_value() -> None: 1abcdefghijklmnopqrst
403 def dep(a: str = "a"): 1abcdefghijklmnopqrst
404 return a 1abcdefghijklmnopqrst
406 @inject(cast=False) 1abcdefghijklmnopqrst
407 def func(a=Depends(dep)): 1abcdefghijklmnopqrst
408 return a 1abcdefghijklmnopqrst
410 assert func() == "a" 1abcdefghijklmnopqrst
413def test_contextmanager() -> None: 1abcdefghijklmnopqrst
414 def dep(a: str): 1abcdefghijklmnopqrst
415 return a 1abcdefghijklmnopqrst
417 @contextmanager 1abcdefghijklmnopqrst
418 @inject 1abcdefghijklmnopqrst
419 def func(a: str, b: str = Depends(dep)): 1abcdefghijklmnopqrst
420 yield a == b 1abcdefghijklmnopqrst
422 with func("a") as is_equal: 1abcdefghijklmnopqrst
423 assert is_equal 1abcdefghijklmnopqrst
426def test_solve_wrapper() -> None: 1abcdefghijklmnopqrst
427 @inject 1abcdefghijklmnopqrst
428 def dep1(a: int) -> Generator[int, None, None]: 1abcdefghijklmnopqrst
429 yield a + 1 1abcdefghijklmnopqrst
431 def dep2(a: int) -> Generator[int, None, None]: 1abcdefghijklmnopqrst
432 yield a + 2 1abcdefghijklmnopqrst
434 @inject 1abcdefghijklmnopqrst
435 def func(a: int, b: int = Depends(dep1), c: int = Depends(dep2)): 1abcdefghijklmnopqrst
436 return a, b, c 1abcdefghijklmnopqrst
438 assert func(1) == (1, 2, 3) 1abcdefghijklmnopqrst
441def test_generator_iter() -> None: 1abcdefghijklmnopqrst
442 # ref: https://github.com/Lancetnik/FastDepends/issues/165
444 def simple_dependency(a: int, b: int = 3) -> int: 1abcdefghijklmnopqrst
445 return a + b 1abcdefghijklmnopqrst
447 @inject 1abcdefghijklmnopqrst
448 def method(a: int, d: int = Depends(simple_dependency)) -> Generator[int, None, None]: 1abcdefghijklmnopqrst
449 yield from range(a + d) 1abcdefghijklmnopqrst
451 iterator = method(5) 1abcdefghijklmnopqrst
453 assert len(list(iterator)) == 13 1abcdefghijklmnopqrst
454 assert len(list(iterator)) == 0 1abcdefghijklmnopqrst