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

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

8 

9import pytest 1abcdefghijklmnopqrst

10 

11from fast_depends import Depends, inject 1abcdefghijklmnopqrst

12from fast_depends.exceptions import ValidationError 1abcdefghijklmnopqrst

13from tests.marks import serializer 1abcdefghijklmnopqrst

14 

15 

16def test_depends() -> None: 1abcdefghijklmnopqrst

17 def dep_func(b: int, a: int = 3): 1abcdefghijklmnopqrst

18 return a + b 1abcdefghijklmnopqrst

19 

20 @inject 1abcdefghijklmnopqrst

21 def some_func(b: int, c=Depends(dep_func)): 1abcdefghijklmnopqrst

22 return b + c 1abcdefghijklmnopqrst

23 

24 assert some_func(2) == 7 1abcdefghijklmnopqrst

25 

26 

27def test_empty_main_body() -> None: 1abcdefghijklmnopqrst

28 def dep_func(a): 1abcdefghijklmnopqrst

29 return a 1abcdefghijklmnopqrst

30 

31 @inject 1abcdefghijklmnopqrst

32 def some_func(c=Depends(dep_func)): 1abcdefghijklmnopqrst

33 return c 1abcdefghijklmnopqrst

34 

35 assert some_func(1) == 1 1abcdefghijklmnopqrst

36 

37 

38def test_class_depends() -> None: 1abcdefghijklmnopqrst

39 class MyDep: 1abcdefghijklmnopqrst

40 def __init__(self, a): 1abcdefghijklmnopqrst

41 self.a = a 1abcdefghijklmnopqrst

42 

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

48 

49 some_func(3) 1abcdefghijklmnopqrst

50 

51 

52def test_empty_main_body_multiple_args() -> None: 1abcdefghijklmnopqrst

53 def dep2(b): 1abcdefghijklmnopqrst

54 return b 1abcdefghijklmnopqrst

55 

56 def dep(a): 1abcdefghijklmnopqrst

57 return a 1abcdefghijklmnopqrst

58 

59 @inject() 1abcdefghijklmnopqrst

60 def handler(d=Depends(dep2), c=Depends(dep)): 1abcdefghijklmnopqrst

61 return d, c 1abcdefghijklmnopqrst

62 

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

67 

68 

69def test_ignore_depends_if_setted_manual() -> None: 1abcdefghijklmnopqrst

70 mock = Mock() 1abcdefghijklmnopqrst

71 

72 def dep_func(a, b) -> int: 1abcdefghijklmnopqrst

73 mock(a, b) 1abcdefghijklmnopqrst

74 return a + b 1abcdefghijklmnopqrst

75 

76 @inject 1abcdefghijklmnopqrst

77 def some_func(c=Depends(dep_func)) -> int: 1abcdefghijklmnopqrst

78 return c 1abcdefghijklmnopqrst

79 

80 assert some_func(c=2) == 2 1abcdefghijklmnopqrst

81 assert not mock.called 1abcdefghijklmnopqrst

82 

83 assert some_func(1, 2) == 3 1abcdefghijklmnopqrst

84 mock.assert_called_once_with(1, 2) 1abcdefghijklmnopqrst

85 

86 

87def test_depends_annotated_type_str() -> None: 1abcdefghijklmnopqrst

88 def dep_func(a): 1abcdefghijklmnopqrst

89 return a 1abcdefghijklmnopqrst

90 

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

98 

99 @inject 1abcdefghijklmnopqrst

100 def another_func( 1abcdefghijklmnopqrst

101 a: int, 

102 c: Annotated["int", Depends(dep_func)], 

103 ): 

104 return a + c 1abcdefghijklmnopqrst

105 

106 assert some_func(1, 2) == 4 1abcdefghijklmnopqrst

107 assert another_func(3) == 6 1abcdefghijklmnopqrst

108 

109 

110def test_cache() -> None: 1abcdefghijklmnopqrst

111 mock = Mock() 1abcdefghijklmnopqrst

112 

113 def nested_dep_func(): 1abcdefghijklmnopqrst

114 mock() 1abcdefghijklmnopqrst

115 return 1000 1abcdefghijklmnopqrst

116 

117 def dep_func(a=Depends(nested_dep_func)): 1abcdefghijklmnopqrst

118 return a 1abcdefghijklmnopqrst

119 

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

127 

128 some_func() 1abcdefghijklmnopqrst

129 mock.assert_called_once() 1abcdefghijklmnopqrst

130 

131 

132def test_not_cache() -> None: 1abcdefghijklmnopqrst

133 mock = Mock() 1abcdefghijklmnopqrst

134 

135 def nested_dep_func(): 1abcdefghijklmnopqrst

136 mock() 1abcdefghijklmnopqrst

137 return 1000 1abcdefghijklmnopqrst

138 

139 def dep_func(a=Depends(nested_dep_func, use_cache=False)): 1abcdefghijklmnopqrst

140 return a 1abcdefghijklmnopqrst

141 

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

149 

150 some_func() 1abcdefghijklmnopqrst

151 assert mock.call_count == 2 1abcdefghijklmnopqrst

152 

153 

