executiontimer 1.0.2__tar.gz → 1.0.3__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.
- {executiontimer-1.0.2 → executiontimer-1.0.3}/.gitignore +1 -0
- {executiontimer-1.0.2 → executiontimer-1.0.3}/CHANGELOG.md +24 -1
- {executiontimer-1.0.2 → executiontimer-1.0.3}/CONTRIBUTING.md +19 -3
- executiontimer-1.0.3/PKG-INFO +117 -0
- executiontimer-1.0.3/README.md +86 -0
- executiontimer-1.0.3/benchmarks/README.md +41 -0
- executiontimer-1.0.3/docs/_static/icon-dark.svg +34 -0
- executiontimer-1.0.3/docs/_static/icon-light.svg +34 -0
- executiontimer-1.0.3/docs/api.md +72 -0
- executiontimer-1.0.3/docs/changelog.md +2 -0
- executiontimer-1.0.3/docs/conf.py +90 -0
- executiontimer-1.0.3/docs/contributing.md +2 -0
- executiontimer-1.0.3/docs/getting-started.md +162 -0
- executiontimer-1.0.3/docs/guide/categories.md +90 -0
- executiontimer-1.0.3/docs/guide/concurrency.md +132 -0
- executiontimer-1.0.3/docs/guide/counters.md +70 -0
- executiontimer-1.0.3/docs/guide/long-running.md +61 -0
- executiontimer-1.0.3/docs/guide/overhead.md +36 -0
- executiontimer-1.0.3/docs/guide/reports.md +177 -0
- executiontimer-1.0.3/docs/guide/timing-code.md +170 -0
- executiontimer-1.0.3/docs/index.md +94 -0
- {executiontimer-1.0.2 → executiontimer-1.0.3}/pyproject.toml +9 -1
- {executiontimer-1.0.2 → executiontimer-1.0.3}/src/execution_timer/__init__.py +1 -1
- {executiontimer-1.0.2 → executiontimer-1.0.3}/src/execution_timer/_timer.py +139 -33
- executiontimer-1.0.3/tests/docs_examples_test.py +41 -0
- executiontimer-1.0.2/PKG-INFO +0 -333
- executiontimer-1.0.2/README.md +0 -302
- executiontimer-1.0.2/benchmarks/README.md +0 -40
- {executiontimer-1.0.2 → executiontimer-1.0.3}/LICENSE +0 -0
- {executiontimer-1.0.2 → executiontimer-1.0.3}/benchmarks/overhead.py +0 -0
- {executiontimer-1.0.2 → executiontimer-1.0.3}/src/execution_timer/py.typed +0 -0
- {executiontimer-1.0.2 → executiontimer-1.0.3}/tests/execution_timer_test.py +0 -0
|
@@ -7,6 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.0.3] - 2026-09-30
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Entering and exiting a section is 20–25% faster, about 0.25 µs less per section on
|
|
15
|
+
CPython 3.14. Each active section's state is now a plain tuple rather than a named
|
|
16
|
+
tuple, whose constructor cost more than the rest of section entry. Behaviour is
|
|
17
|
+
unchanged.
|
|
18
|
+
|
|
19
|
+
### Documentation
|
|
20
|
+
|
|
21
|
+
- A documentation site at <https://seba2390.github.io/ExecutionTimer/>, with a getting
|
|
22
|
+
started guide, a user guide and an API reference generated from the docstrings. It is
|
|
23
|
+
built with Sphinx and deployed to GitHub Pages whenever `main` changes. The package's
|
|
24
|
+
`Documentation` link points to it from this release on.
|
|
25
|
+
- The README is shorter and links to the site for details.
|
|
26
|
+
- Public functions and types have full docstrings, with parameters, return values and
|
|
27
|
+
exceptions.
|
|
28
|
+
- The Python examples in the README and the documentation run as part of the test suite,
|
|
29
|
+
and CI builds the site on every pull request, failing on any warning.
|
|
30
|
+
- Refresh the overhead benchmark, comparing 0.1.0, 1.0.2 and 1.0.3.
|
|
31
|
+
|
|
10
32
|
## [1.0.2] - 2026-09-30
|
|
11
33
|
|
|
12
34
|
### Fixed
|
|
@@ -172,7 +194,8 @@ First public release on PyPI.
|
|
|
172
194
|
`py.typed` marker so type checkers use the inline annotations.
|
|
173
195
|
- `__version__` attribute on the package.
|
|
174
196
|
|
|
175
|
-
[Unreleased]: https://github.com/seba2390/ExecutionTimer/compare/v1.0.
|
|
197
|
+
[Unreleased]: https://github.com/seba2390/ExecutionTimer/compare/v1.0.3...HEAD
|
|
198
|
+
[1.0.3]: https://github.com/seba2390/ExecutionTimer/compare/v1.0.2...v1.0.3
|
|
176
199
|
[1.0.2]: https://github.com/seba2390/ExecutionTimer/compare/v1.0.1...v1.0.2
|
|
177
200
|
[1.0.1]: https://github.com/seba2390/ExecutionTimer/compare/v1.0.0...v1.0.1
|
|
178
201
|
[1.0.0]: https://github.com/seba2390/ExecutionTimer/compare/v0.2.0...v1.0.0
|
|
@@ -41,16 +41,32 @@ machine and Python version, without coverage instrumentation:
|
|
|
41
41
|
uv run python benchmarks/overhead.py --number 100000 --repeat 9
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
See [benchmarks/README.md](benchmarks/README.md) for methodology and reference results.
|
|
44
|
+
See [benchmarks/README.md](https://github.com/seba2390/ExecutionTimer/blob/main/benchmarks/README.md) for methodology and reference results.
|
|
45
45
|
Timing results are advisory rather than CI pass/fail thresholds.
|
|
46
46
|
|
|
47
|
+
## Documentation
|
|
48
|
+
|
|
49
|
+
The documentation site is built with [Sphinx](https://www.sphinx-doc.org/) from the
|
|
50
|
+
Markdown pages in `docs/` and the docstrings in `src/`. To build and preview it:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uv run --group docs sphinx-build -M html docs docs/_build -W --keep-going -n
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Then open `docs/_build/html/index.html`. CI builds the site on every pull request and fails
|
|
57
|
+
on any warning, such as a broken cross-reference. Changes merged into `main` are published
|
|
58
|
+
to [GitHub Pages](https://seba2390.github.io/ExecutionTimer/) automatically.
|
|
59
|
+
|
|
60
|
+
The Python examples in `docs/` and `README.md` run as part of the test suite, so keep them
|
|
61
|
+
self-contained and runnable.
|
|
62
|
+
|
|
47
63
|
## Guidelines
|
|
48
64
|
|
|
49
65
|
- Tests exercise the **public API** only — import from `execution_timer`, not
|
|
50
66
|
`execution_timer._timer`. This keeps internals free to change.
|
|
51
67
|
- Every behaviour change needs a test that fails before the fix and passes after it.
|
|
52
68
|
- Public functions carry type annotations and a one-line docstring.
|
|
53
|
-
- Add an entry under `## [Unreleased]` in [CHANGELOG.md](CHANGELOG.md).
|
|
69
|
+
- Add an entry under `## [Unreleased]` in [CHANGELOG.md](https://github.com/seba2390/ExecutionTimer/blob/main/CHANGELOG.md).
|
|
54
70
|
|
|
55
71
|
## Releasing
|
|
56
72
|
|
|
@@ -68,7 +84,7 @@ Maintainers only:
|
|
|
68
84
|
5. Publish a GitHub release tagged `vX.Y.Z`, targeting the merged commit on `main`.
|
|
69
85
|
Use that version's changelog entries as release notes.
|
|
70
86
|
|
|
71
|
-
The [Publish to PyPI workflow](.github/workflows/publish.yml) runs when a GitHub release
|
|
87
|
+
The [Publish to PyPI workflow](https://github.com/seba2390/ExecutionTimer/blob/main/.github/workflows/publish.yml) runs when a GitHub release
|
|
72
88
|
is **published**. Pushing to `main`, pushing a tag alone, or saving a draft release does
|
|
73
89
|
not trigger it. The workflow builds and validates the distributions, checks that the tag
|
|
74
90
|
matches `__version__`, and uploads them to PyPI via Trusted Publishing. No manual
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: executiontimer
|
|
3
|
+
Version: 1.0.3
|
|
4
|
+
Summary: Hierarchical execution timing with user-defined categories.
|
|
5
|
+
Project-URL: Homepage, https://github.com/seba2390/ExecutionTimer
|
|
6
|
+
Project-URL: Documentation, https://seba2390.github.io/ExecutionTimer/
|
|
7
|
+
Project-URL: Repository, https://github.com/seba2390/ExecutionTimer
|
|
8
|
+
Project-URL: Issues, https://github.com/seba2390/ExecutionTimer/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/seba2390/ExecutionTimer/blob/main/CHANGELOG.md
|
|
10
|
+
Author: Sebastian Yde Madsen
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: benchmark,context-manager,decorator,execution-time,instrumentation,performance,profiling,timing
|
|
14
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Programming Language :: Python :: Free Threading :: 3 - Stable
|
|
24
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
25
|
+
Classifier: Topic :: Software Development
|
|
26
|
+
Classifier: Topic :: Software Development :: Testing
|
|
27
|
+
Classifier: Topic :: System :: Benchmark
|
|
28
|
+
Classifier: Typing :: Typed
|
|
29
|
+
Requires-Python: >=3.11
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
<p align="center">
|
|
33
|
+
<picture>
|
|
34
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/seba2390/ExecutionTimer/main/assets/logo-dark.svg">
|
|
35
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/seba2390/ExecutionTimer/main/assets/logo-light.svg">
|
|
36
|
+
<img src="https://raw.githubusercontent.com/seba2390/ExecutionTimer/main/assets/logo-light.svg" alt="executiontimer" width="520">
|
|
37
|
+
</picture>
|
|
38
|
+
</p>
|
|
39
|
+
|
|
40
|
+
<p align="center">
|
|
41
|
+
<a href="https://pypi.org/project/executiontimer/"><img src="https://img.shields.io/pypi/v/executiontimer?color=blue" alt="PyPI version"></a>
|
|
42
|
+
<a href="https://pypi.org/project/executiontimer/"><img src="https://img.shields.io/pypi/pyversions/executiontimer" alt="Python versions"></a>
|
|
43
|
+
<a href="https://github.com/seba2390/ExecutionTimer/actions/workflows/ci.yml"><img src="https://github.com/seba2390/ExecutionTimer/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
44
|
+
<a href="https://github.com/seba2390/ExecutionTimer/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="License"></a>
|
|
45
|
+
<a href="https://seba2390.github.io/ExecutionTimer/"><img src="https://img.shields.io/badge/docs-GitHub%20Pages-4F46E5" alt="Documentation"></a>
|
|
46
|
+
</p>
|
|
47
|
+
|
|
48
|
+
Time named sections of your code with a `with` block or a decorator. Sections nested inside
|
|
49
|
+
each other form a tree, so you see where the time actually went, not just one number at the
|
|
50
|
+
end.
|
|
51
|
+
|
|
52
|
+
Zero dependencies. Fully typed. Works with threads and `asyncio`.
|
|
53
|
+
|
|
54
|
+
## Documentation
|
|
55
|
+
[seba2390.github.io/ExecutionTimer](https://seba2390.github.io/ExecutionTimer/)
|
|
56
|
+
|
|
57
|
+
## Installation
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pip install executiontimer
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Requires Python 3.11+. The install name is `executiontimer`; the import name is
|
|
64
|
+
`execution_timer`.
|
|
65
|
+
|
|
66
|
+
## Quick start
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
import time
|
|
70
|
+
|
|
71
|
+
from execution_timer import TimerContext, get_execution_times_report
|
|
72
|
+
|
|
73
|
+
with TimerContext("load_data"):
|
|
74
|
+
time.sleep(0.12)
|
|
75
|
+
|
|
76
|
+
with TimerContext("solve"):
|
|
77
|
+
for i in range(3):
|
|
78
|
+
with TimerContext("step", category="gpu", counter=i):
|
|
79
|
+
time.sleep(0.05)
|
|
80
|
+
with TimerContext("postprocess", category="cpu"):
|
|
81
|
+
time.sleep(0.03)
|
|
82
|
+
|
|
83
|
+
print(get_execution_times_report())
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```text
|
|
87
|
+
Total time: 0.3156 s.
|
|
88
|
+
|
|
89
|
+
load_data: 0.1219 s (38.62%)
|
|
90
|
+
solve: 0.1937 s (61.38%)
|
|
91
|
+
.. step: 0.1585 s (50.24%)
|
|
92
|
+
.. postprocess: 0.0350 s (11.10%)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`TimerContext` also works as a decorator, including on `async def` functions:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
@TimerContext("preprocess")
|
|
99
|
+
def preprocess(rows: list[str]) -> list[str]:
|
|
100
|
+
return [row.strip() for row in rows]
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Learn more
|
|
104
|
+
|
|
105
|
+
- [Getting started](https://seba2390.github.io/ExecutionTimer/getting-started.html)
|
|
106
|
+
- User guide: [timing code](https://seba2390.github.io/ExecutionTimer/guide/timing-code.html),
|
|
107
|
+
[counters](https://seba2390.github.io/ExecutionTimer/guide/counters.html),
|
|
108
|
+
[categories](https://seba2390.github.io/ExecutionTimer/guide/categories.html),
|
|
109
|
+
[reports and JSON export](https://seba2390.github.io/ExecutionTimer/guide/reports.html),
|
|
110
|
+
[threads, asyncio and generators](https://seba2390.github.io/ExecutionTimer/guide/concurrency.html)
|
|
111
|
+
- [API reference](https://seba2390.github.io/ExecutionTimer/api.html)
|
|
112
|
+
- [Changelog](https://github.com/seba2390/ExecutionTimer/blob/main/CHANGELOG.md) and
|
|
113
|
+
[contributing guide](https://github.com/seba2390/ExecutionTimer/blob/main/CONTRIBUTING.md)
|
|
114
|
+
|
|
115
|
+
## License
|
|
116
|
+
|
|
117
|
+
MIT — see [LICENSE](https://github.com/seba2390/ExecutionTimer/blob/main/LICENSE).
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/seba2390/ExecutionTimer/main/assets/logo-dark.svg">
|
|
4
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/seba2390/ExecutionTimer/main/assets/logo-light.svg">
|
|
5
|
+
<img src="https://raw.githubusercontent.com/seba2390/ExecutionTimer/main/assets/logo-light.svg" alt="executiontimer" width="520">
|
|
6
|
+
</picture>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://pypi.org/project/executiontimer/"><img src="https://img.shields.io/pypi/v/executiontimer?color=blue" alt="PyPI version"></a>
|
|
11
|
+
<a href="https://pypi.org/project/executiontimer/"><img src="https://img.shields.io/pypi/pyversions/executiontimer" alt="Python versions"></a>
|
|
12
|
+
<a href="https://github.com/seba2390/ExecutionTimer/actions/workflows/ci.yml"><img src="https://github.com/seba2390/ExecutionTimer/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
13
|
+
<a href="https://github.com/seba2390/ExecutionTimer/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="License"></a>
|
|
14
|
+
<a href="https://seba2390.github.io/ExecutionTimer/"><img src="https://img.shields.io/badge/docs-GitHub%20Pages-4F46E5" alt="Documentation"></a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
Time named sections of your code with a `with` block or a decorator. Sections nested inside
|
|
18
|
+
each other form a tree, so you see where the time actually went, not just one number at the
|
|
19
|
+
end.
|
|
20
|
+
|
|
21
|
+
Zero dependencies. Fully typed. Works with threads and `asyncio`.
|
|
22
|
+
|
|
23
|
+
## Documentation
|
|
24
|
+
[seba2390.github.io/ExecutionTimer](https://seba2390.github.io/ExecutionTimer/)
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install executiontimer
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Requires Python 3.11+. The install name is `executiontimer`; the import name is
|
|
33
|
+
`execution_timer`.
|
|
34
|
+
|
|
35
|
+
## Quick start
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
import time
|
|
39
|
+
|
|
40
|
+
from execution_timer import TimerContext, get_execution_times_report
|
|
41
|
+
|
|
42
|
+
with TimerContext("load_data"):
|
|
43
|
+
time.sleep(0.12)
|
|
44
|
+
|
|
45
|
+
with TimerContext("solve"):
|
|
46
|
+
for i in range(3):
|
|
47
|
+
with TimerContext("step", category="gpu", counter=i):
|
|
48
|
+
time.sleep(0.05)
|
|
49
|
+
with TimerContext("postprocess", category="cpu"):
|
|
50
|
+
time.sleep(0.03)
|
|
51
|
+
|
|
52
|
+
print(get_execution_times_report())
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
Total time: 0.3156 s.
|
|
57
|
+
|
|
58
|
+
load_data: 0.1219 s (38.62%)
|
|
59
|
+
solve: 0.1937 s (61.38%)
|
|
60
|
+
.. step: 0.1585 s (50.24%)
|
|
61
|
+
.. postprocess: 0.0350 s (11.10%)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`TimerContext` also works as a decorator, including on `async def` functions:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
@TimerContext("preprocess")
|
|
68
|
+
def preprocess(rows: list[str]) -> list[str]:
|
|
69
|
+
return [row.strip() for row in rows]
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Learn more
|
|
73
|
+
|
|
74
|
+
- [Getting started](https://seba2390.github.io/ExecutionTimer/getting-started.html)
|
|
75
|
+
- User guide: [timing code](https://seba2390.github.io/ExecutionTimer/guide/timing-code.html),
|
|
76
|
+
[counters](https://seba2390.github.io/ExecutionTimer/guide/counters.html),
|
|
77
|
+
[categories](https://seba2390.github.io/ExecutionTimer/guide/categories.html),
|
|
78
|
+
[reports and JSON export](https://seba2390.github.io/ExecutionTimer/guide/reports.html),
|
|
79
|
+
[threads, asyncio and generators](https://seba2390.github.io/ExecutionTimer/guide/concurrency.html)
|
|
80
|
+
- [API reference](https://seba2390.github.io/ExecutionTimer/api.html)
|
|
81
|
+
- [Changelog](https://github.com/seba2390/ExecutionTimer/blob/main/CHANGELOG.md) and
|
|
82
|
+
[contributing guide](https://github.com/seba2390/ExecutionTimer/blob/main/CONTRIBUTING.md)
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
|
|
86
|
+
MIT — see [LICENSE](https://github.com/seba2390/ExecutionTimer/blob/main/LICENSE).
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Overhead benchmarks
|
|
2
|
+
|
|
3
|
+
From a repository checkout, run:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
uv run python benchmarks/overhead.py --number 100000 --repeat 9
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
The script prints JSON with the Python version, platform, and median nanoseconds per
|
|
10
|
+
operation. Recording cases run `--number` operations per repeat. Reporting cases run
|
|
11
|
+
`max(1, number // 1000)` operations against 1,000 recorded counter variants with ten
|
|
12
|
+
categories. Async calls run in one event loop, so loop startup is excluded.
|
|
13
|
+
|
|
14
|
+
Compare the same interpreter and machine under similar load, without coverage or a
|
|
15
|
+
profiler enabled. These are microbenchmarks, not CI timing thresholds. The no-op bodies
|
|
16
|
+
make instrumentation costs visible; application speedups depend on the work being timed.
|
|
17
|
+
|
|
18
|
+
## Local comparison
|
|
19
|
+
|
|
20
|
+
Measured on macOS 26.6.2, ARM64, CPython 3.14.5, using 100,000 operations and nine repeats.
|
|
21
|
+
The baseline is commit `008494c` (version 0.1.0). All three versions ran the same script,
|
|
22
|
+
one after the other. Values below are microseconds per operation and include the benchmark
|
|
23
|
+
function call; plain calls cost approximately 0.02 µs and plain awaits 0.06 µs in every
|
|
24
|
+
run. The last column compares 1.0.3 with the baseline.
|
|
25
|
+
|
|
26
|
+
| Operation | 0.1.0 (µs) | 1.0.2 (µs) | 1.0.3 (µs) | Reduction |
|
|
27
|
+
| --- | ---: | ---: | ---: | ---: |
|
|
28
|
+
| New context | 1.604 | 1.116 | 0.877 | 45% |
|
|
29
|
+
| Reused context | 1.433 | 1.013 | 0.786 | 45% |
|
|
30
|
+
| Decorated call | 1.656 | 1.220 | 0.897 | 46% |
|
|
31
|
+
| Decorated await | 1.800 | 1.197 | 0.948 | 47% |
|
|
32
|
+
| Five nested contexts | 8.238 | 5.782 | 4.371 | 47% |
|
|
33
|
+
| Total time, 1,000 sections | 522.668 | 43.786 | 43.630 | 92% |
|
|
34
|
+
| JSON, 1,000 sections | 1,255.098 | 1,139.416 | 1,065.708 | 15% |
|
|
35
|
+
| Disabled logging, 1,000 sections | 530.408 | 0.100 | 0.100 | >99.9% |
|
|
36
|
+
|
|
37
|
+
Recording keeps each invocation's start time and cached path in a context-local frame,
|
|
38
|
+
stored as a plain tuple because a named tuple's constructor costs more than the rest of
|
|
39
|
+
entering a section. Decorators reuse their context instead of constructing one per call.
|
|
40
|
+
Total-time queries avoid copying and flattening entries, JSON exports share one snapshot,
|
|
41
|
+
and disabled logging returns before building a report.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="14 10 112 112" width="112" height="112" role="img" aria-label="executiontimer">
|
|
2
|
+
<title>executiontimer</title>
|
|
3
|
+
<defs>
|
|
4
|
+
<linearGradient id="ring1" x1="0" y1="0" x2="1" y2="1">
|
|
5
|
+
<stop offset="0%" stop-color="#818CF8"/>
|
|
6
|
+
<stop offset="100%" stop-color="#4F46E5"/>
|
|
7
|
+
</linearGradient>
|
|
8
|
+
<linearGradient id="ring2" x1="0" y1="0" x2="1" y2="1">
|
|
9
|
+
<stop offset="0%" stop-color="#C084FC"/>
|
|
10
|
+
<stop offset="100%" stop-color="#9333EA"/>
|
|
11
|
+
</linearGradient>
|
|
12
|
+
<linearGradient id="ring3" x1="0" y1="0" x2="1" y2="1">
|
|
13
|
+
<stop offset="0%" stop-color="#22D3EE"/>
|
|
14
|
+
<stop offset="100%" stop-color="#0891B2"/>
|
|
15
|
+
</linearGradient>
|
|
16
|
+
</defs>
|
|
17
|
+
|
|
18
|
+
<!-- Stopwatch stem and crown -->
|
|
19
|
+
<rect x="62" y="16" width="16" height="14" rx="4" fill="#94A3B8"/>
|
|
20
|
+
<rect x="55" y="10" width="30" height="9" rx="4.5" fill="#94A3B8"/>
|
|
21
|
+
|
|
22
|
+
<!-- Unfilled tracks -->
|
|
23
|
+
<circle cx="70" cy="76" r="42" fill="none" stroke="#334155" stroke-width="8"/>
|
|
24
|
+
<circle cx="70" cy="76" r="31" fill="none" stroke="#334155" stroke-width="8"/>
|
|
25
|
+
<circle cx="70" cy="76" r="20" fill="none" stroke="#334155" stroke-width="8"/>
|
|
26
|
+
|
|
27
|
+
<!-- Nested arcs: each ring is one level of the timing hierarchy -->
|
|
28
|
+
<g fill="none" stroke-width="8" stroke-linecap="round">
|
|
29
|
+
<path d="M 70 34 A 42 42 0 1 1 28.64 83.29" stroke="url(#ring1)"/>
|
|
30
|
+
<path d="M 70 45 A 31 31 0 1 1 64.62 106.53" stroke="url(#ring2)"/>
|
|
31
|
+
<path d="M 70 56 A 20 20 0 0 1 80 93.32" stroke="url(#ring3)"/>
|
|
32
|
+
</g>
|
|
33
|
+
|
|
34
|
+
</svg>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="14 10 112 112" width="112" height="112" role="img" aria-label="executiontimer">
|
|
2
|
+
<title>executiontimer</title>
|
|
3
|
+
<defs>
|
|
4
|
+
<linearGradient id="ring1" x1="0" y1="0" x2="1" y2="1">
|
|
5
|
+
<stop offset="0%" stop-color="#818CF8"/>
|
|
6
|
+
<stop offset="100%" stop-color="#4F46E5"/>
|
|
7
|
+
</linearGradient>
|
|
8
|
+
<linearGradient id="ring2" x1="0" y1="0" x2="1" y2="1">
|
|
9
|
+
<stop offset="0%" stop-color="#C084FC"/>
|
|
10
|
+
<stop offset="100%" stop-color="#9333EA"/>
|
|
11
|
+
</linearGradient>
|
|
12
|
+
<linearGradient id="ring3" x1="0" y1="0" x2="1" y2="1">
|
|
13
|
+
<stop offset="0%" stop-color="#22D3EE"/>
|
|
14
|
+
<stop offset="100%" stop-color="#0891B2"/>
|
|
15
|
+
</linearGradient>
|
|
16
|
+
</defs>
|
|
17
|
+
|
|
18
|
+
<!-- Stopwatch stem and crown -->
|
|
19
|
+
<rect x="62" y="16" width="16" height="14" rx="4" fill="#475569"/>
|
|
20
|
+
<rect x="55" y="10" width="30" height="9" rx="4.5" fill="#475569"/>
|
|
21
|
+
|
|
22
|
+
<!-- Unfilled tracks -->
|
|
23
|
+
<circle cx="70" cy="76" r="42" fill="none" stroke="#E2E8F0" stroke-width="8"/>
|
|
24
|
+
<circle cx="70" cy="76" r="31" fill="none" stroke="#E2E8F0" stroke-width="8"/>
|
|
25
|
+
<circle cx="70" cy="76" r="20" fill="none" stroke="#E2E8F0" stroke-width="8"/>
|
|
26
|
+
|
|
27
|
+
<!-- Nested arcs: each ring is one level of the timing hierarchy -->
|
|
28
|
+
<g fill="none" stroke-width="8" stroke-linecap="round">
|
|
29
|
+
<path d="M 70 34 A 42 42 0 1 1 28.64 83.29" stroke="url(#ring1)"/>
|
|
30
|
+
<path d="M 70 45 A 31 31 0 1 1 64.62 106.53" stroke="url(#ring2)"/>
|
|
31
|
+
<path d="M 70 56 A 20 20 0 0 1 80 93.32" stroke="url(#ring3)"/>
|
|
32
|
+
</g>
|
|
33
|
+
|
|
34
|
+
</svg>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# API reference
|
|
2
|
+
|
|
3
|
+
Everything below is importable from `execution_timer`. The public API follows
|
|
4
|
+
[semantic versioning](https://semver.org/): it only changes incompatibly in a new major
|
|
5
|
+
version.
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from execution_timer import TimerContext, get_execution_times_report
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Timing
|
|
12
|
+
|
|
13
|
+
```{eval-rst}
|
|
14
|
+
.. autoclass:: execution_timer.TimerContext
|
|
15
|
+
:special-members: __call__
|
|
16
|
+
|
|
17
|
+
.. py:data:: execution_timer.DEFAULT_CATEGORY
|
|
18
|
+
:type: str
|
|
19
|
+
:value: "default"
|
|
20
|
+
|
|
21
|
+
The category of sections created without one.
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Reports
|
|
25
|
+
|
|
26
|
+
```{eval-rst}
|
|
27
|
+
.. autofunction:: execution_timer.get_execution_times_report
|
|
28
|
+
.. autofunction:: execution_timer.log_execution_times
|
|
29
|
+
.. autofunction:: execution_timer.get_execution_timings
|
|
30
|
+
.. autofunction:: execution_timer.get_total_time
|
|
31
|
+
.. autofunction:: execution_timer.get_total_category_time
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## JSON export
|
|
35
|
+
|
|
36
|
+
```{eval-rst}
|
|
37
|
+
.. autofunction:: execution_timer.get_execution_times_json
|
|
38
|
+
.. autofunction:: execution_timer.save_execution_timings_json
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Managing timings and rules
|
|
42
|
+
|
|
43
|
+
```{eval-rst}
|
|
44
|
+
.. autofunction:: execution_timer.clear_execution_timings
|
|
45
|
+
.. autofunction:: execution_timer.register_forbidden_nesting
|
|
46
|
+
.. autofunction:: execution_timer.clear_forbidden_nesting
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Types
|
|
50
|
+
|
|
51
|
+
These are {class}`~typing.TypedDict` classes: at runtime the values are plain
|
|
52
|
+
dictionaries, and the classes exist for type checkers.
|
|
53
|
+
|
|
54
|
+
```{eval-rst}
|
|
55
|
+
.. autoclass:: execution_timer.TimingReport
|
|
56
|
+
:members:
|
|
57
|
+
|
|
58
|
+
.. autoclass:: execution_timer.TimingsPayload
|
|
59
|
+
:members:
|
|
60
|
+
|
|
61
|
+
.. autoclass:: execution_timer.SectionRecord
|
|
62
|
+
:members:
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Version
|
|
66
|
+
|
|
67
|
+
```{eval-rst}
|
|
68
|
+
.. py:data:: execution_timer.__version__
|
|
69
|
+
:type: str
|
|
70
|
+
|
|
71
|
+
The installed version, for example ``"1.0.2"``.
|
|
72
|
+
```
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Sphinx configuration for the executiontimer documentation."""
|
|
2
|
+
|
|
3
|
+
from datetime import date
|
|
4
|
+
|
|
5
|
+
import execution_timer
|
|
6
|
+
|
|
7
|
+
project = "executiontimer"
|
|
8
|
+
author = "Sebastian Yde Madsen"
|
|
9
|
+
copyright = f"{date.today().year}, {author}"
|
|
10
|
+
release = execution_timer.__version__
|
|
11
|
+
version = release
|
|
12
|
+
|
|
13
|
+
extensions = [
|
|
14
|
+
"myst_parser",
|
|
15
|
+
"sphinx.ext.autodoc",
|
|
16
|
+
"sphinx.ext.napoleon",
|
|
17
|
+
"sphinx.ext.intersphinx",
|
|
18
|
+
"sphinx.ext.viewcode",
|
|
19
|
+
"sphinx_copybutton",
|
|
20
|
+
"sphinx_design",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
exclude_patterns = ["_build"]
|
|
24
|
+
nitpicky = True
|
|
25
|
+
|
|
26
|
+
# Markdown pages
|
|
27
|
+
myst_enable_extensions = ["colon_fence", "deflist", "fieldlist"]
|
|
28
|
+
myst_heading_anchors = 3
|
|
29
|
+
|
|
30
|
+
# API reference
|
|
31
|
+
autodoc_member_order = "bysource"
|
|
32
|
+
autodoc_typehints = "description"
|
|
33
|
+
autodoc_typehints_description_target = "documented"
|
|
34
|
+
autodoc_preserve_defaults = True
|
|
35
|
+
napoleon_google_docstring = True
|
|
36
|
+
napoleon_numpy_docstring = False
|
|
37
|
+
napoleon_use_rtype = False
|
|
38
|
+
intersphinx_mapping = {"python": ("https://docs.python.org/3", None)}
|
|
39
|
+
|
|
40
|
+
# Type variables in decorator signatures have no page of their own.
|
|
41
|
+
nitpick_ignore_regex = [("py:class", r"(~|execution_timer\._timer\.)?[PRT]")]
|
|
42
|
+
|
|
43
|
+
# HTML output
|
|
44
|
+
# The GitHub mark from Primer Octicons (mark-github-16).
|
|
45
|
+
_GITHUB_MARK = (
|
|
46
|
+
'<svg fill="currentColor" viewBox="0 0 16 16"><path d="'
|
|
47
|
+
"M6.766 11.328c-2.063-.25-3.516-1.734-3.516-3.656 0-.781.281-1.625.75-2.188-.203-.515-.172-"
|
|
48
|
+
"1.609.063-2.062.625-.078 1.468.25 1.968.703.594-.187 1.219-.281 1.985-.281.765 0 1.39.094 "
|
|
49
|
+
"1.953.265.484-.437 1.344-.765 1.969-.687.218.422.25 1.515.046 2.047.5.593.766 1.39.766 2.2"
|
|
50
|
+
"03 0 1.922-1.453 3.375-3.547 3.64.531.344.89 1.094.89 1.954v1.625c0 .468.391.734.86.547C13"
|
|
51
|
+
".781 14.359 16 11.53 16 8.03 16 3.61 12.406 0 7.984 0 3.563 0 0 3.61 0 8.031a7.88 7.88 0 0"
|
|
52
|
+
" 0 5.172 7.422c.422.156.828-.125.828-.547v-1.25c-.219.094-.5.156-.75.156-1.031 0-1.64-.562"
|
|
53
|
+
"-2.078-1.609-.172-.422-.36-.672-.719-.719-.187-.015-.25-.093-.25-.187 0-.188.313-.328.625-"
|
|
54
|
+
".328.453 0 .844.281 1.25.86.313.452.64.655 1.031.655s.641-.14 1-.5c.266-.265.47-.5.657-.65"
|
|
55
|
+
"6"
|
|
56
|
+
'"/></svg>'
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
html_theme = "furo"
|
|
60
|
+
html_title = "executiontimer"
|
|
61
|
+
html_static_path = ["_static"]
|
|
62
|
+
html_favicon = "_static/icon-light.svg"
|
|
63
|
+
html_copy_source = False
|
|
64
|
+
html_show_sourcelink = False
|
|
65
|
+
html_theme_options = {
|
|
66
|
+
"light_logo": "icon-light.svg",
|
|
67
|
+
"dark_logo": "icon-dark.svg",
|
|
68
|
+
"source_repository": "https://github.com/seba2390/ExecutionTimer/",
|
|
69
|
+
"source_branch": "main",
|
|
70
|
+
"source_directory": "docs/",
|
|
71
|
+
"light_css_variables": {
|
|
72
|
+
"color-brand-primary": "#4F46E5",
|
|
73
|
+
"color-brand-content": "#4F46E5",
|
|
74
|
+
"color-brand-visited": "#4F46E5",
|
|
75
|
+
},
|
|
76
|
+
"dark_css_variables": {
|
|
77
|
+
"color-brand-primary": "#818CF8",
|
|
78
|
+
"color-brand-content": "#818CF8",
|
|
79
|
+
"color-brand-visited": "#818CF8",
|
|
80
|
+
},
|
|
81
|
+
"footer_icons": [
|
|
82
|
+
{
|
|
83
|
+
"name": "GitHub",
|
|
84
|
+
"url": "https://github.com/seba2390/ExecutionTimer",
|
|
85
|
+
"html": _GITHUB_MARK,
|
|
86
|
+
"class": "",
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
}
|
|
90
|
+
copybutton_exclude = ".linenos, .gp, .go"
|