tests.test_magic_partial_functions   A
last analyzed

Complexity

Total Complexity 26

Size/Duplication

Total Lines 159
Duplicated Lines 8.81 %

Importance

Changes 0
Metric Value
eloc 93
dl 14
loc 159
rs 10
c 0
b 0
f 0
wmc 26

21 Functions

Rating   Name   Duplication   Size   Complexity  
A test_container_values_can_be_overridden() 0 4 1
A test_partial_application_can_be_applied_to_generators() 0 4 1
A test_missing_call_arguments_results_in_sensible_error_messages() 0 5 2
A test_if_a_typed_argument_cant_be_constructed_a_helpful_exception_is_returned() 0 6 2
A failing_to_construct_function() 0 3 1
A test_passed_in_arguments_are_used_over_container_generated_ones_when_named() 0 3 1
A test_incorrect_arguments_are_handled_well() 0 4 2
A example_function_with_to_injectables() 0 2 1
A test_a_decorator_can_be_used_to_bind_as_well() 0 2 1
A test_deps_are_loaded_at_call_time_not_definition_time() 0 8 1
A test_passed_in_arguments_are_used_over_container_generated_ones_when_positional() 0 3 1
A example_generator() 0 3 1
A test_partial_application_returns_something_that_is_considered_a_function() 0 3 1
A example_function() 0 2 1
A test_a_decorator_can_be_used_to_bind_and_with_positional_arguments() 0 2 1
A test_partial_application_can_be_applied_to_functions_with_named_args() 0 3 1
A test_injected_arguments_can_be_skipped() 0 3 1
A another_example_function() 0 6 1
A test_partial_application_can_be_applied_to_functions_with_positional_args_first() 0 3 1
A test_name_and_docs_are_kept() 0 5 1
A test_partials_can_be_provided_with_an_update_method() 14 14 1

2 Methods

Rating   Name   Duplication   Size   Complexity  
A CantBeAutoConstructed.__init__() 0 2 1
A MyDep.__init__() 0 3 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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