Test Failed
Pull Request — master (#252)
by Steve
06:28
created

lagom.composition.compose()   A

Complexity

Conditions 1

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
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