nano-dev-utils 0.5.8__py3-none-any.whl → 1.0.0__py3-none-any.whl
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.
Potentially problematic release.
This version of nano-dev-utils might be problematic. Click here for more details.
- nano_dev_utils/timers.py +37 -18
- {nano_dev_utils-0.5.8.dist-info → nano_dev_utils-1.0.0.dist-info}/METADATA +35 -19
- nano_dev_utils-1.0.0.dist-info/RECORD +8 -0
- nano_dev_utils-0.5.8.dist-info/RECORD +0 -8
- {nano_dev_utils-0.5.8.dist-info → nano_dev_utils-1.0.0.dist-info}/WHEEL +0 -0
- {nano_dev_utils-0.5.8.dist-info → nano_dev_utils-1.0.0.dist-info}/licenses/LICENSE +0 -0
nano_dev_utils/timers.py
CHANGED
|
@@ -7,38 +7,57 @@ R = TypeVar('R')
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class Timer:
|
|
10
|
-
def __init__(self, precision=4, verbose=False):
|
|
10
|
+
def __init__(self, precision: int = 4, verbose: bool = False):
|
|
11
11
|
self.precision = precision
|
|
12
12
|
self.verbose = verbose
|
|
13
13
|
self.units = [(1e9, 's'), (1e6, 'ms'), (1e3, 'μs'), (1.0, 'ns')]
|
|
14
14
|
|
|
15
15
|
def timeit(
|
|
16
|
-
self,
|
|
16
|
+
self,
|
|
17
|
+
iterations: int = 1,
|
|
18
|
+
timeout: float | None = None,
|
|
19
|
+
per_iteration: bool = False,
|
|
17
20
|
) -> Callable[[Callable[P, R]], Callable[P, R | None]]:
|
|
18
|
-
|
|
19
|
-
"""Decorator that times function execution with automatic unit scaling and averaging."""
|
|
21
|
+
"""Decorator that times function execution with optional timeout support."""
|
|
20
22
|
|
|
23
|
+
def decorator(func: Callable[P, R]) -> Callable[P, R | None]:
|
|
21
24
|
@wraps(func)
|
|
22
25
|
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R | None:
|
|
23
|
-
|
|
24
|
-
result = None
|
|
26
|
+
total_elapsed_ns = 0
|
|
27
|
+
result: R | None = None
|
|
25
28
|
|
|
26
|
-
for
|
|
27
|
-
|
|
29
|
+
for i in range(1, iterations + 1):
|
|
30
|
+
start_ns = time.perf_counter_ns()
|
|
28
31
|
result = func(*args, **kwargs)
|
|
29
|
-
|
|
32
|
+
duration_ns = time.perf_counter_ns() - start_ns
|
|
33
|
+
total_elapsed_ns += duration_ns
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
if timeout is not None:
|
|
36
|
+
if per_iteration:
|
|
37
|
+
duration_s = duration_ns / 1e9
|
|
38
|
+
if duration_s > timeout:
|
|
39
|
+
raise TimeoutError(
|
|
40
|
+
f'{func.__name__} exceeded '
|
|
41
|
+
f'{timeout:.{self.precision}f}s on '
|
|
42
|
+
f'iteration {i} (took '
|
|
43
|
+
f'{duration_s:.{self.precision}f}s)'
|
|
44
|
+
)
|
|
45
|
+
else:
|
|
46
|
+
total_duration_s = total_elapsed_ns / 1e9
|
|
47
|
+
if total_duration_s > timeout:
|
|
48
|
+
raise TimeoutError(
|
|
49
|
+
f'{func.__name__} exceeded {timeout:.{self.precision}f}s '
|
|
50
|
+
f'after {i} iterations (took {total_duration_s:.{self.precision}f}s)'
|
|
51
|
+
)
|
|
39
52
|
|
|
53
|
+
avg_elapsed_ns = total_elapsed_ns / iterations
|
|
54
|
+
value, unit = next(
|
|
55
|
+
(avg_elapsed_ns / div, u)
|
|
56
|
+
for div, u in self.units
|
|
57
|
+
if avg_elapsed_ns >= div or u == 'ns'
|
|
58
|
+
)
|
|
40
59
|
extra_info = f'{args} {kwargs} ' if self.verbose else ''
|
|
41
|
-
iter_info = f' (avg over {iterations} runs)' if iterations > 1 else ''
|
|
60
|
+
iter_info = f' (avg. over {iterations} runs)' if iterations > 1 else ''
|
|
42
61
|
print(
|
|
43
62
|
f'{func.__name__} {extra_info}took {value:.{self.precision}f} [{unit}]{iter_info}'
|
|
44
63
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nano_dev_utils
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: A collection of small Python utilities for developers.
|
|
5
5
|
Project-URL: Homepage, https://github.com/yaronday/nano_utils
|
|
6
6
|
Project-URL: Issues, https://github.com/yaronday/nano_utils/issues
|
|
@@ -24,23 +24,33 @@ A collection of small Python utilities for developers.
|
|
|
24
24
|
|
|
25
25
|
### `timers.py`
|
|
26
26
|
|
|
27
|
-
This module provides a `Timer` class for measuring the execution time of code blocks and functions.
|
|
27
|
+
This module provides a `Timer` class for measuring the execution time of code blocks and functions with additional features like timeout control and multi-iteration averaging.
|
|
28
28
|
|
|
29
29
|
#### `Timer` Class
|
|
30
30
|
|
|
31
31
|
* **`__init__(self, precision: int = 4, verbose: bool = False)`**: Initializes a `Timer` instance.
|
|
32
|
-
* `precision`: The number of decimal places to record and
|
|
33
|
-
|
|
34
|
-
* `verbose`: Optionally displays the function's positional arguments (args) and keyword arguments (kwargs).
|
|
35
|
-
Defaults to `False`.
|
|
32
|
+
* `precision`: The number of decimal places to record and display time durations. Defaults to 4.
|
|
33
|
+
* `verbose`: Optionally displays the function's positional arguments (args) and keyword arguments (kwargs). Defaults to `False`.
|
|
36
34
|
|
|
37
35
|
* **`timeit(
|
|
38
|
-
self,
|
|
36
|
+
self,
|
|
37
|
+
iterations: int = 1,
|
|
38
|
+
timeout: float | None = None,
|
|
39
|
+
per_iteration: bool = False
|
|
39
40
|
) -> Callable[[Callable[P, R]], Callable[P, R | None]]`**:
|
|
40
|
-
Decorator that times function execution with
|
|
41
|
-
*
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
Decorator that times function execution with advanced features:
|
|
42
|
+
* `iterations`: Number of times to run the function (for averaging). Defaults to 1.
|
|
43
|
+
* `timeout`: Maximum allowed execution time in seconds. When exceeded:
|
|
44
|
+
* Raises `TimeoutError` immediately
|
|
45
|
+
* **Warning:** The function execution will be aborted mid-operation
|
|
46
|
+
* No return value will be available if timeout occurs
|
|
47
|
+
* `per_iteration`: If True, applies timeout check to each iteration; otherwise checks total time across all iterations.
|
|
48
|
+
* Features:
|
|
49
|
+
* Records execution times
|
|
50
|
+
* Handles timeout conditions
|
|
51
|
+
* Calculates average execution time across iterations
|
|
52
|
+
* Prints the function name and execution time (with optional arguments)
|
|
53
|
+
* Returns the result of the original function (unless timeout occurs)
|
|
44
54
|
|
|
45
55
|
#### Example Usage:
|
|
46
56
|
|
|
@@ -50,16 +60,22 @@ from nano_dev_utils.timers import Timer
|
|
|
50
60
|
|
|
51
61
|
timer = Timer(precision=6, verbose=True)
|
|
52
62
|
|
|
53
|
-
|
|
63
|
+
# Basic timing
|
|
54
64
|
@timer.timeit()
|
|
55
65
|
def my_function(a, b=10):
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
66
|
+
"""A sample function."""
|
|
67
|
+
time.sleep(0.1)
|
|
68
|
+
return a + b
|
|
69
|
+
|
|
70
|
+
# Advanced usage with timeout and iterations
|
|
71
|
+
@timer.timeit(iterations=5, timeout=0.5, per_iteration=True)
|
|
72
|
+
def critical_function(x):
|
|
73
|
+
"""Function with timeout check per iteration."""
|
|
74
|
+
time.sleep(0.08)
|
|
75
|
+
return x * 2
|
|
76
|
+
|
|
77
|
+
result1 = my_function(5, b=20) # Shows args/kwargs and timing
|
|
78
|
+
result2 = critical_function(10) # Runs 5 times with per-iteration timeout
|
|
63
79
|
```
|
|
64
80
|
|
|
65
81
|
### `dynamic_importer.py`
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
nano_dev_utils/__init__.py,sha256=imiI367TPj5s4IFmi-VrKJLbdkIxdIPISNscthoaS9U,454
|
|
2
|
+
nano_dev_utils/dynamic_importer.py,sha256=cm2VwDYSGwhGZNO3uMX-O0LaKtEFtzkPm7BrZW4igG4,911
|
|
3
|
+
nano_dev_utils/release_ports.py,sha256=sgmoPax9Hpcse1rHbBSnDJWTkvV6aWpZ5hQFxBKhGR8,5886
|
|
4
|
+
nano_dev_utils/timers.py,sha256=dTbmf2O10YQw_Gz_fVATdZXqxgSpTjTlbeekd_jpLyw,2875
|
|
5
|
+
nano_dev_utils-1.0.0.dist-info/METADATA,sha256=YOD8JC-1a-gaDHF5-VYu3Qtr5-uqHlsSorPguSZvk58,6498
|
|
6
|
+
nano_dev_utils-1.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
7
|
+
nano_dev_utils-1.0.0.dist-info/licenses/LICENSE,sha256=Muenl7Bw_LdtHZtlOMAP7Kt97gDCq8WWp2605eDWhHU,1089
|
|
8
|
+
nano_dev_utils-1.0.0.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
nano_dev_utils/__init__.py,sha256=imiI367TPj5s4IFmi-VrKJLbdkIxdIPISNscthoaS9U,454
|
|
2
|
-
nano_dev_utils/dynamic_importer.py,sha256=cm2VwDYSGwhGZNO3uMX-O0LaKtEFtzkPm7BrZW4igG4,911
|
|
3
|
-
nano_dev_utils/release_ports.py,sha256=sgmoPax9Hpcse1rHbBSnDJWTkvV6aWpZ5hQFxBKhGR8,5886
|
|
4
|
-
nano_dev_utils/timers.py,sha256=IiCltOHRkYqfX_IzHQ2Xty4ptITBiaOldFO1HhQ6r_A,1748
|
|
5
|
-
nano_dev_utils-0.5.8.dist-info/METADATA,sha256=KA_vxHbiStc8At1rFrWu2Rt8G_eJzyrRLeb3tYQWfUs,5550
|
|
6
|
-
nano_dev_utils-0.5.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
7
|
-
nano_dev_utils-0.5.8.dist-info/licenses/LICENSE,sha256=Muenl7Bw_LdtHZtlOMAP7Kt97gDCq8WWp2605eDWhHU,1089
|
|
8
|
-
nano_dev_utils-0.5.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|