pyutilkit 0.3.0__tar.gz → 0.4.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyutilkit
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: python's missing batteries
5
5
  Home-page: https://pyutilkit.readthedocs.io/en/stable/
6
6
  License: LGPL-3.0+
@@ -126,7 +126,7 @@ skip_empty = true
126
126
 
127
127
  [tool.poetry]
128
128
  name = "pyutilkit"
129
- version = "0.3.0"
129
+ version = "0.4.0"
130
130
  description = "python's missing batteries"
131
131
  authors = [
132
132
  "Stephanos Kuma <stephanos@kuma.ai>",
File without changes
@@ -0,0 +1,123 @@
1
+ from __future__ import annotations # py3.9: remove this line
2
+
3
+ from dataclasses import dataclass
4
+ from time import perf_counter_ns
5
+ from types import TracebackType
6
+ from typing import TYPE_CHECKING, Any
7
+
8
+ if TYPE_CHECKING:
9
+ from typing_extensions import Self # py3.10: import Self from typing
10
+
11
+
12
+ @dataclass(frozen=True, order=True)
13
+ class Timing:
14
+ __slots__ = ("nanoseconds",) # py3.9: remove this line
15
+
16
+ nanoseconds: int
17
+
18
+ def __init__(
19
+ self,
20
+ *,
21
+ days: int = 0,
22
+ seconds: int = 0,
23
+ milliseconds: int = 0,
24
+ microseconds: int = 0,
25
+ nanoseconds: int = 0,
26
+ ) -> None:
27
+ total_nanoseconds = (
28
+ nanoseconds
29
+ + 1000 * microseconds
30
+ + 1_000_000 * milliseconds
31
+ + 1_000_000_000 * seconds
32
+ + 86_400_000_000_000 * days
33
+ )
34
+ object.__setattr__(self, "nanoseconds", total_nanoseconds)
35
+
36
+ def __str__(self) -> str:
37
+ if self.nanoseconds < 1000:
38
+ return f"{self.nanoseconds}ns"
39
+ microseconds = self.nanoseconds / 1000
40
+ if microseconds < 1000:
41
+ return f"{microseconds:.1f}µs"
42
+ milliseconds = microseconds / 1000
43
+ if milliseconds < 1000:
44
+ return f"{milliseconds:.1f}ms"
45
+ seconds = milliseconds / 1000
46
+ if seconds < 60:
47
+ return f"{seconds:.2f}s"
48
+ round_seconds = int(seconds)
49
+ minutes, seconds = divmod(round_seconds, 60)
50
+ hours, minutes = divmod(minutes, 60)
51
+ if hours < 24:
52
+ return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
53
+ days, hours = divmod(hours, 24)
54
+ return f"{days:,}d {hours:02d}:{minutes:02d}:{seconds:02d}"
55
+
56
+ def __bool__(self) -> bool:
57
+ return bool(self.nanoseconds)
58
+
59
+ def __add__(self, other: Any) -> Timing:
60
+ if not isinstance(other, Timing):
61
+ return NotImplemented
62
+ return Timing(nanoseconds=self.nanoseconds + other.nanoseconds)
63
+
64
+ def __radd__(self, other: Any) -> Timing:
65
+ if not isinstance(other, Timing):
66
+ return NotImplemented
67
+ return Timing(nanoseconds=self.nanoseconds + other.nanoseconds)
68
+
69
+ def __mul__(self, other: Any) -> Timing:
70
+ if not isinstance(other, int):
71
+ return NotImplemented
72
+ return Timing(nanoseconds=self.nanoseconds * other)
73
+
74
+ def __rmul__(self, other: Any) -> Timing:
75
+ if not isinstance(other, int):
76
+ return NotImplemented
77
+ return Timing(nanoseconds=self.nanoseconds * other)
78
+
79
+ def __floordiv__(self, other: Any) -> Timing:
80
+ if not isinstance(other, int):
81
+ return NotImplemented
82
+ return Timing(nanoseconds=self.nanoseconds // other)
83
+
84
+ def __truediv__(self, other: Any) -> Timing:
85
+ if not isinstance(other, int):
86
+ return NotImplemented
87
+ return Timing(nanoseconds=self.nanoseconds // other)
88
+
89
+
90
+ class Stopwatch:
91
+ _start: int
92
+ laps: list[Timing]
93
+
94
+ def __init__(self) -> None:
95
+ self._start = 0
96
+ self.laps: list[Timing] = []
97
+
98
+ def __enter__(self) -> Self:
99
+ self._start = perf_counter_ns()
100
+ return self
101
+
102
+ def __exit__(
103
+ self,
104
+ exc_type: type[Exception] | None,
105
+ exc_value: Exception | None,
106
+ traceback: TracebackType | None,
107
+ ) -> None:
108
+ _end = perf_counter_ns()
109
+ self.laps.append(Timing(nanoseconds=_end - self._start))
110
+
111
+ def __bool__(self) -> bool:
112
+ return bool(self.elapsed)
113
+
114
+ @property
115
+ def elapsed(self) -> Timing:
116
+ return sum(self.laps, Timing())
117
+
118
+ @property
119
+ def average(self) -> Timing:
120
+ if not self.laps:
121
+ msg = "No laps recorded"
122
+ raise ZeroDivisionError(msg)
123
+ return self.elapsed // len(self.laps)
@@ -1,68 +0,0 @@
1
- from __future__ import annotations # py3.9: remove this line
2
-
3
- from dataclasses import dataclass
4
- from time import perf_counter_ns
5
- from types import TracebackType
6
- from typing import TYPE_CHECKING
7
-
8
- if TYPE_CHECKING:
9
- from typing_extensions import Self # py3.10: import Self from typing
10
-
11
-
12
- @dataclass(frozen=True, order=True)
13
- class Timing:
14
- __slots__ = ("nanoseconds",) # py3.9: remove this line
15
-
16
- nanoseconds: int
17
-
18
- def __init__(
19
- self,
20
- *,
21
- days: int = 0,
22
- seconds: int = 0,
23
- milliseconds: int = 0,
24
- microseconds: int = 0,
25
- nanoseconds: int = 0,
26
- ) -> None:
27
- total_nanoseconds = (
28
- nanoseconds
29
- + 1000 * microseconds
30
- + 1_000_000 * milliseconds
31
- + 1_000_000_000 * seconds
32
- + 86_400_000_000_000 * days
33
- )
34
- object.__setattr__(self, "nanoseconds", total_nanoseconds)
35
-
36
- def __str__(self) -> str:
37
- if self.nanoseconds < 1000:
38
- return f"{self.nanoseconds}ns"
39
- microseconds = self.nanoseconds / 1000
40
- if microseconds < 1000:
41
- return f"{microseconds:.1f}µs"
42
- milliseconds = microseconds / 1000
43
- if milliseconds < 1000:
44
- return f"{milliseconds:.1f}ms"
45
- seconds = milliseconds / 1000
46
- return f"{seconds:,.2f}s"
47
-
48
-
49
- class Stopwatch:
50
- _start: int
51
- timing: Timing
52
-
53
- def __init__(self) -> None:
54
- self._start = 0
55
- self.timing = Timing(nanoseconds=0)
56
-
57
- def __enter__(self) -> Self:
58
- self._start = perf_counter_ns()
59
- return self
60
-
61
- def __exit__(
62
- self,
63
- exc_type: type[Exception] | None,
64
- exc_value: Exception | None,
65
- traceback: TracebackType | None,
66
- ) -> None:
67
- _end = perf_counter_ns()
68
- self.timing = Timing(nanoseconds=_end - self._start)
File without changes
File without changes