-
Notifications
You must be signed in to change notification settings - Fork 0
/
test_build.py
217 lines (191 loc) · 7.1 KB
/
test_build.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
"""
Test file with examples of DI usage.
"""
from di.declarative import (
DeclarativeApp,
DeclarativeModule,
NameModuleImport,
VariableFilterSets,
add_factories,
add_values,
arg_check,
scan_factories,
scan_values,
type_check,
)
from tests.di.declarative import mod_abstract, mod_config, mod_impl, mod_plugins
from tests.di.declarative.mod_abstract import AllCombinations, DataProvider
def _check_app_works(all_combinations: AllCombinations):
"""
Tests if `AllCombinations` object is configured properly.
:param all_combinations: `AllCombinations` object
"""
combinations = [*all_combinations.all()]
assert set(combinations) == {
frozenset(pair)
for pair in [
("1", "A"),
("1", "B"),
("1", "2"),
("A", "B"),
("A", "2"),
("B", "2"),
]
}
def test_plain():
"""
Tests application initialized in plain way.
This example looks simple, but real-world applications are much more complex.
"""
all_combinations = mod_abstract.AllCombinations(
config=mod_config.config,
combinations_generator=mod_impl.ItertoolsGroupCombinationsGenerator(),
providers=[mod_plugins.LetterDataProvider(), mod_plugins.NumberDataProvider()],
)
_check_app_works(all_combinations)
def test_build_manual():
"""
Creates application using declarative containers
with manual control of used components.
"""
# Create application definition by creating `DeclarativeApp` object
app_def = DeclarativeApp(
# Add logical module config
DeclarativeModule(
# Add module components - specified list of values
add_values(mod_config.config),
# Set name to "config"
name="config",
),
# Add logical module main
DeclarativeModule(
# Add module components - specified list of factories
add_factories(
mod_abstract.AllCombinations,
mod_impl.ItertoolsGroupCombinationsGenerator,
mod_plugins.LetterDataProvider,
mod_plugins.NumberDataProvider,
),
# Import config module by name
imports=["config"],
# Set name to main
name="main",
),
# Add argument aggregation of `DataProvider` collection
agg_checks=[type_check(DataProvider)],
)
# This operation builds application instance:
# - solves module dependency graph
# - solves in module dependency injection sub-graphs
# - initializes factories dependency injection chain
# - calls factories marked by `bootstrap` option
instance = app_def.build_instance()
# This operation creates/gets `AllCombinations` provided
# by automatic dependency injection mechanism.
(all_combinations,) = instance.values_by_type(mod_abstract.AllCombinations)
# Check initialized application.
_check_app_works(all_combinations)
def test_build_scan():
"""
Creates application using declarative containers
with automatic control of used components.
"""
# Create application definition part by part
# Create logical module config
config = DeclarativeModule(
# Scan for all values in `mod_config` using specified filter sets (optional)
scan_values(mod_config, filter_sets=[VariableFilterSets.domain()]),
# Set name config
name="config",
)
# Create logical module main
main = DeclarativeModule(
# Add factory to module with aggregation in argument named "providers"
add_factories(
mod_abstract.AllCombinations, agg_checks=[arg_check("providers")]
),
# Scan for all factories in `mod_impl` and `mod_plugins`
scan_factories(mod_impl, mod_plugins),
# Import config module by reference
imports=[config],
# Set name to main
name="main",
)
# Create app definition.
# NOTE:
# By default application option `follow_imports` is `True`,
# which means that modules recursively imported,
# but not provided in app definition will be added automatically.
app_def = DeclarativeApp(main)
# This operation builds application instance:
# - solves module dependency graph
# - solves in module dependency injection sub-graphs
# - initializes factories dependency injection chain
# - calls factories marked by `bootstrap` option
instance = app_def.build_instance()
# This operation creates/gets `AllCombinations` provided
# by automatic dependency injection mechanism.
(all_combinations,) = instance.values_by_type(mod_abstract.AllCombinations)
# Check initialized application.
_check_app_works(all_combinations)
def test_build_simplified():
"""
Creates application using declarative with automatic control of used components.
Simplified example.
"""
# Create single module application
app_def = DeclarativeApp(
DeclarativeModule(
# Scan for values and factories in pointed modules
scan_values(mod_config),
scan_factories(mod_abstract, mod_impl, mod_plugins),
),
# Add argument aggregation of `DataProvider` collection
agg_checks=[type_check(DataProvider)],
)
# This operation builds application instance:
# - solves module dependency graph
# - solves in module dependency injection sub-graphs
# - initializes factories dependency injection chain
# - calls factories marked by `bootstrap` option
instance = app_def.build_instance()
# This operation creates/gets `AllCombinations` provided
# by automatic dependency injection mechanism.
(all_combinations,) = instance.values_by_type(mod_abstract.AllCombinations)
# Check initialized application.
_check_app_works(all_combinations)
def test_build_globals():
"""
Creates application using declarative with automatic control of used components.
Uses global flag and reexport in modules.
"""
# Create application.
# NOTE: Modules with `global_=True` will be imported automatically
# by other non global related modules.
# NOTE: Reexport flag will take all imported module exports
# and appends to exports in current module.
# Works like exported elements forwarding.
app_def = DeclarativeApp(
DeclarativeModule(
scan_values(mod_config),
global_=True,
),
DeclarativeModule(
scan_factories(mod_plugins),
name="plugins",
),
DeclarativeModule(
scan_factories(mod_impl),
imports=[NameModuleImport("plugins", reexport=True)],
global_=True,
),
DeclarativeModule(
scan_factories(mod_abstract),
),
agg_checks=[type_check(DataProvider)],
)
# This operation builds application instance and gets `AllCombinations` object
instance = app_def.build_instance()
(all_combinations,) = instance.values_by_type(mod_abstract.AllCombinations)
# Check initialized application.
_check_app_works(all_combinations)