UnfulfilledDeps.__init__()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nop 2
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
import io
2
import typing
3
from typing import List
4
5
import pytest
6
7
from lagom import Container
8
from lagom.definitions import UnresolvableTypeDefinition
9
from lagom.exceptions import (
10
    UnresolvableType,
11
    RecursiveDefinitionError,
12
    TypeResolutionBlocked,
13
)
14
15
16
class MyMissingDep:
17
    def __init__(self, _stuff: str):
18
        pass
19
20
21
class UnfulfilledDeps:
22
    def __init__(self, _stuff: MyMissingDep):
23
        pass
24
25
26
class SomeDep:
27
    pass
28
29
30
@pytest.mark.parametrize("dep", [str, int, float, bool, bytes, bytearray])
31
def test_simple_objects_cannot_be_resolved(container: Container, dep):
32
    with pytest.raises(UnresolvableType):
33
        container.resolve(dep)
34
35
36
@pytest.mark.parametrize(
37
    "dep",
38
    [
39
        io.BytesIO,
40
        io.FileIO,
41
        io.IOBase,
42
        io.RawIOBase,
43
        io.TextIOBase,
44
        io.BufferedIOBase,
45
        io.BufferedRandom,
46
        io.BufferedReader,
47
        io.BufferedRWPair,
48
        io.BufferedWriter,
49
        typing.IO,
50
        typing.TextIO,
51
        typing.BinaryIO,
52
    ],
53
)
54
def test_generic_io_cant_be_resolved(container: Container, dep):
55
    with pytest.raises(UnresolvableType):
56
        container.resolve(dep)
57
58
59
def test_raises_error_with_the_dep_that_couldnt_be_built(container):
60
    with pytest.raises(UnresolvableType):
61
        container.resolve(MyMissingDep)
62
63
64
def test_raises_error_with_the_dep_that_couldnt_be_built_at_the_top_level(container):
65
    with pytest.raises(UnresolvableType) as e_info:
66
        container.resolve(UnfulfilledDeps)
67
    assert (
68
        "Unable to construct dependency of type UnfulfilledDeps "
69
        "The constructor probably has some unresolvable dependencies"
70
        in str(e_info.value)
71
    )
72
73
74
def test_composite_type_failures_still_throw_sensible_errors(container):
75
    with pytest.raises(UnresolvableType) as e_info:
76
        container.resolve(List[UnfulfilledDeps])
77
    exception_message = str(e_info.value)
78
    assert "Unable to construct dependency of type" in exception_message
79
    assert "List[tests.test_error_handling.UnfulfilledDeps]" in exception_message
80
    assert (
81
        "The constructor probably has some unresolvable dependencies"
82
        in exception_message
83
    )
84
85
86
def test_types_can_be_explicitly_made_unresolvable(container: Container):
87
    container[SomeDep] = UnresolvableTypeDefinition("You can't resolve SomeDep")
88
    with pytest.raises(TypeResolutionBlocked) as err:
89
        container.resolve(SomeDep)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable SomeDep does not seem to be defined.
Loading history...
90
    assert "You can't resolve SomeDep" in str(err.value)
91
92
93
def test_types_can_be_explicitly_made_unresolvable_with_a_custom_exception(
94
    container: Container,
95
):
96
    container[SomeDep] = UnresolvableTypeDefinition(SyntaxError("nopes"))
97
    with pytest.raises(SyntaxError) as err:
98
        container.resolve(SomeDep)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable SomeDep does not seem to be defined.
Loading history...
99
    assert str(err.value) == "nopes"
100
101
102
class A:
103
    def __init__(self, b: "B"):
104
        pass
105
106
107
class B:
108
    def __init__(self, a: "A"):
109
        pass
110
111
112
@pytest.mark.skip(
113
    reason="This behaviour is a nice to have but is execution env dependent"
114
)
115
def test_circular_imports_raise_a_clear_error(container):
116
    with pytest.raises(RecursiveDefinitionError) as e_info:
117
        container.resolve(A)
118
    err_string = str(e_info.value)
119
    assert "When trying to build dependency of type " in err_string
120
    assert "This could indicate a circular definition somewhere." in err_string
121
122
123
class MyTypedHTTPClient:
124
    def __init__(self, _stuff: MyMissingDep):
125
        pass
126
127
128
class MyDataProvider:
129
    def __init__(self, _stuff: MyTypedHTTPClient):
130
        pass
131
132
133
class MyService:
134
    def __init__(self, _stuff: MyDataProvider):
135
        pass
136
137
138
@pytest.mark.mypyc_failing
139
def test_error_displays_dependency_list(container):
140
    with pytest.raises(UnresolvableType) as e_info:
141
        container.resolve(MyService)
142
    assert (
143
        str(e_info.value) == "Unable to construct dependency of type MyService "
144
        "The constructor probably has some unresolvable dependencies: "
145
        "MyService => MyDataProvider => MyTypedHTTPClient => MyMissingDep => str => str"
146
    )
147