Skip to content

Commit f8ab127

Browse files
committed
Add support for List and Dict providers to _locate_dependent_closing_args
1 parent 72a316c commit f8ab127

File tree

3 files changed

+91
-103
lines changed

3 files changed

+91
-103
lines changed

src/dependency_injector/wiring.py

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
"""Wiring module."""
22

33
import functools
4-
import inspect
54
import importlib
65
import importlib.machinery
6+
import inspect
77
import pkgutil
8-
import warnings
98
import sys
9+
import warnings
1010
from types import ModuleType
1111
from typing import (
12-
Optional,
13-
Iterable,
14-
Iterator,
15-
Callable,
1612
Any,
17-
Tuple,
13+
Callable,
1814
Dict,
1915
Generic,
20-
TypeVar,
16+
Iterable,
17+
Iterator,
18+
Optional,
19+
Set,
20+
Tuple,
2121
Type,
22+
TypeVar,
2223
Union,
23-
Set,
2424
cast,
2525
)
2626

@@ -643,21 +643,18 @@ def _fetch_reference_injections( # noqa: C901
643643

644644

645645
def _locate_dependent_closing_args(
646-
provider: providers.Provider,
646+
provider: providers.Provider, closing_deps: Dict[str, providers.Provider]
647647
) -> Dict[str, providers.Provider]:
648-
if not hasattr(provider, "args"):
649-
return {}
650-
651-
closing_deps = {}
652-
for arg in [*provider.args, *provider.kwargs.values()]:
653-
if not isinstance(arg, providers.Provider) or not hasattr(arg, "args"):
648+
for arg in [
649+
*getattr(provider, "args", []),
650+
*getattr(provider, "kwargs", {}).values(),
651+
]:
652+
if not isinstance(arg, providers.Provider):
654653
continue
655654
if isinstance(arg, providers.Resource):
656-
return {str(id(arg)): arg}
657-
if arg.args or arg.kwargs:
658-
closing_deps |= _locate_dependent_closing_args(arg)
655+
closing_deps[str(id(arg))] = arg
659656

660-
return closing_deps
657+
_locate_dependent_closing_args(arg, closing_deps)
661658

662659

663660
def _bind_injections(fn: Callable[..., Any], providers_map: ProvidersMap) -> None:
@@ -681,7 +678,8 @@ def _bind_injections(fn: Callable[..., Any], providers_map: ProvidersMap) -> Non
681678

682679
if injection in patched_callable.reference_closing:
683680
patched_callable.add_closing(injection, provider)
684-
deps = _locate_dependent_closing_args(provider)
681+
deps = {}
682+
_locate_dependent_closing_args(provider, deps)
685683
for key, dep in deps.items():
686684
patched_callable.add_closing(key, dep)
687685

@@ -1030,8 +1028,8 @@ def is_loader_installed() -> bool:
10301028
_loader = AutoLoader()
10311029

10321030
# Optimizations
1033-
from ._cwiring import _get_sync_patched # noqa
10341031
from ._cwiring import _async_inject # noqa
1032+
from ._cwiring import _get_sync_patched # noqa
10351033

10361034

10371035
# Wiring uses the following Python wrapper because there is
Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,78 @@
1+
from typing import Any, Dict, List, Optional
2+
13
from dependency_injector import containers, providers
2-
from dependency_injector.wiring import inject, Provide, Closing
4+
from dependency_injector.wiring import Closing, Provide, inject
5+
6+
7+
class Counter:
8+
def __init__(self) -> None:
9+
self._init = 0
10+
self._shutdown = 0
11+
12+
def init(self) -> None:
13+
self._init += 1
314

15+
def shutdown(self) -> None:
16+
self._shutdown += 1
417

5-
class Singleton:
6-
pass
18+
def reset(self) -> None:
19+
self._init = 0
20+
self._shutdown = 0
721

822

923
class Service:
10-
init_counter: int = 0
11-
shutdown_counter: int = 0
12-
dependency: Singleton = None
24+
def __init__(self, counter: Optional[Counter] = None, **dependencies: Any) -> None:
25+
self.counter = counter or Counter()
26+
self.dependencies = dependencies
1327

14-
@classmethod
15-
def reset_counter(cls):
16-
cls.init_counter = 0
17-
cls.shutdown_counter = 0
28+
def init(self) -> None:
29+
self.counter.init()
1830

19-
@classmethod
20-
def init(cls, dependency: Singleton = None):
21-
if dependency:
22-
cls.dependency = dependency
23-
cls.init_counter += 1
31+
def shutdown(self) -> None:
32+
self.counter.shutdown()
2433

25-
@classmethod
26-
def shutdown(cls):
27-
cls.shutdown_counter += 1
34+
@property
35+
def init_counter(self) -> int:
36+
return self.counter._init
37+
38+
@property
39+
def shutdown_counter(self) -> int:
40+
return self.counter._shutdown
2841

2942

3043
class FactoryService:
31-
def __init__(self, service: Service):
44+
def __init__(self, service: Service, service2: Service):
3245
self.service = service
46+
self.service2 = service2
3347

3448

3549
class NestedService:
3650
def __init__(self, factory_service: FactoryService):
3751
self.factory_service = factory_service
3852

3953

40-
def init_service():
41-
service = Service()
54+
def init_service(counter: Counter, _list: List[int], _dict: Dict[str, int]):
55+
service = Service(counter, _list=_list, _dict=_dict)
4256
service.init()
4357
yield service
4458
service.shutdown()
4559

4660

47-
def init_service_with_singleton(singleton: Singleton):
48-
service = Service()
49-
service.init(singleton)
50-
yield service
51-
service.shutdown()
52-
53-
5461
class Container(containers.DeclarativeContainer):
55-
56-
service = providers.Resource(init_service)
57-
factory_service = providers.Factory(FactoryService, service)
58-
factory_service_kwargs = providers.Factory(
59-
FactoryService,
60-
service=service
62+
counter = providers.Singleton(Counter)
63+
_list = providers.List(
64+
providers.Callable(lambda a: a, a=1), providers.Callable(lambda b: b, 2)
6165
)
62-
nested_service = providers.Factory(NestedService, factory_service)
63-
64-
65-
class ContainerSingleton(containers.DeclarativeContainer):
66-
67-
singleton = providers.Singleton(Singleton)
68-
service = providers.Resource(
69-
init_service_with_singleton,
70-
singleton
66+
_dict = providers.Dict(
67+
a=providers.Callable(lambda a: a, a=3), b=providers.Callable(lambda b: b, 4)
7168
)
72-
factory_service = providers.Factory(FactoryService, service)
69+
service = providers.Resource(init_service, counter, _list, _dict=_dict)
70+
service2 = providers.Resource(init_service, counter, _list, _dict=_dict)
71+
factory_service = providers.Factory(FactoryService, service, service2)
7372
factory_service_kwargs = providers.Factory(
7473
FactoryService,
75-
service=service
74+
service=service,
75+
service2=service2,
7676
)
7777
nested_service = providers.Factory(NestedService, factory_service)
7878

@@ -84,20 +84,20 @@ def test_function(service: Service = Closing[Provide["service"]]):
8484

8585
@inject
8686
def test_function_dependency(
87-
factory: FactoryService = Closing[Provide["factory_service"]]
87+
factory: FactoryService = Closing[Provide["factory_service"]],
8888
):
8989
return factory
9090

9191

9292
@inject
9393
def test_function_dependency_kwargs(
94-
factory: FactoryService = Closing[Provide["factory_service_kwargs"]]
94+
factory: FactoryService = Closing[Provide["factory_service_kwargs"]],
9595
):
9696
return factory
9797

9898

9999
@inject
100100
def test_function_nested_dependency(
101-
nested: NestedService = Closing[Provide["nested_service"]]
101+
nested: NestedService = Closing[Provide["nested_service"]],
102102
):
103103
return nested

tests/unit/wiring/string_ids/test_main_py36.py

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
from decimal import Decimal
44

5-
from dependency_injector import errors
6-
from dependency_injector.wiring import Closing, Provide, Provider, wire
75
from pytest import fixture, mark, raises
8-
96
from samples.wiringstringids import module, package, resourceclosing
10-
from samples.wiringstringids.service import Service
117
from samples.wiringstringids.container import Container, SubContainer
8+
from samples.wiringstringids.service import Service
9+
10+
from dependency_injector import errors
11+
from dependency_injector.wiring import Closing, Provide, Provider, wire
1212

1313

1414
@fixture(autouse=True)
@@ -33,14 +33,12 @@ def subcontainer():
3333
container.unwire()
3434

3535

36-
@fixture(params=[
37-
resourceclosing.Container,
38-
resourceclosing.ContainerSingleton,
39-
])
36+
@fixture
4037
def resourceclosing_container(request):
41-
container = request.param()
38+
container = resourceclosing.Container()
4239
container.wire(modules=[resourceclosing])
43-
yield container
40+
with container.reset_singletons():
41+
yield container
4442
container.unwire()
4543

4644

@@ -277,72 +275,65 @@ def test_wire_multiple_containers():
277275

278276
@mark.usefixtures("resourceclosing_container")
279277
def test_closing_resource():
280-
resourceclosing.Service.reset_counter()
281-
282278
result_1 = resourceclosing.test_function()
283279
assert isinstance(result_1, resourceclosing.Service)
284280
assert result_1.init_counter == 1
285281
assert result_1.shutdown_counter == 1
282+
assert result_1.dependencies == {"_list": [1, 2], "_dict": {"a": 3, "b": 4}}
286283

287284
result_2 = resourceclosing.test_function()
288285
assert isinstance(result_2, resourceclosing.Service)
289286
assert result_2.init_counter == 2
290287
assert result_2.shutdown_counter == 2
288+
assert result_1.dependencies == {"_list": [1, 2], "_dict": {"a": 3, "b": 4}}
291289

292290
assert result_1 is not result_2
293291

294292

295293
@mark.usefixtures("resourceclosing_container")
296294
def test_closing_dependency_resource():
297-
resourceclosing.Service.reset_counter()
298-
299295
result_1 = resourceclosing.test_function_dependency()
300296
assert isinstance(result_1, resourceclosing.FactoryService)
301-
assert result_1.service.init_counter == 1
302-
assert result_1.service.shutdown_counter == 1
297+
assert result_1.service.init_counter == 2
298+
assert result_1.service.shutdown_counter == 2
303299

304300
result_2 = resourceclosing.test_function_dependency()
301+
305302
assert isinstance(result_2, resourceclosing.FactoryService)
306-
assert result_2.service.init_counter == 2
307-
assert result_2.service.shutdown_counter == 2
303+
assert result_2.service.init_counter == 4
304+
assert result_2.service.shutdown_counter == 4
308305

309306

310307
@mark.usefixtures("resourceclosing_container")
311308
def test_closing_dependency_resource_kwargs():
312-
resourceclosing.Service.reset_counter()
313-
314309
result_1 = resourceclosing.test_function_dependency_kwargs()
315310
assert isinstance(result_1, resourceclosing.FactoryService)
316-
assert result_1.service.init_counter == 1
317-
assert result_1.service.shutdown_counter == 1
311+
assert result_1.service.init_counter == 2
312+
assert result_1.service.shutdown_counter == 2
318313

319314
result_2 = resourceclosing.test_function_dependency_kwargs()
320315
assert isinstance(result_2, resourceclosing.FactoryService)
321-
assert result_2.service.init_counter == 2
322-
assert result_2.service.shutdown_counter == 2
316+
assert result_2.service.init_counter == 4
317+
assert result_2.service.shutdown_counter == 4
323318

324319

325320
@mark.usefixtures("resourceclosing_container")
326321
def test_closing_nested_dependency_resource():
327-
resourceclosing.Service.reset_counter()
328-
329322
result_1 = resourceclosing.test_function_nested_dependency()
330323
assert isinstance(result_1, resourceclosing.NestedService)
331-
assert result_1.factory_service.service.init_counter == 1
332-
assert result_1.factory_service.service.shutdown_counter == 1
324+
assert result_1.factory_service.service.init_counter == 2
325+
assert result_1.factory_service.service.shutdown_counter == 2
333326

334327
result_2 = resourceclosing.test_function_nested_dependency()
335328
assert isinstance(result_2, resourceclosing.NestedService)
336-
assert result_2.factory_service.service.init_counter == 2
337-
assert result_2.factory_service.service.shutdown_counter == 2
329+
assert result_2.factory_service.service.init_counter == 4
330+
assert result_2.factory_service.service.shutdown_counter == 4
338331

339332
assert result_1 is not result_2
340333

341334

342335
@mark.usefixtures("resourceclosing_container")
343336
def test_closing_resource_bypass_marker_injection():
344-
resourceclosing.Service.reset_counter()
345-
346337
result_1 = resourceclosing.test_function(service=Closing[Provide["service"]])
347338
assert isinstance(result_1, resourceclosing.Service)
348339
assert result_1.init_counter == 1
@@ -358,7 +349,6 @@ def test_closing_resource_bypass_marker_injection():
358349

359350
@mark.usefixtures("resourceclosing_container")
360351
def test_closing_resource_context():
361-
resourceclosing.Service.reset_counter()
362352
service = resourceclosing.Service()
363353

364354
result_1 = resourceclosing.test_function(service=service)

0 commit comments

Comments
 (0)