|
1
|
|
|
from itertools import chain |
|
2
|
|
|
from typing import TypeVar, Type, Optional, Set, Tuple, Collection, Sequence |
|
3
|
|
|
|
|
4
|
|
|
from .container import Container |
|
5
|
|
|
from .interfaces import DefinitionsSource, SpecialDepDefinition |
|
6
|
|
|
|
|
7
|
|
|
X = TypeVar("X") |
|
8
|
|
|
|
|
9
|
|
|
|
|
10
|
|
|
def compose(*args: DefinitionsSource) -> Container: |
|
11
|
|
|
combined_sources = _SourceList(*args) |
|
12
|
|
|
_assert_unique_dependencies(args) |
|
13
|
|
|
|
|
14
|
|
|
return Container(container=combined_sources) |
|
15
|
|
|
|
|
16
|
|
|
|
|
17
|
|
|
class _SourceList(DefinitionsSource): |
|
18
|
|
|
""" |
|
19
|
|
|
Combines multiple `DefinitionsSource`s which are accessed in order |
|
20
|
|
|
""" |
|
21
|
|
|
|
|
22
|
|
|
sources: Collection[DefinitionsSource] |
|
23
|
|
|
|
|
24
|
|
|
def __init__(self, *args: DefinitionsSource): |
|
25
|
|
|
self.sources = args |
|
26
|
|
|
|
|
27
|
|
|
def get_definition(self, dep_type: Type[X]) -> Optional[SpecialDepDefinition[X]]: |
|
28
|
|
|
""" |
|
29
|
|
|
For a supplied type returns the definition of how to build that type. |
|
30
|
|
|
If unknown None is returned |
|
31
|
|
|
:param dep_type: |
|
32
|
|
|
""" |
|
33
|
|
|
for source in self.sources: |
|
34
|
|
|
definition = source.get_definition(dep_type) |
|
35
|
|
|
if definition is not None: |
|
36
|
|
|
return definition |
|
37
|
|
|
return None |
|
38
|
|
|
|
|
39
|
|
|
@property |
|
40
|
|
|
def defined_types(self) -> Set[Type]: |
|
41
|
|
|
""" |
|
42
|
|
|
The list of types that have been explicitly defined |
|
43
|
|
|
:return: |
|
44
|
|
|
""" |
|
45
|
|
|
return set(chain.from_iterable(s.defined_types for s in self.sources)) |
|
46
|
|
|
|
|
47
|
|
|
|
|
48
|
|
|
def _assert_unique_dependencies(definition_sources: Sequence[DefinitionsSource]): |
|
49
|
|
|
for first in range(0, len(definition_sources)): |
|
50
|
|
|
for second in range(first + 1, len(definition_sources)): |
|
51
|
|
|
for dep in definition_sources[first].defined_types: |
|
52
|
|
|
if ( |
|
53
|
|
|
dep.__name__ != "ContainerDebugInfo" |
|
54
|
|
|
and dep in definition_sources[second].defined_types |
|
55
|
|
|
): |
|
56
|
|
|
raise ValueError(f"Dep {dep} defined in {first} and {second}") |
|
57
|
|
|
|