timerun 0.6.1__tar.gz → 0.7.0__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.
timerun-0.7.0/PKG-INFO ADDED
@@ -0,0 +1,163 @@
1
+ Metadata-Version: 2.4
2
+ Name: timerun
3
+ Version: 0.7.0
4
+ Summary: Structured wall-clock & CPU timing for Python (stdlib only). Zero dependencies, nanosecond precision, and ready for your logs, metrics, and OpenTelemetry.
5
+ Author-email: HH-MWB <h.hong@mail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://hh-mwb.github.io/timerun/
8
+ Project-URL: Documentation, https://hh-mwb.github.io/timerun/
9
+ Project-URL: Repository, https://github.com/HH-MWB/timerun
10
+ Project-URL: Issues, https://github.com/HH-MWB/timerun/issues
11
+ Project-URL: Changelog, https://github.com/HH-MWB/timerun/releases
12
+ Project-URL: PyPI, https://pypi.org/project/timerun
13
+ Keywords: time,timing,measurement,measurements,elapsed,stopwatch,timer,performance,latency,profiler,benchmarking,telemetry,opentelemetry,wall-clock,cpu-time,asyncio,fastapi
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Programming Language :: Python :: 3.15
25
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
+ Classifier: Topic :: System :: Monitoring
27
+ Requires-Python: >=3.10
28
+ Description-Content-Type: text/markdown
29
+ License-File: LICENSE
30
+ Dynamic: license-file
31
+
32
+ <p align="center">
33
+ <a href="https://github.com/HH-MWB/timerun">
34
+ <img src="https://github.com/user-attachments/assets/00f08873-3ee5-4ee4-a41f-f9eda37fc30d" alt="TimeRun">
35
+ </a>
36
+ </p>
37
+
38
+ <p align="center">
39
+ <strong>Structured, zero-dependency Python timing for humans and telemetry.</strong><br>
40
+ Instantly isolate wall-clock latency from CPU burn across sync, async, and generators.
41
+ </p>
42
+
43
+ <p align="center">
44
+ <a href="https://pypi.org/project/timerun/"><img alt="PyPI Version" src="https://img.shields.io/pypi/v/timerun.svg"></a>
45
+ <a href="https://codecov.io/gh/HH-MWB/timerun"><img alt="Coverage" src="https://codecov.io/gh/HH-MWB/timerun/branch/main/graph/badge.svg"></a>
46
+ <a href="https://github.com/HH-MWB/timerun/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/pypi/l/timerun.svg"></a>
47
+ <a href="https://pepy.tech/project/timerun"><img alt="Total Downloads" src="https://static.pepy.tech/badge/timerun"></a>
48
+ </p>
49
+
50
+ ---
51
+
52
+ ## Quickstart
53
+
54
+ ### 1. Measure Code Blocks (Wall vs. CPU)
55
+
56
+ Wrap any block in `with Timer() as m:` (or `async with Timer() as m:`). On exit, `m.wall_time` and `m.cpu_time` are immediately available:
57
+
58
+ ```python
59
+ import time
60
+ from timerun import Timer
61
+
62
+ with Timer() as m:
63
+ time.sleep(0.05) # Simulates network I/O or database wait
64
+ total = sum(i * i for i in range(100_000)) # Simulates CPU computation
65
+
66
+ print("Elapsed (Wall):", m.wall_time.timedelta) # e.g., 0:00:00.055120
67
+ print("Compute (CPU): ", m.cpu_time.timedelta) # e.g., 0:00:00.005110
68
+ ```
69
+
70
+ > **Why both?** If wall time is 2 seconds but CPU time is 5 milliseconds, your code spent 99.7% of its time waiting on I/O. If both are 2 seconds, you have a CPU bottleneck.
71
+
72
+ ### 2. Time Functions and Generators
73
+
74
+ Use `@Timer()` on sync or async functions. The wrapped function retains a bounded deque of measurements:
75
+
76
+ ```python
77
+ from timerun import Timer
78
+
79
+
80
+ @Timer(maxlen=100)
81
+ def process_batch(items):
82
+ return [x * 2 for x in items]
83
+
84
+
85
+ process_batch([1, 2, 3])
86
+
87
+ last = process_batch.measurements[-1]
88
+ print("Wall time:", last.wall_time.timedelta)
89
+ print("CPU time: ", last.cpu_time.timedelta)
90
+ ```
91
+
92
+ ### 3. Stream to Logs & Observability
93
+
94
+ Use `on_end` to ship timings directly to your logs, OpenTelemetry, Prometheus, or Datadog without adding vendor dependencies to your core logic:
95
+
96
+ ```python
97
+ import logging
98
+ from timerun import Timer
99
+
100
+ logger = logging.getLogger("app")
101
+
102
+ with Timer(
103
+ metadata={"service": "checkout", "user_id": "u-123"},
104
+ on_end=lambda m: logger.info(
105
+ "checkout_completed",
106
+ extra={
107
+ "wall_ms": m.wall_time.duration / 1e6,
108
+ "cpu_ms": m.cpu_time.duration / 1e6,
109
+ **m.metadata,
110
+ },
111
+ ),
112
+ ):
113
+ pass # your operation
114
+ ```
115
+
116
+ ## Installation
117
+
118
+ ```bash
119
+ pip install timerun
120
+ ```
121
+
122
+ *Requires Python 3.10+.*
123
+
124
+ ## Why TimeRun?
125
+
126
+ When code runs slowly, **is it waiting on network/disk I/O, or burning CPU?**
127
+
128
+ - `time.perf_counter()` only gives a raw float of elapsed wall time. Measuring CPU time requires manual `time.thread_time()` calls and boilerplate.
129
+ - Profilers (`cProfile`, `py-spy`) and APM agents (`Datadog`, `New Relic`) introduce binary dependencies, sampling overhead, or vendor lock-in.
130
+ - Naive timing patterns risk race conditions and crosstalk in concurrent `asyncio` tasks or multi-threaded workers.
131
+
132
+ TimeRun provides clean, structured timing with sub-microsecond overhead:
133
+
134
+ | Feature | Manual `time.perf_counter()` | Profilers (`cProfile`, `py-spy`) | APM Agents (`Datadog`, `New Relic`) | **TimeRun** |
135
+ | :--- | :---: | :---: | :---: | :---: |
136
+ | **Dependencies** | None | Extra tooling | Large binary agents | **Zero (stdlib only)** |
137
+ | **Wall vs. CPU Breakdown** | ❌ Manual boilerplate | ⚠️ Profiling overhead | ❌ Usually wall only | **✅ Built-in & precise** |
138
+ | **Structured Output** | ❌ Raw floats | ❌ Binary trace files | ⚠️ Proprietary format | **✅ Structured `Measurement`** |
139
+ | **Asyncio & Thread Safe** | ❌ Race condition risk | ⚠️ Global runtime cost | ✅ Handled by agent | **✅ Task & Thread isolated** |
140
+ | **Telemetry Hooks** | ❌ Build it yourself | ❌ Offline analysis only | ⚠️ Vendor locked | **✅ Agnostic (`on_end`)** |
141
+ | **Footprint** | 0 LOC | Heavy | Large background daemon | **Single file (~500 LOC)** |
142
+
143
+ ## Key Capabilities
144
+
145
+ - **Zero Supply-Chain Risk:** Pure Python standard library only (`time`, `dataclasses`, `contextvars`); vendorable as a single file (`timerun.py`).
146
+ - **Context Isolation:** Native `ContextVar` stacks ensure concurrent `asyncio` tasks and threads never mix up measurements.
147
+ - **Sub-Microsecond Overhead:** Slotted dataclasses and integer nanoseconds keep internal overhead under ~0.4 µs.
148
+ - **Full Async & Generator Support:** Accurately times coroutines, synchronous generators, and asynchronous streaming generators across full iteration.
149
+ - **100% Test Coverage:** Verified with comprehensive Behavior-Driven Development (BDD) test suites.
150
+
151
+ ## Documentation
152
+
153
+ - **[Documentation Site](https://hh-mwb.github.io/timerun/)** — Tutorials, concepts, and guides.
154
+ - **[API Guide](https://hh-mwb.github.io/timerun/guide/)** — In-depth reference for `Timer`, `Measurement`, and `TimeSpan`.
155
+ - **[Cookbooks](https://hh-mwb.github.io/timerun/cookbook/)** — Real-world recipes for FastAPI, OpenTelemetry, Structlog, and LLM streaming.
156
+
157
+ ## Contributing
158
+
159
+ Contributions are welcome! See [CONTRIBUTING.md](https://github.com/HH-MWB/timerun/blob/main/CONTRIBUTING.md) for setup, testing, and pull request guidelines.
160
+
161
+ ## License
162
+
163
+ This project is licensed under the MIT License — see the [LICENSE](https://github.com/HH-MWB/timerun/blob/main/LICENSE) file for details.
@@ -0,0 +1,132 @@
1
+ <p align="center">
2
+ <a href="https://github.com/HH-MWB/timerun">
3
+ <img src="https://github.com/user-attachments/assets/00f08873-3ee5-4ee4-a41f-f9eda37fc30d" alt="TimeRun">
4
+ </a>
5
+ </p>
6
+
7
+ <p align="center">
8
+ <strong>Structured, zero-dependency Python timing for humans and telemetry.</strong><br>
9
+ Instantly isolate wall-clock latency from CPU burn across sync, async, and generators.
10
+ </p>
11
+
12
+ <p align="center">
13
+ <a href="https://pypi.org/project/timerun/"><img alt="PyPI Version" src="https://img.shields.io/pypi/v/timerun.svg"></a>
14
+ <a href="https://codecov.io/gh/HH-MWB/timerun"><img alt="Coverage" src="https://codecov.io/gh/HH-MWB/timerun/branch/main/graph/badge.svg"></a>
15
+ <a href="https://github.com/HH-MWB/timerun/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/pypi/l/timerun.svg"></a>
16
+ <a href="https://pepy.tech/project/timerun"><img alt="Total Downloads" src="https://static.pepy.tech/badge/timerun"></a>
17
+ </p>
18
+
19
+ ---
20
+
21
+ ## Quickstart
22
+
23
+ ### 1. Measure Code Blocks (Wall vs. CPU)
24
+
25
+ Wrap any block in `with Timer() as m:` (or `async with Timer() as m:`). On exit, `m.wall_time` and `m.cpu_time` are immediately available:
26
+
27
+ ```python
28
+ import time
29
+ from timerun import Timer
30
+
31
+ with Timer() as m:
32
+ time.sleep(0.05) # Simulates network I/O or database wait
33
+ total = sum(i * i for i in range(100_000)) # Simulates CPU computation
34
+
35
+ print("Elapsed (Wall):", m.wall_time.timedelta) # e.g., 0:00:00.055120
36
+ print("Compute (CPU): ", m.cpu_time.timedelta) # e.g., 0:00:00.005110
37
+ ```
38
+
39
+ > **Why both?** If wall time is 2 seconds but CPU time is 5 milliseconds, your code spent 99.7% of its time waiting on I/O. If both are 2 seconds, you have a CPU bottleneck.
40
+
41
+ ### 2. Time Functions and Generators
42
+
43
+ Use `@Timer()` on sync or async functions. The wrapped function retains a bounded deque of measurements:
44
+
45
+ ```python
46
+ from timerun import Timer
47
+
48
+
49
+ @Timer(maxlen=100)
50
+ def process_batch(items):
51
+ return [x * 2 for x in items]
52
+
53
+
54
+ process_batch([1, 2, 3])
55
+
56
+ last = process_batch.measurements[-1]
57
+ print("Wall time:", last.wall_time.timedelta)
58
+ print("CPU time: ", last.cpu_time.timedelta)
59
+ ```
60
+
61
+ ### 3. Stream to Logs & Observability
62
+
63
+ Use `on_end` to ship timings directly to your logs, OpenTelemetry, Prometheus, or Datadog without adding vendor dependencies to your core logic:
64
+
65
+ ```python
66
+ import logging
67
+ from timerun import Timer
68
+
69
+ logger = logging.getLogger("app")
70
+
71
+ with Timer(
72
+ metadata={"service": "checkout", "user_id": "u-123"},
73
+ on_end=lambda m: logger.info(
74
+ "checkout_completed",
75
+ extra={
76
+ "wall_ms": m.wall_time.duration / 1e6,
77
+ "cpu_ms": m.cpu_time.duration / 1e6,
78
+ **m.metadata,
79
+ },
80
+ ),
81
+ ):
82
+ pass # your operation
83
+ ```
84
+
85
+ ## Installation
86
+
87
+ ```bash
88
+ pip install timerun
89
+ ```
90
+
91
+ *Requires Python 3.10+.*
92
+
93
+ ## Why TimeRun?
94
+
95
+ When code runs slowly, **is it waiting on network/disk I/O, or burning CPU?**
96
+
97
+ - `time.perf_counter()` only gives a raw float of elapsed wall time. Measuring CPU time requires manual `time.thread_time()` calls and boilerplate.
98
+ - Profilers (`cProfile`, `py-spy`) and APM agents (`Datadog`, `New Relic`) introduce binary dependencies, sampling overhead, or vendor lock-in.
99
+ - Naive timing patterns risk race conditions and crosstalk in concurrent `asyncio` tasks or multi-threaded workers.
100
+
101
+ TimeRun provides clean, structured timing with sub-microsecond overhead:
102
+
103
+ | Feature | Manual `time.perf_counter()` | Profilers (`cProfile`, `py-spy`) | APM Agents (`Datadog`, `New Relic`) | **TimeRun** |
104
+ | :--- | :---: | :---: | :---: | :---: |
105
+ | **Dependencies** | None | Extra tooling | Large binary agents | **Zero (stdlib only)** |
106
+ | **Wall vs. CPU Breakdown** | ❌ Manual boilerplate | ⚠️ Profiling overhead | ❌ Usually wall only | **✅ Built-in & precise** |
107
+ | **Structured Output** | ❌ Raw floats | ❌ Binary trace files | ⚠️ Proprietary format | **✅ Structured `Measurement`** |
108
+ | **Asyncio & Thread Safe** | ❌ Race condition risk | ⚠️ Global runtime cost | ✅ Handled by agent | **✅ Task & Thread isolated** |
109
+ | **Telemetry Hooks** | ❌ Build it yourself | ❌ Offline analysis only | ⚠️ Vendor locked | **✅ Agnostic (`on_end`)** |
110
+ | **Footprint** | 0 LOC | Heavy | Large background daemon | **Single file (~500 LOC)** |
111
+
112
+ ## Key Capabilities
113
+
114
+ - **Zero Supply-Chain Risk:** Pure Python standard library only (`time`, `dataclasses`, `contextvars`); vendorable as a single file (`timerun.py`).
115
+ - **Context Isolation:** Native `ContextVar` stacks ensure concurrent `asyncio` tasks and threads never mix up measurements.
116
+ - **Sub-Microsecond Overhead:** Slotted dataclasses and integer nanoseconds keep internal overhead under ~0.4 µs.
117
+ - **Full Async & Generator Support:** Accurately times coroutines, synchronous generators, and asynchronous streaming generators across full iteration.
118
+ - **100% Test Coverage:** Verified with comprehensive Behavior-Driven Development (BDD) test suites.
119
+
120
+ ## Documentation
121
+
122
+ - **[Documentation Site](https://hh-mwb.github.io/timerun/)** — Tutorials, concepts, and guides.
123
+ - **[API Guide](https://hh-mwb.github.io/timerun/guide/)** — In-depth reference for `Timer`, `Measurement`, and `TimeSpan`.
124
+ - **[Cookbooks](https://hh-mwb.github.io/timerun/cookbook/)** — Real-world recipes for FastAPI, OpenTelemetry, Structlog, and LLM streaming.
125
+
126
+ ## Contributing
127
+
128
+ Contributions are welcome! See [CONTRIBUTING.md](https://github.com/HH-MWB/timerun/blob/main/CONTRIBUTING.md) for setup, testing, and pull request guidelines.
129
+
130
+ ## License
131
+
132
+ This project is licensed under the MIT License — see the [LICENSE](https://github.com/HH-MWB/timerun/blob/main/LICENSE) file for details.
@@ -0,0 +1,258 @@
1
+ # ============================================================================
2
+ # Build System & Package Metadata (PEP 517 / PEP 621 / PEP 735)
3
+ # ============================================================================
4
+
5
+ [build-system]
6
+ requires = ["setuptools"]
7
+ build-backend = "setuptools.build_meta"
8
+
9
+ [project]
10
+ name = "timerun"
11
+ description = "Structured wall-clock & CPU timing for Python (stdlib only). Zero dependencies, nanosecond precision, and ready for your logs, metrics, and OpenTelemetry."
12
+ readme = "README.md"
13
+ requires-python = ">=3.10"
14
+ license = { text = "MIT" }
15
+ authors = [{ name = "HH-MWB", email = "h.hong@mail.com" }]
16
+ keywords = [
17
+ "time",
18
+ "timing",
19
+ "measurement",
20
+ "measurements",
21
+ "elapsed",
22
+ "stopwatch",
23
+ "timer",
24
+ "performance",
25
+ "latency",
26
+ "profiler",
27
+ "benchmarking",
28
+ "telemetry",
29
+ "opentelemetry",
30
+ "wall-clock",
31
+ "cpu-time",
32
+ "asyncio",
33
+ "fastapi",
34
+ ]
35
+ classifiers = [
36
+ "Development Status :: 4 - Beta",
37
+ "Intended Audience :: Developers",
38
+ "License :: OSI Approved :: MIT License",
39
+ "Operating System :: OS Independent",
40
+ "Programming Language :: Python :: 3",
41
+ "Programming Language :: Python :: 3.10",
42
+ "Programming Language :: Python :: 3.11",
43
+ "Programming Language :: Python :: 3.12",
44
+ "Programming Language :: Python :: 3.13",
45
+ "Programming Language :: Python :: 3.14",
46
+ "Programming Language :: Python :: 3.15",
47
+ "Topic :: Software Development :: Libraries :: Python Modules",
48
+ "Topic :: System :: Monitoring",
49
+ ]
50
+ dynamic = ["version"]
51
+
52
+ [project.urls]
53
+ Homepage = "https://hh-mwb.github.io/timerun/"
54
+ Documentation = "https://hh-mwb.github.io/timerun/"
55
+ Repository = "https://github.com/HH-MWB/timerun"
56
+ Issues = "https://github.com/HH-MWB/timerun/issues"
57
+ Changelog = "https://github.com/HH-MWB/timerun/releases"
58
+ PyPI = "https://pypi.org/project/timerun"
59
+
60
+ [dependency-groups]
61
+ dev = [
62
+ { include-group = "test" },
63
+ { include-group = "audit" },
64
+ "pre-commit",
65
+ ]
66
+ test = [
67
+ "behave",
68
+ "coverage",
69
+ ]
70
+ audit = [
71
+ "pip-audit",
72
+ ]
73
+ docs = [
74
+ "zensical",
75
+ ]
76
+ build = [
77
+ "build",
78
+ "twine",
79
+ ]
80
+
81
+ # ============================================================================
82
+ # Build Backend
83
+ # ============================================================================
84
+
85
+ [tool.setuptools]
86
+ py-modules = ["timerun"]
87
+ license-files = ["LICENSE"]
88
+
89
+ [tool.setuptools.dynamic]
90
+ version = { attr = "timerun.__version__" }
91
+
92
+ # ============================================================================
93
+ # Linting & Formatting
94
+ # ============================================================================
95
+
96
+ [tool.ruff]
97
+ target-version = "py310"
98
+ line-length = 79
99
+ fix = true
100
+ force-exclude = true
101
+
102
+ [tool.ruff.lint]
103
+ select = ["ALL"]
104
+ ignore = [
105
+ "CPY001", # Missing copyright notice at top of file
106
+ "D203", # Incompatible with D211 (no-blank-line-before-class)
107
+ "D213", # Incompatible with D212 (multi-line-summary-first-line)
108
+ ]
109
+
110
+ [tool.ruff.lint.per-file-ignores]
111
+ "features/steps/*.py" = ["S101"]
112
+
113
+ [tool.ruff.lint.isort]
114
+ combine-as-imports = true
115
+ known-first-party = ["timerun"]
116
+
117
+ [tool.ruff.lint.mccabe]
118
+ max-complexity = 5
119
+
120
+ [tool.ruff.lint.pydocstyle]
121
+ convention = "numpy"
122
+
123
+ [tool.ruff.lint.flake8-type-checking]
124
+ strict = true
125
+
126
+ [tool.pylint.main]
127
+ py-version = "3.10"
128
+ fail-under = 10.0
129
+ load-plugins = ["pylint.extensions.mccabe"]
130
+
131
+ [tool.pylint.messages_control]
132
+ disable = [
133
+ "not-callable", # false positive for behave's when/then decorators
134
+ ]
135
+
136
+ [tool.pylint.format]
137
+ max-line-length = 79
138
+
139
+ [tool.pylint.imports]
140
+ known-first-party = ["timerun"]
141
+
142
+ [tool.pylint.design]
143
+ max-args = 4
144
+ max-attributes = 5
145
+ max-complexity = 5
146
+ max-returns = 3
147
+ max-branches = 4
148
+ max-statements = 20
149
+
150
+ # ============================================================================
151
+ # Type Checking
152
+ # ============================================================================
153
+
154
+ [tool.mypy]
155
+ python_version = "3.10"
156
+ strict = true
157
+ extra_checks = true
158
+ local_partial_types = true
159
+
160
+ # Stricter checks beyond default strict mode
161
+ disallow_any_decorated = true
162
+ disallow_any_explicit = true
163
+ disallow_any_unimported = true
164
+ strict_equality_for_none = true
165
+ warn_unreachable = true
166
+
167
+ # Extended error codes
168
+ enable_error_code = [
169
+ "deprecated",
170
+ "exhaustive-match",
171
+ "explicit-override",
172
+ "ignore-without-code",
173
+ "possibly-undefined",
174
+ "redundant-expr",
175
+ "redundant-self",
176
+ "truthy-bool",
177
+ "truthy-function",
178
+ "truthy-iterable",
179
+ "unimported-reveal",
180
+ "unused-awaitable",
181
+ ]
182
+
183
+ # Output formatting
184
+ show_column_numbers = true
185
+ show_error_codes = true
186
+ show_error_context = true
187
+ pretty = true
188
+
189
+ [[tool.mypy.overrides]]
190
+ module = [
191
+ "behave",
192
+ "behave.*",
193
+ ]
194
+ ignore_missing_imports = true
195
+
196
+ [[tool.mypy.overrides]]
197
+ module = "features.*"
198
+ ignore_errors = true
199
+
200
+ [tool.pyright]
201
+ pythonVersion = "3.10"
202
+ venvPath = "."
203
+ venv = ".venv"
204
+
205
+ include = ["timerun.py"]
206
+ exclude = ["features"]
207
+
208
+ typeCheckingMode = "strict"
209
+ deprecateTypingAliases = true
210
+
211
+ # Diagnostic rules elevated to error beyond strict mode
212
+ reportCallInDefaultInitializer = "error"
213
+ reportImplicitOverride = "error"
214
+ reportImplicitStringConcatenation = "error"
215
+ reportImportCycles = "error"
216
+ reportMissingSuperCall = "error"
217
+ reportPropertyTypeMismatch = "error"
218
+ reportUninitializedInstanceVariable = "error"
219
+ reportUnnecessaryCast = "error"
220
+ reportUnnecessaryComparison = "error"
221
+ reportUnnecessaryContains = "error"
222
+ reportUnnecessaryIsInstance = "error"
223
+ reportUnnecessaryTypeIgnoreComment = "error"
224
+ reportUnusedCallResult = "error"
225
+
226
+ # ============================================================================
227
+ # Security Analysis
228
+ # ============================================================================
229
+
230
+ [tool.bandit]
231
+ exclude_dirs = ["features/steps"]
232
+
233
+ [tool.bandit.try_except_pass]
234
+ check_typed_exception = true
235
+
236
+ # ============================================================================
237
+ # Spelling & Quality
238
+ # ============================================================================
239
+
240
+ [tool.codespell]
241
+ check-filenames = true
242
+ check-hidden = true
243
+
244
+ # ============================================================================
245
+ # Testing & Coverage
246
+ # ============================================================================
247
+
248
+ [tool.behave]
249
+ show_snippets = false
250
+ show_skipped = false
251
+
252
+ [tool.coverage.run]
253
+ source = ["timerun"]
254
+ relative_files = true
255
+
256
+ [tool.coverage.report]
257
+ fail_under = 100
258
+ show_missing = true