kaparoo-python 0.6.0__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.
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/PKG-INFO +2 -2
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/README.md +1 -1
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/README.md +22 -1
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/__init__.py +2 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/utils.py +53 -1
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/utils/README.md +14 -14
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/utils/__init__.py +3 -3
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/utils/timer.py +32 -32
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/pyproject.toml +1 -1
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/LICENSE +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/__init__.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/data/README.md +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/data/__init__.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/data/sequences/__init__.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/data/sequences/base.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/data/sequences/composers.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/data/sequences/templates.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/data/sequences/utils.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/directory.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/exceptions.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/existence.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/search/README.md +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/search/__init__.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/search/classes.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/search/deprecated.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/search/filters/__init__.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/search/filters/base.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/search/filters/logical.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/search/filters/multi_pattern.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/search/filters/pattern.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/search/filters/types.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/search/filters/utils.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/search/wrappers.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/staged.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/types.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/py.typed +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/utils/aggregate.py +0 -0
- {kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/utils/optional.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kaparoo-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Personally common and useful Python features
|
|
5
5
|
Keywords: filesystem,pathlib,paths,utilities
|
|
6
6
|
Author: Jaewoo Park
|
|
@@ -65,7 +65,7 @@ hook for custom filter kinds.
|
|
|
65
65
|
|
|
66
66
|
### [`kaparoo.utils`](https://github.com/kaparoo/kaparoo-python/tree/main/kaparoo/utils)
|
|
67
67
|
|
|
68
|
-
`Timer` / `
|
|
68
|
+
`Timer` / `SpanTimer` context-manager-and-decorator timers (with
|
|
69
69
|
`lap`-split and `measure`-block timings); `Aggregator` for nested,
|
|
70
70
|
pluggable metric aggregation (the batch → epoch → run pattern;
|
|
71
71
|
experimental); plus a small family of helpers for working with
|
|
@@ -44,7 +44,7 @@ hook for custom filter kinds.
|
|
|
44
44
|
|
|
45
45
|
### [`kaparoo.utils`](https://github.com/kaparoo/kaparoo-python/tree/main/kaparoo/utils)
|
|
46
46
|
|
|
47
|
-
`Timer` / `
|
|
47
|
+
`Timer` / `SpanTimer` context-manager-and-decorator timers (with
|
|
48
48
|
`lap`-split and `measure`-block timings); `Aggregator` for nested,
|
|
49
49
|
pluggable metric aggregation (the batch → epoch → run pattern;
|
|
50
50
|
experimental); plus a small family of helpers for working with
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
`dir_not_empty(s)` with validation, plus `_unsafe` variants that skip
|
|
11
11
|
pre-checks
|
|
12
12
|
- [`utils`](./utils.py) — `stringify_path(s)`, `wrap_path(s)`,
|
|
13
|
-
`reserve_path(s)`
|
|
13
|
+
`reserve_path(s)`, `ensure_file_extension`
|
|
14
14
|
- [`staged`](./staged.py) — `StagedFile` / `StagedDirectory`, safe
|
|
15
15
|
(atomic) writers usable as a context manager or explicitly
|
|
16
16
|
- [`exceptions`](./exceptions.py) — `DirectoryNotFoundError`, `NotAFileError`
|
|
@@ -116,6 +116,27 @@ stringify_paths(["data/a.txt", "data/b.txt"], after="data") # ["a.txt", "b.txt"
|
|
|
116
116
|
wrap_path("logs", prepend="var", append="server.log") # var/logs/server.log
|
|
117
117
|
```
|
|
118
118
|
|
|
119
|
+
`ensure_file_extension` is a pure (no filesystem) extension check: it
|
|
120
|
+
requires a `.<ext>` final suffix, raising `ValueError` otherwise. `ext` may
|
|
121
|
+
be a single extension or an iterable of acceptable ones; the leading dot is
|
|
122
|
+
optional and the match is case-insensitive. `add=True` mirrors `make` on
|
|
123
|
+
`ensure_dir_exists` — it appends the (first) extension when the path has no
|
|
124
|
+
suffix (`np.save`-style) instead of raising; a *wrong* suffix still raises.
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
from kaparoo.filesystem import ensure_file_extension
|
|
128
|
+
|
|
129
|
+
ensure_file_extension("data.bin", "bin") # Path("data.bin")
|
|
130
|
+
ensure_file_extension("data.txt", "bin") # ValueError
|
|
131
|
+
ensure_file_extension("out/00000_phase", "bin") # ValueError (no suffix)
|
|
132
|
+
|
|
133
|
+
# Any of several accepted extensions:
|
|
134
|
+
ensure_file_extension("img.jpeg", ("jpg", "jpeg", "png")) # Path("img.jpeg")
|
|
135
|
+
|
|
136
|
+
ensure_file_extension("out/00000_phase", "bin", add=True) # Path("out/00000_phase.bin")
|
|
137
|
+
ensure_file_extension("out/data.txt", "bin", add=True) # ValueError (wrong suffix)
|
|
138
|
+
```
|
|
139
|
+
|
|
119
140
|
## Reserving a destination
|
|
120
141
|
|
|
121
142
|
`reserve_path` guards a path that should *not* yet exist, so you don't
|
|
@@ -16,6 +16,7 @@ __all__ = (
|
|
|
16
16
|
"ensure_dir_exists",
|
|
17
17
|
"ensure_dirs_exist",
|
|
18
18
|
"ensure_file_exists",
|
|
19
|
+
"ensure_file_extension",
|
|
19
20
|
"ensure_files_exist",
|
|
20
21
|
"ensure_path_exists",
|
|
21
22
|
"ensure_paths_exist",
|
|
@@ -79,6 +80,7 @@ from kaparoo.filesystem.search import (
|
|
|
79
80
|
)
|
|
80
81
|
from kaparoo.filesystem.staged import StagedDirectory, StagedFile
|
|
81
82
|
from kaparoo.filesystem.utils import (
|
|
83
|
+
ensure_file_extension,
|
|
82
84
|
reserve_path,
|
|
83
85
|
reserve_paths,
|
|
84
86
|
stringify_path,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
__all__ = (
|
|
4
|
+
"ensure_file_extension",
|
|
4
5
|
"reserve_path",
|
|
5
6
|
"reserve_paths",
|
|
6
7
|
"stringify_path",
|
|
@@ -15,7 +16,7 @@ from pathlib import Path
|
|
|
15
16
|
from typing import TYPE_CHECKING, overload
|
|
16
17
|
|
|
17
18
|
if TYPE_CHECKING:
|
|
18
|
-
from collections.abc import Sequence
|
|
19
|
+
from collections.abc import Iterable, Sequence
|
|
19
20
|
from typing import Literal
|
|
20
21
|
|
|
21
22
|
from kaparoo.filesystem.types import StrPath, StrPaths
|
|
@@ -357,3 +358,54 @@ def reserve_paths(
|
|
|
357
358
|
reserve_path(p, exist_ok=exist_ok, make_parents=make_parents) for p in paths
|
|
358
359
|
]
|
|
359
360
|
return stringify_paths(paths) if stringify else paths
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def ensure_file_extension(
|
|
364
|
+
path: StrPath, ext: str | Iterable[str], *, add: bool = False
|
|
365
|
+
) -> Path:
|
|
366
|
+
"""Return `path` as a `Path`, requiring a case-insensitive `.<ext>` suffix.
|
|
367
|
+
|
|
368
|
+
A pure path check that never touches the filesystem. `ext` is a single
|
|
369
|
+
extension or an iterable of acceptable ones (e.g. `("jpg", "jpeg")`); the
|
|
370
|
+
leading dot on each is optional, so `"bin"` and `".bin"` behave the same.
|
|
371
|
+
Only the final suffix is considered: `archive.tar.gz` matches `ext="gz"`,
|
|
372
|
+
not `ext="tar.gz"`.
|
|
373
|
+
|
|
374
|
+
`add` mirrors `make` on `ensure_dir_exists`: when False (the default) a
|
|
375
|
+
path with no suffix raises like any other mismatch; when True, the missing
|
|
376
|
+
suffix is appended -- the *first* of `ext` when several are given, so pass
|
|
377
|
+
an ordered list/tuple if that matters. A *wrong* suffix always raises,
|
|
378
|
+
regardless of `add`.
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
path: The path to check.
|
|
382
|
+
ext: The required extension, or an iterable of acceptable ones, each
|
|
383
|
+
with or without a leading dot.
|
|
384
|
+
add: Whether to append the (first) extension when `path` has no
|
|
385
|
+
suffix, instead of raising. Defaults to False.
|
|
386
|
+
|
|
387
|
+
Returns:
|
|
388
|
+
The path as a Path object, guaranteed to end in an accepted `.<ext>`.
|
|
389
|
+
|
|
390
|
+
Raises:
|
|
391
|
+
ValueError: If `ext` is empty, or `path`'s final suffix is none of the
|
|
392
|
+
accepted extensions -- except the no-suffix case resolved by
|
|
393
|
+
`add=True`.
|
|
394
|
+
"""
|
|
395
|
+
exts = [ext] if isinstance(ext, str) else list(ext)
|
|
396
|
+
exts = [e.removeprefix(".") for e in exts]
|
|
397
|
+
|
|
398
|
+
if not exts:
|
|
399
|
+
msg = "ext must name at least one extension"
|
|
400
|
+
raise ValueError(msg)
|
|
401
|
+
|
|
402
|
+
path = Path(path)
|
|
403
|
+
if add and not path.suffix:
|
|
404
|
+
return path.with_suffix(f".{exts[0]}")
|
|
405
|
+
|
|
406
|
+
if path.suffix.lower() not in {f".{e.lower()}" for e in exts}:
|
|
407
|
+
wanted = " / ".join(f".{e}" for e in exts)
|
|
408
|
+
msg = f"{path.name} must have a {wanted} extension (got {path.suffix!r})"
|
|
409
|
+
raise ValueError(msg)
|
|
410
|
+
|
|
411
|
+
return path
|
|
@@ -4,7 +4,7 @@ Small, focused helpers — not enough material for their own packages.
|
|
|
4
4
|
|
|
5
5
|
## Modules
|
|
6
6
|
|
|
7
|
-
- [`timer`](./timer.py) — `Timer`, `
|
|
7
|
+
- [`timer`](./timer.py) — `Timer`, `SpanTimer`, `SpanRecord`
|
|
8
8
|
- [`aggregate`](./aggregate.py) — `Aggregator` + the `Reduction` family
|
|
9
9
|
(`Mean`, `Sum`, `Min`, `Max`, `Last`, `Fold`)
|
|
10
10
|
- [`optional`](./optional.py) — helpers for `T | None` values
|
|
@@ -47,29 +47,29 @@ with Timer("ms") as t:
|
|
|
47
47
|
do_work()
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
##
|
|
50
|
+
## SpanTimer
|
|
51
51
|
|
|
52
|
-
`
|
|
53
|
-
is a `
|
|
52
|
+
`SpanTimer` extends `Timer` with named time *spans*. Each span
|
|
53
|
+
is a `SpanRecord` (a `TypedDict` with `label`, `duration`,
|
|
54
54
|
`total_time`) and is produced in one of two ways:
|
|
55
55
|
|
|
56
56
|
- **`lap(label)` — split.** Each lap's `duration` is the time since the
|
|
57
57
|
previous lap (or the start), so every instant belongs to exactly one
|
|
58
|
-
|
|
58
|
+
span.
|
|
59
59
|
- **`measure(label)` — stopwatch.** Times only the wrapped block; time
|
|
60
|
-
spent outside any `measure` block is attributed to no
|
|
60
|
+
spent outside any `measure` block is attributed to no span.
|
|
61
61
|
|
|
62
62
|
```python
|
|
63
|
-
from kaparoo.utils.timer import
|
|
63
|
+
from kaparoo.utils.timer import SpanTimer
|
|
64
64
|
|
|
65
|
-
with
|
|
65
|
+
with SpanTimer("ms", ndigits=1) as st:
|
|
66
66
|
step_a()
|
|
67
67
|
st.lap("A") # split: time since start
|
|
68
68
|
idle() # NOT counted by the next measure
|
|
69
69
|
with st.measure("B"): # stopwatch: only this block
|
|
70
70
|
step_b()
|
|
71
71
|
|
|
72
|
-
# Per-
|
|
72
|
+
# Per-span details:
|
|
73
73
|
for record in st.records:
|
|
74
74
|
print(record["label"], record["duration"])
|
|
75
75
|
|
|
@@ -80,7 +80,7 @@ print(st.elapsed) # total wall time of the `with` block
|
|
|
80
80
|
|
|
81
81
|
### `lap` vs `measure`
|
|
82
82
|
|
|
83
|
-
`lap` splits the timeline into contiguous
|
|
83
|
+
`lap` splits the timeline into contiguous spans — the gap before a
|
|
84
84
|
lap is folded into that lap. `measure` brackets a region and ignores
|
|
85
85
|
everything outside it, so untimed work between blocks is excluded from
|
|
86
86
|
`summary`. Pick `lap` for back-to-back phases, `measure` for discrete
|
|
@@ -88,16 +88,16 @@ operations interleaved with untimed work. Pauses inside either are
|
|
|
88
88
|
excluded; a `measure` block that raises records nothing.
|
|
89
89
|
|
|
90
90
|
`measure` doubles as a decorator (every decorated call records one
|
|
91
|
-
|
|
91
|
+
span, as long as the timer is running when it is called):
|
|
92
92
|
|
|
93
93
|
```python
|
|
94
|
-
st =
|
|
94
|
+
st = SpanTimer("ms")
|
|
95
95
|
|
|
96
96
|
@st.measure("load")
|
|
97
97
|
def load() -> None: ...
|
|
98
98
|
|
|
99
99
|
with st:
|
|
100
|
-
load() # records a "load"
|
|
100
|
+
load() # records a "load" span each call
|
|
101
101
|
```
|
|
102
102
|
|
|
103
103
|
### Same-label policies
|
|
@@ -111,7 +111,7 @@ with st:
|
|
|
111
111
|
The policy applies to both `lap` and `measure`:
|
|
112
112
|
|
|
113
113
|
```python
|
|
114
|
-
with
|
|
114
|
+
with SpanTimer(on_same_label="separate") as st:
|
|
115
115
|
st.lap("A")
|
|
116
116
|
st.lap("A") # recorded as "A (2)"
|
|
117
117
|
st.lap("A") # recorded as "A (3)"
|
|
@@ -6,8 +6,8 @@ __all__ = (
|
|
|
6
6
|
"Mean",
|
|
7
7
|
"Min",
|
|
8
8
|
"Reduction",
|
|
9
|
-
"
|
|
10
|
-
"
|
|
9
|
+
"SpanRecord",
|
|
10
|
+
"SpanTimer",
|
|
11
11
|
"Std",
|
|
12
12
|
"Sum",
|
|
13
13
|
"Timer",
|
|
@@ -42,4 +42,4 @@ from kaparoo.utils.optional import (
|
|
|
42
42
|
unwrap_or_factories,
|
|
43
43
|
unwrap_or_factory,
|
|
44
44
|
)
|
|
45
|
-
from kaparoo.utils.timer import
|
|
45
|
+
from kaparoo.utils.timer import SpanRecord, SpanTimer, Timer
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
__all__ = ("
|
|
3
|
+
__all__ = ("SpanRecord", "SpanTimer", "Timer")
|
|
4
4
|
|
|
5
5
|
import time
|
|
6
6
|
from abc import ABC, abstractmethod
|
|
@@ -22,20 +22,20 @@ _SCALES: dict[str, float] = {"s": 1e-9, "ms": 1e-6, "us": 1e-3, "ns": 1.0}
|
|
|
22
22
|
_LABEL_POLICIES: frozenset[str] = frozenset({"merge", "separate", "reject"})
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
class
|
|
26
|
-
"""A single timing record produced by `
|
|
25
|
+
class SpanRecord(TypedDict):
|
|
26
|
+
"""A single timing record produced by `SpanTimer`.
|
|
27
27
|
|
|
28
|
-
A
|
|
28
|
+
A span is produced either by `lap` (the span since the previous
|
|
29
29
|
lap) or by `measure` (the span of a wrapped block).
|
|
30
30
|
|
|
31
31
|
Attributes:
|
|
32
|
-
label: The
|
|
32
|
+
label: The span's name. May carry a " (N)" suffix when produced
|
|
33
33
|
under `on_same_label="separate"`.
|
|
34
|
-
duration: Length of this
|
|
34
|
+
duration: Length of this span, in the timer's `unit` and rounded
|
|
35
35
|
by `ndigits` if given. For `lap`, the time since the previous
|
|
36
36
|
lap (or the timer start); for `measure`, the wrapped block's
|
|
37
37
|
duration.
|
|
38
|
-
total_time: Time elapsed from the timer start to this
|
|
38
|
+
total_time: Time elapsed from the timer start to this span's end,
|
|
39
39
|
in the timer's `unit` and rounded by `ndigits` if given.
|
|
40
40
|
"""
|
|
41
41
|
|
|
@@ -45,14 +45,14 @@ class SegmentRecord(TypedDict):
|
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
class BaseTimer(ContextDecorator, ABC):
|
|
48
|
-
"""Abstract base for `Timer` and `
|
|
48
|
+
"""Abstract base for `Timer` and `SpanTimer`.
|
|
49
49
|
|
|
50
50
|
Provides the shared timing machinery: unit/precision formatting,
|
|
51
51
|
`pause`/`resume`/`suspend`, and a context-manager protocol that
|
|
52
52
|
auto-resumes a paused timer on exit. Subclasses implement `_finalize`
|
|
53
53
|
to record their final result, and may override the `_reset` hook to
|
|
54
54
|
clear per-`with`-block state. Not part of the public API -- prefer
|
|
55
|
-
`Timer` or `
|
|
55
|
+
`Timer` or `SpanTimer`.
|
|
56
56
|
|
|
57
57
|
An instance is reusable but **not reentrant**: a single instance must
|
|
58
58
|
not be nested within itself -- including as a decorator on a recursive
|
|
@@ -249,30 +249,30 @@ class Timer(BaseTimer):
|
|
|
249
249
|
self.elapsed = self._format_time(elapsed_ns)
|
|
250
250
|
|
|
251
251
|
|
|
252
|
-
class
|
|
253
|
-
"""A timer recording named time
|
|
252
|
+
class SpanTimer(BaseTimer):
|
|
253
|
+
"""A timer recording named time spans within one `with` block.
|
|
254
254
|
|
|
255
|
-
Usable as a context manager or as a decorator.
|
|
255
|
+
Usable as a context manager or as a decorator. Spans are recorded
|
|
256
256
|
in two complementary ways:
|
|
257
257
|
|
|
258
258
|
- `lap(label)` splits the timeline: each lap's `duration` is the
|
|
259
259
|
time since the previous lap (or the start), so every instant is
|
|
260
|
-
attributed to exactly one
|
|
260
|
+
attributed to exactly one span.
|
|
261
261
|
- `measure(label)` brackets a region (as a `with` block or a
|
|
262
262
|
decorator): only the wrapped span is recorded, and time spent
|
|
263
|
-
outside any `measure` block is attributed to no
|
|
263
|
+
outside any `measure` block is attributed to no span.
|
|
264
264
|
|
|
265
265
|
Both feed the same `records` / `summary`, honour `on_same_label`, and
|
|
266
266
|
exclude paused intervals.
|
|
267
267
|
|
|
268
268
|
Attributes:
|
|
269
269
|
on_same_label: The same-label handling policy (see `__init__`).
|
|
270
|
-
records: The recorded
|
|
270
|
+
records: The recorded spans, in call order.
|
|
271
271
|
elapsed: The total measured duration, from start to exit.
|
|
272
272
|
Defaults to 0.0 until the first exit.
|
|
273
273
|
|
|
274
274
|
Example:
|
|
275
|
-
with
|
|
275
|
+
with SpanTimer("ms", ndigits=1) as st:
|
|
276
276
|
step_a()
|
|
277
277
|
st.lap("A") # split: time since start
|
|
278
278
|
with st.measure("B"): # block: only this region
|
|
@@ -288,7 +288,7 @@ class SegmentTimer(BaseTimer):
|
|
|
288
288
|
ndigits: int | None = None,
|
|
289
289
|
on_same_label: LabelPolicy = "merge",
|
|
290
290
|
) -> None:
|
|
291
|
-
"""Initialize the
|
|
291
|
+
"""Initialize the span timer.
|
|
292
292
|
|
|
293
293
|
Args:
|
|
294
294
|
unit: The time unit for reported values. One of "s", "ms", "us",
|
|
@@ -313,7 +313,7 @@ class SegmentTimer(BaseTimer):
|
|
|
313
313
|
raise ValueError(msg)
|
|
314
314
|
|
|
315
315
|
self.on_same_label = on_same_label
|
|
316
|
-
self.records: list[
|
|
316
|
+
self.records: list[SpanRecord] = []
|
|
317
317
|
self.elapsed: float = 0.0
|
|
318
318
|
|
|
319
319
|
self._last_time: int = 0
|
|
@@ -323,8 +323,8 @@ class SegmentTimer(BaseTimer):
|
|
|
323
323
|
def summary(self) -> dict[str, float]:
|
|
324
324
|
"""Per-label sum of `duration` across `records`.
|
|
325
325
|
|
|
326
|
-
Only recorded
|
|
327
|
-
|
|
326
|
+
Only recorded spans count: time outside every `lap` / `measure`
|
|
327
|
+
span (e.g. after the last `lap`, or between `measure` blocks) is
|
|
328
328
|
not included. Each record's `duration` is already rounded by
|
|
329
329
|
`ndigits` (when set); this property sums those rounded values and
|
|
330
330
|
rounds the sum once more.
|
|
@@ -377,11 +377,11 @@ class SegmentTimer(BaseTimer):
|
|
|
377
377
|
else label
|
|
378
378
|
)
|
|
379
379
|
|
|
380
|
-
def _make_record(self, label: str) ->
|
|
380
|
+
def _make_record(self, label: str) -> SpanRecord:
|
|
381
381
|
"""Build a record stamped with the current time and advance `_last_time`."""
|
|
382
382
|
current_time = time.perf_counter_ns()
|
|
383
383
|
|
|
384
|
-
record:
|
|
384
|
+
record: SpanRecord = {
|
|
385
385
|
"label": label,
|
|
386
386
|
"duration": self._format_time(current_time - self._last_time),
|
|
387
387
|
"total_time": self._format_time(current_time - self._start_time),
|
|
@@ -415,12 +415,12 @@ class SegmentTimer(BaseTimer):
|
|
|
415
415
|
|
|
416
416
|
@contextmanager
|
|
417
417
|
def measure(self, label: str = "Block") -> Iterator[None]:
|
|
418
|
-
"""Record a
|
|
418
|
+
"""Record a span covering only the wrapped block (stopwatch style).
|
|
419
419
|
|
|
420
|
-
Unlike `lap`, which splits the timeline into contiguous
|
|
420
|
+
Unlike `lap`, which splits the timeline into contiguous spans,
|
|
421
421
|
`measure` times only the wrapped region; time spent outside any
|
|
422
|
-
`measure` block is attributed to no
|
|
423
|
-
block are excluded. A
|
|
422
|
+
`measure` block is attributed to no span. Pauses inside the
|
|
423
|
+
block are excluded. A span is recorded only on clean exit -- if
|
|
424
424
|
the block raises, nothing is recorded and the exception propagates.
|
|
425
425
|
Repeated labels follow `on_same_label`, exactly as `lap`. Do not
|
|
426
426
|
nest `measure` blocks: each resets the shared baseline, so an outer
|
|
@@ -428,23 +428,23 @@ class SegmentTimer(BaseTimer):
|
|
|
428
428
|
|
|
429
429
|
Because `contextmanager` results are also `ContextDecorator`s, the
|
|
430
430
|
returned object doubles as a decorator (every decorated call
|
|
431
|
-
records one
|
|
431
|
+
records one span, provided the timer is running when called):
|
|
432
432
|
|
|
433
|
-
st =
|
|
433
|
+
st = SpanTimer("ms")
|
|
434
434
|
|
|
435
435
|
@st.measure("load")
|
|
436
436
|
def load() -> None: ...
|
|
437
437
|
|
|
438
438
|
with st:
|
|
439
|
-
load() # records a "load"
|
|
439
|
+
load() # records a "load" span
|
|
440
440
|
with st.measure("parse"):
|
|
441
|
-
parse() # records a "parse"
|
|
441
|
+
parse() # records a "parse" span
|
|
442
442
|
|
|
443
443
|
Args:
|
|
444
|
-
label: The
|
|
444
|
+
label: The span's name. Defaults to "Block".
|
|
445
445
|
|
|
446
446
|
Yields:
|
|
447
|
-
None. The wrapped block runs while the
|
|
447
|
+
None. The wrapped block runs while the span is timed.
|
|
448
448
|
|
|
449
449
|
Raises:
|
|
450
450
|
RuntimeError: If the timer has not been started, or is paused on
|
|
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
|
{kaparoo_python-0.6.0 → kaparoo_python-0.7.0}/kaparoo/filesystem/search/filters/multi_pattern.py
RENAMED
|
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
|