Coverage for onionizer/tests/test_onionizer.py: 91%
189 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-04-06 11:39 +0200
« prev ^ index » next coverage.py v7.2.2, created at 2023-04-06 11:39 +0200
1import contextlib
3import pytest as pytest
5import onionizer
8@pytest.fixture
9def func_that_adds():
10 def func(x: int, y: int) -> int:
11 return x + y
13 return func
16def test_mutate_arguments(func_that_adds):
17 def middleware1(x: int, y: int) -> onionizer.OnionGenerator[int]:
18 result = yield (x + 1, y + 1), {}
19 return result
21 def middleware2(x: int, y: int) -> onionizer.OnionGenerator[int]:
22 result = yield (x, y + 1), {}
23 return result
25 wrapped_func = onionizer.wrap(func_that_adds, [middleware1, middleware2])
26 result = wrapped_func(0, 0)
28 assert result == 3
31def test_mutate_output(func_that_adds):
32 def middleware1(x: int, y: int) -> onionizer.OnionGenerator[int]:
33 result = yield onionizer.UNCHANGED
34 return result + 1
36 def middleware2(x: int, y: int) -> onionizer.OnionGenerator[int]:
37 result = yield onionizer.UNCHANGED
38 return result * 2
40 wrapped_func = onionizer.wrap(func_that_adds, [middleware1, middleware2])
41 result = wrapped_func(0, 0)
42 assert result == 1
44 wrapped_func = onionizer.wrap(func_that_adds, [middleware2, middleware1])
45 result = wrapped_func(0, 0)
46 assert result == 2
49def test_pos_only(func_that_adds):
50 def middleware1(x: int, y: int):
51 result = yield onionizer.PositionalArgs(x + 1, y)
52 return result
54 def middleware2(x: int, y: int):
55 result = yield onionizer.PositionalArgs(x, y + 1)
56 return result
58 wrapped_func = onionizer.wrap(func_that_adds, [middleware1, middleware2])
59 result = wrapped_func(0, 0)
60 assert result == 2
63def test_kw_only(func_that_adds):
64 def middleware1(x: int, y: int):
65 result = yield onionizer.KeywordArgs({"x": x + 1, "y": y})
66 return result
68 def middleware2(x: int, y: int):
69 result = yield onionizer.KeywordArgs({"x": x, "y": y + 1})
70 return result
72 wrapped_func = onionizer.wrap(func_that_adds, [middleware1, middleware2])
73 result = wrapped_func(x=0, y=0)
74 assert result == 2
77def test_preprocessor(func_that_adds):
78 @onionizer.preprocessor
79 def midd1(x: int, y: int):
80 return onionizer.PositionalArgs(x + 1, y + 1)
82 assert midd1.__name__ == "midd1"
84 wrapped_func = onionizer.wrap(func_that_adds, [midd1])
85 result = wrapped_func(x=0, y=0)
86 assert result == 2
89def test_postprocessor(func_that_adds):
90 @onionizer.postprocessor
91 def midd1(val: int):
92 return val ** 2
94 assert midd1.__name__ == "midd1"
96 wrapped_func = onionizer.wrap(func_that_adds, [midd1])
97 result = wrapped_func(x=1, y=1)
98 assert result == 4
101def test_postprocessor_with_multiple_values():
102 def dummy_func(x, y):
103 return x, y
105 @onionizer.postprocessor
106 def midd1(couple: tuple):
107 c1, c2 = couple
108 return c2, c1
110 wrapped_func = onionizer.wrap(dummy_func, [midd1])
111 result = wrapped_func(x=1, y=2)
112 assert result == (2, 1)
115def test_support_for_context_managers():
116 def func(x, y):
117 return x / y
119 @onionizer.postprocessor
120 def midd1(val):
121 return val + 1
123 @contextlib.contextmanager
124 def exception_catcher():
125 try:
126 yield
127 except Exception as e:
128 raise RuntimeError("Exception caught") from e
130 wrapped_func = onionizer.wrap(func, [exception_catcher()])
131 with pytest.raises(RuntimeError) as e:
132 wrapped_func(x=1, y=0)
133 assert str(e.value) == "Exception caught"
135 another_wrapped_func = onionizer.wrap(func, [exception_catcher(), midd1])
136 assert another_wrapped_func(x=1, y=1) == 2
139def test_decorator():
140 def middleware1(x, y):
141 result = yield onionizer.KeywordArgs({"x": x + 1, "y": y})
142 return result
144 def middleware2(x, y):
145 result = yield onionizer.KeywordArgs({"x": x, "y": y + 1})
146 return result
148 @onionizer.decorate([middleware1, middleware2])
149 def func(x, y):
150 return x + y
152 @onionizer.decorate(middleware1)
153 def func2(x, y):
154 return x + y
156 result = func(x=0, y=0)
157 assert result == 2
159 result2 = func2(x=0, y=0)
160 assert result2 == 1
163def test_incorrect_decorator():
164 with pytest.raises(TypeError) as e:
166 @onionizer.decorate(1)
167 def func2(x, y):
168 return x + y
170 assert (
171 str(e.value) == "middlewares must be a list of coroutines or a single coroutine"
172 )
175def test_as_decorator():
176 @onionizer.as_decorator
177 def middleware1(x, y):
178 result = yield onionizer.KeywordArgs({"x": x + 1, "y": y})
179 return result
181 @onionizer.as_decorator
182 def middleware2(x, y):
183 result = yield onionizer.KeywordArgs({"x": x, "y": y + 1})
184 return result
186 @middleware1
187 @middleware2
188 def func(x, y):
189 return x + y
191 result = func(x=0, y=0)
192 assert result == 2
195def test_uncompatible_signature(func_that_adds):
196 def middleware1(*args):
197 result = yield onionizer.UNCHANGED
198 return result
200 with pytest.raises(ValueError):
201 onionizer.wrap(func_that_adds, middlewares=[middleware1])
204def test_uncompatible_signature_but_disable_sigcheck(func_that_adds):
205 def middleware1(*args):
206 result = yield onionizer.UNCHANGED
207 return result
209 onionizer.wrap(func_that_adds, middlewares=[middleware1], sigcheck=False)
210 assert True
213def test_unyielding_middleware(func_that_adds):
214 def middleware1(*args):
215 return "hello"
217 f2 = onionizer.wrap(
218 func_that_adds, middlewares=[middleware1], sigcheck=False
219 )
220 with pytest.raises(TypeError) as e:
221 f2(1, 2)
222 assert (
223 str(e.value) == "Middleware middleware1 is not a coroutine. "
224 "Did you forget to use a yield statement?"
225 )
228def test_tooyielding_middleware(func_that_adds):
229 def middleware1(*args):
230 yield onionizer.UNCHANGED
231 yield onionizer.UNCHANGED
233 f2 = onionizer.wrap(
234 func_that_adds, middlewares=[middleware1], sigcheck=False
235 )
236 with pytest.raises(RuntimeError) as e:
237 f2(1, 2)
238 assert (
239 str(e.value)
240 == "Generator did not exhaust. Your function should yield exactly once."
241 )
244@pytest.mark.skip(reason="demo")
245def test_incorrects_managers(func_that_adds):
246 class MyManager:
247 def __enter__(self):
248 return self
250 f = onionizer.wrap(func_that_adds, middlewares=[MyManager()], sigcheck=False)
251 with pytest.raises(TypeError):
252 f(1, 2)
253 f2 = onionizer.wrap(
254 func_that_adds, middlewares=[MyManager()], sigcheck=False
255 )
256 with pytest.raises(TypeError):
257 f2(1, 2)
260def test_incorrect_func():
261 with pytest.raises(TypeError) as e:
262 onionizer.wrap(1, [])
263 assert str(e.value) == "func must be callable"
266def test_incorrect_midlist(func_that_adds):
267 def middleware1(*args):
268 result = yield onionizer.UNCHANGED
269 return result
271 with pytest.raises(TypeError) as e:
272 onionizer.wrap(func_that_adds, middlewares=middleware1)
273 assert str(e.value) == "middlewares must be a list of coroutines"
276def test_incorrect_yields(func_that_adds):
277 def middleware1(x: int, y: int):
278 yield 2
279 return 1
281 with pytest.raises(TypeError) as e:
282 onionizer.wrap(func_that_adds, middlewares=[middleware1])(1, 2)
283 assert (
284 str(e.value) == "arguments must be a tuple of length 2, "
285 "maybe use onionizer.PositionalArgs or onionizer.MixedArgs instead"
286 )