executiontimer 1.0.1__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.
Files changed (32) hide show
  1. {executiontimer-1.0.1 → executiontimer-1.0.3}/.gitignore +1 -0
  2. {executiontimer-1.0.1 → executiontimer-1.0.3}/CHANGELOG.md +48 -1
  3. {executiontimer-1.0.1 → executiontimer-1.0.3}/CONTRIBUTING.md +24 -7
  4. executiontimer-1.0.3/PKG-INFO +117 -0
  5. executiontimer-1.0.3/README.md +86 -0
  6. executiontimer-1.0.3/benchmarks/README.md +41 -0
  7. executiontimer-1.0.3/docs/_static/icon-dark.svg +34 -0
  8. executiontimer-1.0.3/docs/_static/icon-light.svg +34 -0
  9. executiontimer-1.0.3/docs/api.md +72 -0
  10. executiontimer-1.0.3/docs/changelog.md +2 -0
  11. executiontimer-1.0.3/docs/conf.py +90 -0
  12. executiontimer-1.0.3/docs/contributing.md +2 -0
  13. executiontimer-1.0.3/docs/getting-started.md +162 -0
  14. executiontimer-1.0.3/docs/guide/categories.md +90 -0
  15. executiontimer-1.0.3/docs/guide/concurrency.md +132 -0
  16. executiontimer-1.0.3/docs/guide/counters.md +70 -0
  17. executiontimer-1.0.3/docs/guide/long-running.md +61 -0
  18. executiontimer-1.0.3/docs/guide/overhead.md +36 -0
  19. executiontimer-1.0.3/docs/guide/reports.md +177 -0
  20. executiontimer-1.0.3/docs/guide/timing-code.md +170 -0
  21. executiontimer-1.0.3/docs/index.md +94 -0
  22. {executiontimer-1.0.1 → executiontimer-1.0.3}/pyproject.toml +13 -2
  23. {executiontimer-1.0.1 → executiontimer-1.0.3}/src/execution_timer/__init__.py +1 -1
  24. {executiontimer-1.0.1 → executiontimer-1.0.3}/src/execution_timer/_timer.py +151 -34
  25. executiontimer-1.0.3/tests/docs_examples_test.py +41 -0
  26. {executiontimer-1.0.1 → executiontimer-1.0.3}/tests/execution_timer_test.py +89 -2
  27. executiontimer-1.0.1/PKG-INFO +0 -329
  28. executiontimer-1.0.1/README.md +0 -298
  29. executiontimer-1.0.1/benchmarks/README.md +0 -40
  30. {executiontimer-1.0.1 → executiontimer-1.0.3}/LICENSE +0 -0
  31. {executiontimer-1.0.1 → executiontimer-1.0.3}/benchmarks/overhead.py +0 -0
  32. {executiontimer-1.0.1 → executiontimer-1.0.3}/src/execution_timer/py.typed +0 -0
@@ -17,3 +17,4 @@ dist/
17
17
  .DS_Store
18
18
  .coverage
19
19
  htmlcov/
20
+ docs/_build/
@@ -7,6 +7,51 @@ 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
+
32
+ ## [1.0.2] - 2026-09-30
33
+
34
+ ### Fixed
35
+
36
+ - Decorating a function that returns a coroutine, typically because another decorator
37
+ sits between `TimerContext` and an `async def`, now times the `await`. Previously the
38
+ section recorded only the call that created the coroutine, a few microseconds however
39
+ long the coroutine ran. Other awaitables, such as futures and tasks, are returned
40
+ unchanged.
41
+
42
+ ### Changed
43
+
44
+ - The test suite fails on any warning, and CI requires 100% statement and branch coverage
45
+ rather than 95%.
46
+
47
+ ### Documentation
48
+
49
+ - Note that flattening also merges sections whose own names end in an integer, such as
50
+ `"row[1]"` and `"row[2]"`.
51
+ - The release steps in the contributing guide describe the pull-request flow that the
52
+ protected `main` branch requires.
53
+ - Refresh the overhead benchmark against version 1.0.2.
54
+
10
55
  ## [1.0.1] - 2026-09-30
11
56
 
12
57
  ### Fixed
@@ -149,7 +194,9 @@ First public release on PyPI.
149
194
  `py.typed` marker so type checkers use the inline annotations.
150
195
  - `__version__` attribute on the package.
151
196
 
152
- [Unreleased]: https://github.com/seba2390/ExecutionTimer/compare/v1.0.1...HEAD
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
199
+ [1.0.2]: https://github.com/seba2390/ExecutionTimer/compare/v1.0.1...v1.0.2
153
200
  [1.0.1]: https://github.com/seba2390/ExecutionTimer/compare/v1.0.0...v1.0.1
154
201
  [1.0.0]: https://github.com/seba2390/ExecutionTimer/compare/v0.2.0...v1.0.0
155
202
  [0.2.0]: https://github.com/seba2390/ExecutionTimer/compare/v0.1.1...v0.2.0
@@ -23,8 +23,8 @@ uv run ruff format
23
23
  uv run basedpyright
24
24
  ```
25
25
 
26
- All four must pass. Coverage is enforced at 95%; the current suite has 100% statement
27
- and branch coverage. Preserve coverage when adding or changing behavior.
26
+ All four must pass. The suite has 100% statement and branch coverage, and CI enforces it.
27
+ Any warning raised during the tests fails them.
28
28
 
29
29
  The test suite is also run against Python 3.11, 3.12, 3.13, 3.14 and free-threaded 3.14t
30
30
  on Linux, macOS and Windows.
@@ -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
 
@@ -63,11 +79,12 @@ Maintainers only:
63
79
  3. Run the checks above, build with `uv build`, and validate metadata with
64
80
  `uvx twine check --strict dist/*`. Use a clean output directory so old versions are
65
81
  not included in release artifacts.
66
- 4. Commit, then push to `main` and wait for CI to pass.
67
- 5. Publish a GitHub release tagged `vX.Y.Z`, targeting the validated commit on `main`.
82
+ 4. Commit on a branch and open a pull request. `main` is protected: it only accepts
83
+ pull requests whose `CI passed` check succeeds. Squash-merge once CI is green.
84
+ 5. Publish a GitHub release tagged `vX.Y.Z`, targeting the merged commit on `main`.
68
85
  Use that version's changelog entries as release notes.
69
86
 
70
- 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
71
88
  is **published**. Pushing to `main`, pushing a tag alone, or saving a draft release does
72
89
  not trigger it. The workflow builds and validates the distributions, checks that the tag
73
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,2 @@
1
+ ```{include} ../CHANGELOG.md
2
+ ```
@@ -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"
@@ -0,0 +1,2 @@
1
+ ```{include} ../CONTRIBUTING.md
2
+ ```