Passed
Push — master ( 8dc26c...68acdf )
by Steve
02:50
created

tests.test_error_handling.MyService.__init__()   A

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(
88
        SomeDep, "You can't resolve SomeDep"
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable SomeDep does not seem to be defined.
Loading history...
89
    )
90
    with pytest.raises(TypeResolutionBlocked) as err:
91
        container.resolve(SomeDep)
92
    assert "You can't resolve SomeDep" in str(err.value)
93
94
95
def test_types_can_be_explicitly_made_unresolvable_with_a_custom_exception(
96
    container: Container,
97
):
98
    container[SomeDep] = UnresolvableTypeDefinition(SomeDep, SyntaxError("nopes"))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable SomeDep does not seem to be defined.
Loading history...
99
    with pytest.raises(SyntaxError) as err:
100
        container.resolve(SomeDep)
101
    assert str(err.value) == "nopes"
102
103
104
class A:
105
    def __init__(self, b: "B"):
106
        pass
107
108
109
class B:
110
    def __init__(self, a: "A"):
111
        pass
112
113
114
@pytest.mark.skip(
115
    reason="This behaviour is a nice to have but is execution env dependent"
116
)
117
def test_circular_imports_raise_a_clear_error(container):
118
    with pytest.raises(RecursiveDefinitionError) as e_info:
119
        container.resolve(A)
120
    err_string = str(e_info.value)
121
    assert "When trying to build dependency of type " in err_string
122
    assert "This could indicate a circular definition somewhere." in err_string
123
124
125
class MyTypedHTTPClient:
126
    def __init__(self, _stuff: MyMissingDep):
127
        pass
128
129
130
class MyDataProvider:
131
    def __init__(self, _stuff: MyTypedHTTPClient):
132
        pass
133
134
135
class MyService:
136
    def __init__(self, _stuff: MyDataProvider):
137
        pass
138
139
140
@pytest.mark.mypyc_failing
141
def test_error_displays_dependency_list(container):
142
    with pytest.raises(UnresolvableType) as e_info:
143
        container.resolve(MyService)
144
    assert (
145
        str(e_info.value) == "Unable to construct dependency of type MyService "
146
        "The constructor probably has some unresolvable dependencies: "
147
        "MyService => MyDataProvider => MyTypedHTTPClient => MyMissingDep => str => str"
148
    )
149