154def test_yield() -> None: 1abcdefghijklmnopqrst

155 mock = Mock() 1abcdefghijklmnopqrst

156 

157 def dep_func(): 1abcdefghijklmnopqrst

158 mock() 1abcdefghijklmnopqrst

159 yield 1000 1abcdefghijklmnopqrst

160 mock.exit() 1abcdefghijklmnopqrst

161 

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

167 

168 some_func() 1abcdefghijklmnopqrst

169 mock.assert_called_once() 1abcdefghijklmnopqrst

170 mock.exit.assert_called_once() 1abcdefghijklmnopqrst

171 

172 

173def test_nested_yield_with_inject() -> None: 1abcdefghijklmnopqrst

174 def dep_c(): 1abcdefghijklmnopqrst

175 yield ["foo"] 1abcdefghijklmnopqrst

176 

177 @inject 1abcdefghijklmnopqrst

178 def dep_b(c=Depends(dep_c)): 1abcdefghijklmnopqrst

179 yield c 1abcdefghijklmnopqrst

180 

181 @inject 1abcdefghijklmnopqrst

182 def a(b=Depends(dep_b)): 1abcdefghijklmnopqrst

183 return b[0] 1abcdefghijklmnopqrst

184 

185 assert a() == "foo" 1abcdefghijklmnopqrst

186 

187 

188def test_callable_class_depends() -> None: 1abcdefghijklmnopqrst

189 class MyDep: 1abcdefghijklmnopqrst

190 def __init__(self, a: int): 1abcdefghijklmnopqrst

191 self.a = a 1abcdefghijklmnopqrst

192 

193 def __call__(self) -> int: 1abcdefghijklmnopqrst

194 return self.a 1abcdefghijklmnopqrst

195 

196 @inject 1abcdefghijklmnopqrst

197 def some_func(a: int = Depends(MyDep(3))): # noqa: B008 1abcdefghijklmnopqrst

198 assert a == 3 1abcdefghijklmnopqrst

199 return a 1abcdefghijklmnopqrst

200 

201 some_func() 1abcdefghijklmnopqrst

202 

203 

204def test_not_cast_main() -> None: 1abcdefghijklmnopqrst

205 @dataclass 1abcdefghijklmnopqrst

206 class A: 1abcdefghijklmnopqrst

207 a: int 1abcdefghijkls

208 

209 def dep() -> A: 1abcdefghijklmnopqrst

210 return A(a=1) 1abcdefghijklmnopqrst

211 

212 def get_logger() -> logging.Logger: 1abcdefghijklmnopqrst

213 return logging.getLogger(__file__) 1abcdefghijklmnopqrst

214 

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

224 

225 assert some_func(1) == 1 1abcdefghijklmnopqrst

226 

227 

228def test_extra() -> None: 1abcdefghijklmnopqrst

229 mock = Mock() 1abcdefghijklmnopqrst

230 

231 def dep(): 1abcdefghijklmnopqrst

232 mock.sync_call() 1abcdefghijklmnopqrst

233 

234 @inject(extra_dependencies=(Depends(dep),)) 1abcdefghijklmnopqrst

235 def some_func(): 1abcdefghijklmnopqrst

236 mock() 1abcdefghijklmnopqrst

237 

238 some_func() 1abcdefghijklmnopqrst

239 mock.assert_called_once() 1abcdefghijklmnopqrst

240 mock.sync_call.assert_called_once() 1abcdefghijklmnopqrst

241 

242 

243def test_async_extra() -> None: 1abcdefghijklmnopqrst

244 mock = Mock() 1abcdefghijklmnopqrst

245 

246 async def dep(): # pragma: no cover 1abcdefghijklmnopqrst

247 mock.sync_call() 

248 

249 with pytest.raises(AssertionError): 1abcdefghijklmnopqrst

250 

251 @inject(extra_dependencies=(Depends(dep),)) 1abcdefghijklmnopqrst

252 def some_func(): # pragma: no cover 1abcdefghijklmnopqrst

253 mock() 

254 

255 

256def test_async_depends() -> None: 1abcdefghijklmnopqrst

257 async def dep_func(a: int) -> float: # pragma: no cover 1abcdefghijklmnopqrst

258 return a 

259 

260 with pytest.raises(AssertionError): 1abcdefghijklmnopqrst

261 

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 

265 

266 

267def test_async_extra_depends() -> None: 1abcdefghijklmnopqrst

268 async def dep_func(a: int) -> float: # pragma: no cover 1abcdefghijklmnopqrst

269 return a 

270 

271 with pytest.raises(AssertionError): 1abcdefghijklmnopqrst

272 

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 

276 

277 

278def test_generator() -> None: 1abcdefghijklmnopqrst

279 mock = Mock() 1abcdefghijklmnopqrst

280 

281 def simple_func(): 1abcdefghijklmnopqrst

282 mock.simple() 1abcdefghijklmnopqrst

283 

284 def func(): 1abcdefghijklmnopqrst

285 mock.start() 1abcdefghijklmnopqrst

286 yield 1abcdefghijklmnopqrst

287 mock.end() 1abcdefghijklmnopqrst

