example_function()   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 inspect
2
from typing import Generator, Any, ClassVar
3
4
import pytest
5
6
from lagom import Container, magic_bind_to_container
7
from lagom.exceptions import UnableToInvokeBoundFunction
8
from lagom.interfaces import WriteableContainer
9
10
11
class MyDep:
12
    loaded: ClassVar[bool] = False
13
    value: str
14
15
    def __init__(self, value="testing"):
16
        MyDep.loaded = True
17
        self.value = value
18
19
20
class CantBeAutoConstructed:
21
    def __init__(self, something):
22
        pass
23
24
25
container = Container()
26
27
28
def example_function(message: str, resolved: MyDep) -> str:
29
    return resolved.value + message
30
31
32
def example_function_with_to_injectables(one: MyDep, two: MyDep) -> str:
33
    return one.value + two.value
34
35
36
def example_generator(message: str, resolved: MyDep) -> Generator[str, Any, Any]:
37
    yield resolved.value + message
38
    yield resolved.value + " finished"
39
40
41
@magic_bind_to_container(container)
42
def another_example_function(message: str, resolved: MyDep) -> str:
43
    """
44
    I am DOCS
45
    """
46
    return resolved.value + message
47
48
49
@magic_bind_to_container(container)
50
def failing_to_construct_function(try_to_resolve: CantBeAutoConstructed) -> str:
51
    return "doesnt matter"
52
53
54
def test_partial_application_can_be_applied_to_functions_with_named_args():
55
    partial = container.magic_partial(example_function)
56
    assert partial(message=" world") == "testing world"
57
58
59
def test_partial_application_returns_something_that_is_considered_a_function():
60
    partial = container.magic_partial(example_function)
61
    inspect.isfunction(partial)
62
63
64
def test_partial_application_can_be_applied_to_functions_with_positional_args_first():
65
    partial = container.magic_partial(example_function)
66
    assert partial(" world") == "testing world"
67
68
69
def test_passed_in_arguments_are_used_over_container_generated_ones_when_positional():
70
    partial = container.magic_partial(example_function)
71
    assert partial(" world", MyDep("overridden")) == "overridden world"
72
73
74
def test_passed_in_arguments_are_used_over_container_generated_ones_when_named():
75
    partial = container.magic_partial(example_function)
76
    assert partial(message=" world", resolved=MyDep("overridden")) == "overridden world"
77
78
79
def test_injected_arguments_can_be_skipped():
80
    partial = container.magic_partial(example_function_with_to_injectables)
81
    assert partial(two=MyDep(" 2nd")) == "testing 2nd"
82
83
84
def test_a_decorator_can_be_used_to_bind_as_well():
85
    assert another_example_function(message=" hello") == "testing hello"
86
87
88
def test_a_decorator_can_be_used_to_bind_and_with_positional_arguments():
89
    assert another_example_function(" hello") == "testing hello"
90
91
92
def test_container_values_can_be_overridden():
93
    assert (
94
        another_example_function(resolved=MyDep("replaced"), message=" hello")
95
        == "replaced hello"
96
    )
97
98
99
def test_missing_call_arguments_results_in_sensible_error_messages():
100
    with pytest.raises(TypeError) as err:
101
        another_example_function()
102
    assert "another_example_function() missing 1 required positional argument" in str(
103
        err.value
104
    )
105
106
107
def test_incorrect_arguments_are_handled_well():
108
    with pytest.raises(TypeError) as err:
109
        another_example_function(not_the_message=" no")
110
    assert "unexpected keyword argument 'not_the_message'" in str(err.value)
111
112
113
def test_if_a_typed_argument_cant_be_constructed_a_helpful_exception_is_returned():
114
    with pytest.raises(UnableToInvokeBoundFunction) as err:
115
        failing_to_construct_function()
116
    assert (
117
        "The container could not construct the following types: CantBeAutoConstructed"
118
        in str(err.value)
119
    )
120
121
122
def test_partial_application_can_be_applied_to_generators():
123
    partial = container.magic_partial(example_generator)
124
    results = [result for result in partial(message=" world")]
125
    assert results == ["testing world", "testing finished"]
126
127
128
def test_deps_are_loaded_at_call_time_not_definition_time():
129
    MyDep.loaded = False
130
131
    @magic_bind_to_container(container)
132
    def some_random_unused_function(message: str, resolved: MyDep) -> str:
133
        return resolved.value + message
134
135
    assert not MyDep.loaded
136
137
138
def test_name_and_docs_are_kept():
139
    assert another_example_function.__name__ == "another_example_function"
140
    # Note: whitespace stripping because some versions of python format the docs differently
141
    #       and we don't care too much about that. just that content is kept.
142
    assert another_example_function.__doc__.strip() == "I am DOCS"  # type: ignore[union-attr]
143
144
145 View Code Duplication
def test_partials_can_be_provided_with_an_update_method(container: Container):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
146
    def _my_func(a, b: MyDep):
147
        return a, b
148
149
    def _dep_two_is_dep_one(c: WriteableContainer, a, k):
150
        # We'll do something a bit weird and say the container
151
        # always injects the first supplied argument when asked for
152
        # a MyDep. Don't do this for real.
153
        c[MyDep] = a[0]
154
155
    weird = container.magic_partial(_my_func, container_updater=_dep_two_is_dep_one)
156
157
    arg_1, arg_2 = weird("hello")
158
    assert arg_1 == arg_2
159