wrapture 1.0.0.dev4__tar.gz → 1.0.0.dev7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {wrapture-1.0.0.dev4/src/wrapture.egg-info → wrapture-1.0.0.dev7}/PKG-INFO +13 -3
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/README.md +12 -2
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/__init__.py +4 -2
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/bindings.py +2 -1
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/events.py +11 -3
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/exceptions.py +2 -1
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/timeline.py +5 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7/src/wrapture.egg-info}/PKG-INFO +13 -3
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_bindings.py +18 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_events.py +25 -1
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_timeline.py +12 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/LICENSE +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/pyproject.toml +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/setup.cfg +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/__main__.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/asgi.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/attributes.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/behaviours.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/bootstrap.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/capture.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/collectors.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/config.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/eventlogs.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/export.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/iterators.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/lifecycle.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/observed.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/outputs.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/py.typed +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/pytest_plugin.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/scheduler.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/sinks.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/stacks.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/tools/__init__.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/tools/__main__.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/tools/convert.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/windows.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture/wsgi.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture.egg-info/SOURCES.txt +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture.egg-info/dependency_links.txt +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture.egg-info/entry_points.txt +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture.egg-info/not-zip-safe +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture.egg-info/requires.txt +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/src/wrapture.egg-info/top_level.txt +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_asgi.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_attribute_events.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_attributes.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_behaviours.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_bootstrap.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_capture.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_collectors.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_config.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_eventlogs.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_export.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_generator_events.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_iterators.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_jsonlines.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_observed.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_outputs.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_predicates.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_pytest_plugin.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_recording.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_runner.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_sink_library.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_sinks.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_stacks.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_targets.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_testing_patterns.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_threads.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_tools.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_version.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_windows.py +0 -0
- {wrapture-1.0.0.dev4 → wrapture-1.0.0.dev7}/tests/test_wsgi.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wrapture
|
|
3
|
-
Version: 1.0.0.
|
|
3
|
+
Version: 1.0.0.dev7
|
|
4
4
|
Summary: Monkey patch, test, and trace Python by attaching bindings to call sites, without modifying the code being observed. Built on wrapt.
|
|
5
5
|
Author-email: Graham Dumpleton <Graham.Dumpleton@gmail.com>
|
|
6
6
|
License-Expression: BSD-2-Clause
|
|
@@ -31,7 +31,7 @@ Dynamic: license-file
|
|
|
31
31
|
|
|
32
32
|
# wrapture
|
|
33
33
|
|
|
34
|
-
**
|
|
34
|
+
**Wrap anything, capture everything, change nothing.**
|
|
35
35
|
|
|
36
36
|
[](https://github.com/GrahamDumpleton/wrapture/actions/workflows/build-test-release.yml)
|
|
37
37
|
[](https://wrapture.readthedocs.io)
|
|
@@ -70,7 +70,10 @@ Start with the [getting started](https://wrapture.readthedocs.io/en/latest/getti
|
|
|
70
70
|
page: everything on it can be pasted into a Python interpreter. Coming
|
|
71
71
|
from `unittest.mock`? There is a
|
|
72
72
|
[comparison page](https://wrapture.readthedocs.io/en/latest/coming-from-mock.html)
|
|
73
|
-
mapping each mock idiom to its wrapture counterpart.
|
|
73
|
+
mapping each mock idiom to its wrapture counterpart. After that, the
|
|
74
|
+
worked examples, starting with
|
|
75
|
+
[testing code that calls external services](https://wrapture.readthedocs.io/en/latest/example-external-services.html),
|
|
76
|
+
each take one question you might arrive with and answer it end to end.
|
|
74
77
|
|
|
75
78
|
## Thirty seconds of it
|
|
76
79
|
|
|
@@ -163,6 +166,13 @@ testing assertion library, a tracing tool, or both at once.
|
|
|
163
166
|
- Python 3.12+
|
|
164
167
|
- [wrapt](https://github.com/GrahamDumpleton/wrapt) 2.4.0+
|
|
165
168
|
|
|
169
|
+
## Issues
|
|
170
|
+
|
|
171
|
+
Bug reports and feature requests go to the
|
|
172
|
+
[issue tracker](https://github.com/GrahamDumpleton/wrapture/issues).
|
|
173
|
+
Include the wrapture and Python versions and, where you can, a small
|
|
174
|
+
binding that reproduces the problem.
|
|
175
|
+
|
|
166
176
|
## License
|
|
167
177
|
|
|
168
178
|
BSD 2-Clause. See
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# wrapture
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**Wrap anything, capture everything, change nothing.**
|
|
4
4
|
|
|
5
5
|
[](https://github.com/GrahamDumpleton/wrapture/actions/workflows/build-test-release.yml)
|
|
6
6
|
[](https://wrapture.readthedocs.io)
|
|
@@ -39,7 +39,10 @@ Start with the [getting started](https://wrapture.readthedocs.io/en/latest/getti
|
|
|
39
39
|
page: everything on it can be pasted into a Python interpreter. Coming
|
|
40
40
|
from `unittest.mock`? There is a
|
|
41
41
|
[comparison page](https://wrapture.readthedocs.io/en/latest/coming-from-mock.html)
|
|
42
|
-
mapping each mock idiom to its wrapture counterpart.
|
|
42
|
+
mapping each mock idiom to its wrapture counterpart. After that, the
|
|
43
|
+
worked examples, starting with
|
|
44
|
+
[testing code that calls external services](https://wrapture.readthedocs.io/en/latest/example-external-services.html),
|
|
45
|
+
each take one question you might arrive with and answer it end to end.
|
|
43
46
|
|
|
44
47
|
## Thirty seconds of it
|
|
45
48
|
|
|
@@ -132,6 +135,13 @@ testing assertion library, a tracing tool, or both at once.
|
|
|
132
135
|
- Python 3.12+
|
|
133
136
|
- [wrapt](https://github.com/GrahamDumpleton/wrapt) 2.4.0+
|
|
134
137
|
|
|
138
|
+
## Issues
|
|
139
|
+
|
|
140
|
+
Bug reports and feature requests go to the
|
|
141
|
+
[issue tracker](https://github.com/GrahamDumpleton/wrapture/issues).
|
|
142
|
+
Include the wrapture and Python versions and, where you can, a small
|
|
143
|
+
binding that reproduces the problem.
|
|
144
|
+
|
|
135
145
|
## License
|
|
136
146
|
|
|
137
147
|
BSD 2-Clause. See
|
|
@@ -17,10 +17,10 @@ def _format_version(parts: tuple[str, ...]) -> str:
|
|
|
17
17
|
)
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
__version_info__ = ("1", "0", "0", "
|
|
20
|
+
__version_info__ = ("1", "0", "0", "dev7")
|
|
21
21
|
__version__ = _format_version(__version_info__)
|
|
22
22
|
|
|
23
|
-
from wrapt import MISSING
|
|
23
|
+
from wrapt import MISSING, register_post_import_hook, when_imported
|
|
24
24
|
|
|
25
25
|
from .asgi import (
|
|
26
26
|
ASGIMiddleware,
|
|
@@ -131,6 +131,8 @@ from .wsgi import (
|
|
|
131
131
|
|
|
132
132
|
__all__ = [
|
|
133
133
|
"MISSING",
|
|
134
|
+
"register_post_import_hook",
|
|
135
|
+
"when_imported",
|
|
134
136
|
"ASGIMiddleware",
|
|
135
137
|
"Aggregate",
|
|
136
138
|
"AlreadyAppliedError",
|
|
@@ -135,7 +135,8 @@ def _reject_deferred(target: Any) -> None:
|
|
|
135
135
|
f" wrapt's trailing `?` syntax. A deferred wrap registers a"
|
|
136
136
|
f" post-import hook and returns no handle, so a binding would"
|
|
137
137
|
f" have nothing to remove, suspend or query. Import the module"
|
|
138
|
-
f" first and bind against it
|
|
138
|
+
f" first and bind against it, or create the binding inside a"
|
|
139
|
+
f" `wrapture.when_imported` hook for that module."
|
|
139
140
|
)
|
|
140
141
|
|
|
141
142
|
|
|
@@ -181,9 +181,17 @@ def _format_time(seconds: float) -> str:
|
|
|
181
181
|
def _own_time(event: Event) -> float | None:
|
|
182
182
|
# The execution-time basis for self-time arithmetic. A generator's
|
|
183
183
|
# wall duration includes the consumer's time between yields, so its
|
|
184
|
-
# accumulated body time is the honest measure of the code itself
|
|
185
|
-
#
|
|
186
|
-
#
|
|
184
|
+
# accumulated body time is the honest measure of the code itself. A
|
|
185
|
+
# request has two phases of application code, the synchronous call
|
|
186
|
+
# and the body it then streams, and its own time is their sum, again
|
|
187
|
+
# leaving out the server's time between chunks. Everything else uses
|
|
188
|
+
# its duration. None when the event has not closed with a time.
|
|
189
|
+
|
|
190
|
+
if event.kind == "request" and event.body_duration is not None:
|
|
191
|
+
app_duration = event.data.get("app_duration")
|
|
192
|
+
if app_duration is None:
|
|
193
|
+
return event.duration
|
|
194
|
+
return float(app_duration) + event.body_duration
|
|
187
195
|
|
|
188
196
|
if event.body_duration is not None:
|
|
189
197
|
return event.body_duration
|
|
@@ -48,7 +48,8 @@ class NotImplementedYetError(NotImplementedError):
|
|
|
48
48
|
|
|
49
49
|
class DeferredTargetError(ValueError):
|
|
50
50
|
"""A string target used wrapt's trailing `?` deferred-patching syntax,
|
|
51
|
-
which is not supported. Import the module first and bind against it
|
|
51
|
+
which is not supported. Import the module first and bind against it,
|
|
52
|
+
or create the binding inside a `wrapture.when_imported` hook.
|
|
52
53
|
"""
|
|
53
54
|
|
|
54
55
|
|
|
@@ -246,8 +246,13 @@ class Tape(Sink):
|
|
|
246
246
|
def emit(event: Event) -> None:
|
|
247
247
|
injected = " (injected)" if event.injected else ""
|
|
248
248
|
|
|
249
|
+
# A get event's str() already carries its value, so only the
|
|
250
|
+
# injected mark is added to it.
|
|
251
|
+
|
|
249
252
|
if event.exception is not None:
|
|
250
253
|
marker = f" !! {type(event.exception).__name__}{injected}"
|
|
254
|
+
elif event.kind == "get":
|
|
255
|
+
marker = injected
|
|
251
256
|
elif event.result is not MISSING:
|
|
252
257
|
marker = f" -> {event.result!r}{injected}"
|
|
253
258
|
else:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wrapture
|
|
3
|
-
Version: 1.0.0.
|
|
3
|
+
Version: 1.0.0.dev7
|
|
4
4
|
Summary: Monkey patch, test, and trace Python by attaching bindings to call sites, without modifying the code being observed. Built on wrapt.
|
|
5
5
|
Author-email: Graham Dumpleton <Graham.Dumpleton@gmail.com>
|
|
6
6
|
License-Expression: BSD-2-Clause
|
|
@@ -31,7 +31,7 @@ Dynamic: license-file
|
|
|
31
31
|
|
|
32
32
|
# wrapture
|
|
33
33
|
|
|
34
|
-
**
|
|
34
|
+
**Wrap anything, capture everything, change nothing.**
|
|
35
35
|
|
|
36
36
|
[](https://github.com/GrahamDumpleton/wrapture/actions/workflows/build-test-release.yml)
|
|
37
37
|
[](https://wrapture.readthedocs.io)
|
|
@@ -70,7 +70,10 @@ Start with the [getting started](https://wrapture.readthedocs.io/en/latest/getti
|
|
|
70
70
|
page: everything on it can be pasted into a Python interpreter. Coming
|
|
71
71
|
from `unittest.mock`? There is a
|
|
72
72
|
[comparison page](https://wrapture.readthedocs.io/en/latest/coming-from-mock.html)
|
|
73
|
-
mapping each mock idiom to its wrapture counterpart.
|
|
73
|
+
mapping each mock idiom to its wrapture counterpart. After that, the
|
|
74
|
+
worked examples, starting with
|
|
75
|
+
[testing code that calls external services](https://wrapture.readthedocs.io/en/latest/example-external-services.html),
|
|
76
|
+
each take one question you might arrive with and answer it end to end.
|
|
74
77
|
|
|
75
78
|
## Thirty seconds of it
|
|
76
79
|
|
|
@@ -163,6 +166,13 @@ testing assertion library, a tracing tool, or both at once.
|
|
|
163
166
|
- Python 3.12+
|
|
164
167
|
- [wrapt](https://github.com/GrahamDumpleton/wrapt) 2.4.0+
|
|
165
168
|
|
|
169
|
+
## Issues
|
|
170
|
+
|
|
171
|
+
Bug reports and feature requests go to the
|
|
172
|
+
[issue tracker](https://github.com/GrahamDumpleton/wrapture/issues).
|
|
173
|
+
Include the wrapture and Python versions and, where you can, a small
|
|
174
|
+
binding that reproduces the problem.
|
|
175
|
+
|
|
166
176
|
## License
|
|
167
177
|
|
|
168
178
|
BSD 2-Clause. See
|
|
@@ -250,6 +250,24 @@ def test_deferred_target_error_is_a_value_error() -> None:
|
|
|
250
250
|
assert issubclass(DeferredTargetError, ValueError)
|
|
251
251
|
|
|
252
252
|
|
|
253
|
+
def test_deferred_target_error_points_at_when_imported() -> None:
|
|
254
|
+
with pytest.raises(DeferredTargetError, match="wrapture.when_imported"):
|
|
255
|
+
binding("mymodule?", "handler")
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def test_post_import_hook_helpers_are_reexported_from_wrapt() -> None:
|
|
259
|
+
# The supported route to patching a module before it is imported is
|
|
260
|
+
# a post-import hook, so wrapt's helpers are available under the
|
|
261
|
+
# wrapture name to save application code importing wrapt for them.
|
|
262
|
+
|
|
263
|
+
import wrapture
|
|
264
|
+
|
|
265
|
+
assert wrapture.when_imported is wrapt.when_imported
|
|
266
|
+
assert wrapture.register_post_import_hook is wrapt.register_post_import_hook
|
|
267
|
+
assert "when_imported" in wrapture.__all__
|
|
268
|
+
assert "register_post_import_hook" in wrapture.__all__
|
|
269
|
+
|
|
270
|
+
|
|
253
271
|
# ---------------------------------------------------------------------------
|
|
254
272
|
# modes and behaviour namespaces
|
|
255
273
|
# ---------------------------------------------------------------------------
|
|
@@ -9,10 +9,16 @@ import gc
|
|
|
9
9
|
import weakref
|
|
10
10
|
from typing import Any
|
|
11
11
|
|
|
12
|
+
import pytest
|
|
12
13
|
from wrapt import MISSING
|
|
13
14
|
|
|
14
15
|
from wrapture import Event
|
|
15
|
-
from wrapture.events import
|
|
16
|
+
from wrapture.events import (
|
|
17
|
+
_own_time,
|
|
18
|
+
_signature,
|
|
19
|
+
_signature_cache,
|
|
20
|
+
normalized_arguments,
|
|
21
|
+
)
|
|
16
22
|
|
|
17
23
|
|
|
18
24
|
def charge(amount: int, currency: str = "USD", *, retries: int = 3) -> None:
|
|
@@ -189,3 +195,21 @@ def test_cache_does_not_keep_the_function_alive() -> None:
|
|
|
189
195
|
|
|
190
196
|
gc.collect()
|
|
191
197
|
assert alive() is None
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def test_own_time_of_a_request_sums_both_application_phases() -> None:
|
|
201
|
+
# A request's own time is the synchronous call plus the body it
|
|
202
|
+
# produced, not the wall time that includes the server between chunks.
|
|
203
|
+
|
|
204
|
+
request = Event(kind="request", path="app:wsgi_app", duration=1.0)
|
|
205
|
+
request.body_duration = 0.2
|
|
206
|
+
request.data["app_duration"] = 0.3
|
|
207
|
+
|
|
208
|
+
assert _own_time(request) == pytest.approx(0.5)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def test_own_time_of_a_generator_is_its_body_time() -> None:
|
|
212
|
+
call = Event(kind="call", path="mod:gen", duration=1.0)
|
|
213
|
+
call.body_duration = 0.25
|
|
214
|
+
|
|
215
|
+
assert _own_time(call) == 0.25
|
|
@@ -354,6 +354,18 @@ def test_tree_renders_nesting_results_and_failures() -> None:
|
|
|
354
354
|
assert lines[2] == "Gateway.refund(amount=100) !! TimeoutError (injected)"
|
|
355
355
|
|
|
356
356
|
|
|
357
|
+
def test_tree_shows_a_get_event_value_once() -> None:
|
|
358
|
+
class Settings:
|
|
359
|
+
retries = 3
|
|
360
|
+
|
|
361
|
+
retries = binding(Settings, "retries")
|
|
362
|
+
|
|
363
|
+
with timeline(retries) as tape:
|
|
364
|
+
_ = Settings().retries
|
|
365
|
+
|
|
366
|
+
assert tape.tree() == "get Settings.retries -> 3"
|
|
367
|
+
|
|
368
|
+
|
|
357
369
|
def test_tree_of_an_empty_tape_is_empty() -> None:
|
|
358
370
|
with timeline() as tape:
|
|
359
371
|
pass
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|