288 

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

293 

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

298 

299 mock.simple.assert_called_once() 1abcdefghijklmnopqrst

300 mock.end.assert_called_once() 1abcdefghijklmnopqrst

301 

302 

303def test_partial() -> None: 1abcdefghijklmnopqrst

304 def dep(a): 1abcdefghijklmnopqrst

305 return a 1abcdefghijklmnopqrst

306 

307 @inject 1abcdefghijklmnopqrst

308 def func(a=Depends(partial(dep, 10))): # noqa: B008 1abcdefghijklmnopqrst

309 return a 1abcdefghijklmnopqrst

310 

311 assert func() == 10 1abcdefghijklmnopqrst

312 

313 

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

320 

321 def dep1() -> A: 1abcdefghijklmnopqr

322 return {"a": 1} 1abcdefghijklmnopqr

323 

324 def dep2() -> A: 1abcdefghijklmnopqr

325 return {"a": 1} 1abcdefghijklmnopqr

326 

327 def dep3() -> A: 1abcdefghijklmnopqr

328 return 1 1abcdefghijklmnopqr

329 

330 def get_logger() -> logging.Logger: 1abcdefghijklmnopqr

331 return logging.getLogger(__file__) 1abcdefghijklmnopqr

332 

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

346 

347 assert some_func(1) == 1 1abcdefghijklmnopqr

348 

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 

352 

353 def another_func(b: int, a: int = 3) -> dict: # pragma: no cover 1abcdefghijklmnopqr

354 return a + b 

355 

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 

362 

363 with pytest.raises(ValidationError): 1abcdefghijklmnopqr

364 assert some_func("2") == 7 1abcdefghijklmnopqr

365 

366 def test_depends_response_cast(self) -> None: 1abcdefghijklmnopqrst

367 def dep_func(a): 1abcdefghijklmnopqr

368 return a 1abcdefghijklmnopqr

369 

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

375 

376 assert some_func("1", "2") 1abcdefghijklmnopqr

377 

378 def test_depends_annotated_str(self) -> None: 1abcdefghijklmnopqrst

379 def dep_func(a): 1abcdefghijklmnopqr

380 return a 1abcdefghijklmnopqr

381 

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

390 

391 @inject 1abcdefghijklmnopqr

392 def another_func( 1abcdefghijklmnopqr

393 a: int, 

394 c: "Annotated[int, Depends(dep_func)]", 

395 ): 

396 return a + c 1abcdefghijklmnopqr

397 

398 assert some_func("1", "2") 1abcdefghijklmnopqr

399 assert another_func("3") == 6.0 1abcdefghijklmnopqr

400 

401 

402def test_default_key_value() -> None: 1abcdefghijklmnopqrst

403 def dep(a: str = "a"): 1abcdefghijklmnopqrst

404 return a 1abcdefghijklmnopqrst

405 

406 @inject(cast=False) 1abcdefghijklmnopqrst

407 def func(a=Depends(dep)): 1abcdefghijklmnopqrst

408 return a 1abcdefghijklmnopqrst

409 

410 assert func() == "a" 1abcdefghijklmnopqrst

411 

412 

413def test_contextmanager() -> None: 1abcdefghijklmnopqrst

414 def dep(a: str): 1abcdefghijklmnopqrst

415 return a 1abcdefghijklmnopqrst

416 

417 @contextmanager 1abcdefghijklmnopqrst

418 @inject 1abcdefghijklmnopqrst

419 def func(a: str, b: str = Depends(dep)): 1abcdefghijklmnopqrst

420 yield a == b 1abcdefghijklmnopqrst

421 

422 with func("a") as is_equal: 1abcdefghijklmnopqrst

423 assert is_equal 1abcdefghijklmnopqrst

424 

425 

426def test_solve_wrapper() -> None: 1abcdefghijklmnopqrst

427 @inject 1abcdefghijklmnopqrst

428 def dep1(a: int) -> Generator[int, None, None]: 1abcdefghijklmnopqrst

429 yield a + 1 1abcdefghijklmnopqrst

430 

431 def dep2(a: int) -> Generator[int, None, None]: 1abcdefghijklmnopqrst

432 yield a + 2 1abcdefghijklmnopqrst

433 

434 @inject 1abcdefghijklmnopqrst

435 def func(a: int, b: int = Depends(dep1), c: int = Depends(dep2)): 1abcdefghijklmnopqrst

436 return a, b, c 1abcdefghijklmnopqrst

437 

438 assert func(1) == (1, 2, 3) 1abcdefghijklmnopqrst

439 

440 

441def test_generator_iter() -> None: 1abcdefghijklmnopqrst

442 # ref: https://github.com/Lancetnik/FastDepends/issues/165 

443 

444 def simple_dependency(a: int, b: int = 3) -> int: 1abcdefghijklmnopqrst

445 return a + b 1abcdefghijklmnopqrst

446 

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

450 

451 iterator = method(5) 1abcdefghijklmnopqrst

452 

453 assert len(list(iterator)) == 13 1abcdefghijklmnopqrst

454 assert len(list(iterator)) == 0 1abcdefghijklmnopqrst