haiway 0.10.1__py3-none-any.whl → 0.10.11__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.
- haiway/context/access.py +8 -0
- haiway/context/identifier.py +18 -1
- haiway/helpers/metrics.py +24 -4
- haiway/utils/collections.py +93 -16
- {haiway-0.10.1.dist-info → haiway-0.10.11.dist-info}/METADATA +14 -15
- {haiway-0.10.1.dist-info → haiway-0.10.11.dist-info}/RECORD +8 -9
- {haiway-0.10.1.dist-info → haiway-0.10.11.dist-info}/WHEEL +1 -2
- haiway-0.10.1.dist-info/top_level.txt +0 -1
- {haiway-0.10.1.dist-info → haiway-0.10.11.dist-info/licenses}/LICENSE +0 -0
haiway/context/access.py
CHANGED
@@ -195,6 +195,14 @@ class ScopeContext:
|
|
195
195
|
|
196
196
|
@final
|
197
197
|
class ctx:
|
198
|
+
@staticmethod
|
199
|
+
def trace_id() -> str:
|
200
|
+
"""
|
201
|
+
Get the current context trace identifier.
|
202
|
+
"""
|
203
|
+
|
204
|
+
return ScopeIdentifier.current_trace_id()
|
205
|
+
|
198
206
|
@staticmethod
|
199
207
|
def scope(
|
200
208
|
label: str,
|
haiway/context/identifier.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
from contextvars import ContextVar, Token
|
2
2
|
from types import TracebackType
|
3
|
-
from typing import Self, final
|
3
|
+
from typing import Any, Self, final
|
4
4
|
from uuid import uuid4
|
5
5
|
|
6
6
|
__all__ = [
|
@@ -12,6 +12,14 @@ __all__ = [
|
|
12
12
|
class ScopeIdentifier:
|
13
13
|
_context = ContextVar[Self]("ScopeIdentifier")
|
14
14
|
|
15
|
+
@classmethod
|
16
|
+
def current_trace_id(cls) -> str:
|
17
|
+
try:
|
18
|
+
return ScopeIdentifier._context.get().trace_id
|
19
|
+
|
20
|
+
except LookupError as exc:
|
21
|
+
raise RuntimeError("Attempting to access scope identifier outside of scope") from exc
|
22
|
+
|
15
23
|
@classmethod
|
16
24
|
def scope(
|
17
25
|
cls,
|
@@ -60,6 +68,15 @@ class ScopeIdentifier:
|
|
60
68
|
def __str__(self) -> str:
|
61
69
|
return self.unique_name
|
62
70
|
|
71
|
+
def __eq__(self, other: Any) -> bool:
|
72
|
+
if not isinstance(other, self.__class__):
|
73
|
+
return False
|
74
|
+
|
75
|
+
return self.scope_id == other.scope_id and self.trace_id == other.trace_id
|
76
|
+
|
77
|
+
def __hash__(self) -> int:
|
78
|
+
return hash(self.scope_id)
|
79
|
+
|
63
80
|
def __enter__(self) -> None:
|
64
81
|
assert not hasattr(self, "_token"), "Context reentrance is not allowed" # nosec: B101
|
65
82
|
self._token: Token[ScopeIdentifier] = ScopeIdentifier._context.set(self)
|
haiway/helpers/metrics.py
CHANGED
@@ -101,6 +101,7 @@ class MetricsHolder:
|
|
101
101
|
)
|
102
102
|
|
103
103
|
def __init__(self) -> None:
|
104
|
+
self.root_scope: ScopeIdentifier | None = None
|
104
105
|
self.scopes: dict[ScopeIdentifier, MetricsScopeStore] = {}
|
105
106
|
|
106
107
|
def record(
|
@@ -109,7 +110,9 @@ class MetricsHolder:
|
|
109
110
|
/,
|
110
111
|
metric: State,
|
111
112
|
) -> None:
|
113
|
+
assert self.root_scope is not None # nosec: B101
|
112
114
|
assert scope in self.scopes # nosec: B101
|
115
|
+
|
113
116
|
metric_type: type[State] = type(metric)
|
114
117
|
metrics: dict[type[State], State] = self.scopes[scope].metrics
|
115
118
|
if (current := metrics.get(metric_type)) and hasattr(current, "__add__"):
|
@@ -125,6 +128,9 @@ class MetricsHolder:
|
|
125
128
|
metric: type[Metric],
|
126
129
|
merged: bool,
|
127
130
|
) -> Metric | None:
|
131
|
+
assert self.root_scope is not None # nosec: B101
|
132
|
+
assert scope in self.scopes # nosec: B101
|
133
|
+
|
128
134
|
if merged:
|
129
135
|
return self.scopes[scope].merged(metric)
|
130
136
|
|
@@ -139,7 +145,11 @@ class MetricsHolder:
|
|
139
145
|
assert scope not in self.scopes # nosec: B101
|
140
146
|
scope_metrics = MetricsScopeStore(scope)
|
141
147
|
self.scopes[scope] = scope_metrics
|
142
|
-
|
148
|
+
|
149
|
+
if self.root_scope is None:
|
150
|
+
self.root_scope = scope
|
151
|
+
|
152
|
+
else:
|
143
153
|
for key in self.scopes.keys():
|
144
154
|
if key.scope_id == scope.parent_id:
|
145
155
|
self.scopes[key].nested.append(scope_metrics)
|
@@ -182,9 +192,10 @@ class MetricsLogger:
|
|
182
192
|
items_limit: int | None,
|
183
193
|
redact_content: bool,
|
184
194
|
) -> None:
|
195
|
+
self.root_scope: ScopeIdentifier | None = None
|
196
|
+
self.scopes: dict[ScopeIdentifier, MetricsScopeStore] = {}
|
185
197
|
self.items_limit: int | None = items_limit
|
186
198
|
self.redact_content: bool = redact_content
|
187
|
-
self.scopes: dict[ScopeIdentifier, MetricsScopeStore] = {}
|
188
199
|
|
189
200
|
def record(
|
190
201
|
self,
|
@@ -192,7 +203,9 @@ class MetricsLogger:
|
|
192
203
|
/,
|
193
204
|
metric: State,
|
194
205
|
) -> None:
|
206
|
+
assert self.root_scope is not None # nosec: B101
|
195
207
|
assert scope in self.scopes # nosec: B101
|
208
|
+
|
196
209
|
metric_type: type[State] = type(metric)
|
197
210
|
metrics: dict[type[State], State] = self.scopes[scope].metrics
|
198
211
|
if (current := metrics.get(metric_type)) and hasattr(current, "__add__"):
|
@@ -214,6 +227,9 @@ class MetricsLogger:
|
|
214
227
|
metric: type[Metric],
|
215
228
|
merged: bool,
|
216
229
|
) -> Metric | None:
|
230
|
+
assert self.root_scope is not None # nosec: B101
|
231
|
+
assert scope in self.scopes # nosec: B101
|
232
|
+
|
217
233
|
if merged:
|
218
234
|
return self.scopes[scope].merged(metric)
|
219
235
|
|
@@ -228,7 +244,11 @@ class MetricsLogger:
|
|
228
244
|
assert scope not in self.scopes # nosec: B101
|
229
245
|
scope_metrics = MetricsScopeStore(scope)
|
230
246
|
self.scopes[scope] = scope_metrics
|
231
|
-
|
247
|
+
|
248
|
+
if self.root_scope is None:
|
249
|
+
self.root_scope = scope
|
250
|
+
|
251
|
+
else:
|
232
252
|
for key in self.scopes.keys():
|
233
253
|
if key.scope_id == scope.parent_id:
|
234
254
|
self.scopes[key].nested.append(scope_metrics)
|
@@ -246,7 +266,7 @@ class MetricsLogger:
|
|
246
266
|
assert scope in self.scopes # nosec: B101
|
247
267
|
self.scopes[scope].exited = monotonic()
|
248
268
|
|
249
|
-
if scope.
|
269
|
+
if scope == self.root_scope and self.scopes[scope].finished:
|
250
270
|
if log := _tree_log(
|
251
271
|
self.scopes[scope],
|
252
272
|
list_items_limit=self.items_limit,
|
haiway/utils/collections.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
from collections.abc import Mapping, Sequence, Set
|
2
|
+
from typing import overload
|
2
3
|
|
3
4
|
__all__ = [
|
4
5
|
"as_dict",
|
@@ -8,24 +9,43 @@ __all__ = [
|
|
8
9
|
]
|
9
10
|
|
10
11
|
|
12
|
+
@overload
|
11
13
|
def as_list[T](
|
12
14
|
collection: Sequence[T],
|
13
15
|
/,
|
14
|
-
) -> list[T]:
|
16
|
+
) -> list[T]: ...
|
17
|
+
|
18
|
+
|
19
|
+
@overload
|
20
|
+
def as_list[T](
|
21
|
+
collection: Sequence[T] | None,
|
22
|
+
/,
|
23
|
+
) -> list[T] | None: ...
|
24
|
+
|
25
|
+
|
26
|
+
def as_list[T](
|
27
|
+
collection: Sequence[T] | None,
|
28
|
+
/,
|
29
|
+
) -> list[T] | None:
|
15
30
|
"""
|
16
31
|
Converts any given Sequence into a list.
|
17
32
|
|
18
33
|
Parameters
|
19
34
|
----------
|
20
|
-
collection : Sequence[T]
|
35
|
+
collection : Sequence[T] | None
|
21
36
|
The input collection to be converted.
|
22
37
|
|
23
38
|
Returns
|
24
39
|
-------
|
25
|
-
list[T]
|
26
|
-
A new list containing all elements of the input collection
|
27
|
-
|
40
|
+
list[T] | None
|
41
|
+
A new list containing all elements of the input collection,\
|
42
|
+
or the original list if it was already one.
|
43
|
+
None if no value was provided.
|
28
44
|
"""
|
45
|
+
|
46
|
+
if collection is None:
|
47
|
+
return None
|
48
|
+
|
29
49
|
if isinstance(collection, list):
|
30
50
|
return collection
|
31
51
|
|
@@ -33,24 +53,43 @@ def as_list[T](
|
|
33
53
|
return list(collection)
|
34
54
|
|
35
55
|
|
56
|
+
@overload
|
36
57
|
def as_tuple[T](
|
37
58
|
collection: Sequence[T],
|
38
59
|
/,
|
39
|
-
) -> tuple[T, ...]:
|
60
|
+
) -> tuple[T, ...]: ...
|
61
|
+
|
62
|
+
|
63
|
+
@overload
|
64
|
+
def as_tuple[T](
|
65
|
+
collection: Sequence[T] | None,
|
66
|
+
/,
|
67
|
+
) -> tuple[T, ...] | None: ...
|
68
|
+
|
69
|
+
|
70
|
+
def as_tuple[T](
|
71
|
+
collection: Sequence[T] | None,
|
72
|
+
/,
|
73
|
+
) -> tuple[T, ...] | None:
|
40
74
|
"""
|
41
75
|
Converts any given Sequence into a tuple.
|
42
76
|
|
43
77
|
Parameters
|
44
78
|
----------
|
45
|
-
collection : Sequence[T]
|
79
|
+
collection : Sequence[T] | None
|
46
80
|
The input collection to be converted.
|
47
81
|
|
48
82
|
Returns
|
49
83
|
-------
|
50
|
-
tuple[T]
|
51
|
-
A new tuple containing all elements of the input collection
|
52
|
-
|
84
|
+
tuple[T] | None
|
85
|
+
A new tuple containing all elements of the input collection,\
|
86
|
+
or the original tuple if it was already one.
|
87
|
+
None if no value was provided.
|
53
88
|
"""
|
89
|
+
|
90
|
+
if collection is None:
|
91
|
+
return None
|
92
|
+
|
54
93
|
if isinstance(collection, tuple):
|
55
94
|
return collection
|
56
95
|
|
@@ -58,10 +97,24 @@ def as_tuple[T](
|
|
58
97
|
return tuple(collection)
|
59
98
|
|
60
99
|
|
100
|
+
@overload
|
61
101
|
def as_set[T](
|
62
102
|
collection: Set[T],
|
63
103
|
/,
|
64
|
-
) -> set[T]:
|
104
|
+
) -> set[T]: ...
|
105
|
+
|
106
|
+
|
107
|
+
@overload
|
108
|
+
def as_set[T](
|
109
|
+
collection: Set[T] | None,
|
110
|
+
/,
|
111
|
+
) -> set[T] | None: ...
|
112
|
+
|
113
|
+
|
114
|
+
def as_set[T](
|
115
|
+
collection: Set[T] | None,
|
116
|
+
/,
|
117
|
+
) -> set[T] | None:
|
65
118
|
"""
|
66
119
|
Converts any given Set into a set.
|
67
120
|
|
@@ -73,9 +126,14 @@ def as_set[T](
|
|
73
126
|
Returns
|
74
127
|
-------
|
75
128
|
set[T]
|
76
|
-
A new set containing all elements of the input collection
|
77
|
-
|
129
|
+
A new set containing all elements of the input collection,\
|
130
|
+
or the original set if it was already one.
|
131
|
+
None if no value was provided.
|
78
132
|
"""
|
133
|
+
|
134
|
+
if collection is None:
|
135
|
+
return None
|
136
|
+
|
79
137
|
if isinstance(collection, set):
|
80
138
|
return collection
|
81
139
|
|
@@ -83,10 +141,24 @@ def as_set[T](
|
|
83
141
|
return set(collection)
|
84
142
|
|
85
143
|
|
144
|
+
@overload
|
86
145
|
def as_dict[K, V](
|
87
146
|
collection: Mapping[K, V],
|
88
147
|
/,
|
89
|
-
) -> dict[K, V]:
|
148
|
+
) -> dict[K, V]: ...
|
149
|
+
|
150
|
+
|
151
|
+
@overload
|
152
|
+
def as_dict[K, V](
|
153
|
+
collection: Mapping[K, V] | None,
|
154
|
+
/,
|
155
|
+
) -> dict[K, V] | None: ...
|
156
|
+
|
157
|
+
|
158
|
+
def as_dict[K, V](
|
159
|
+
collection: Mapping[K, V] | None,
|
160
|
+
/,
|
161
|
+
) -> dict[K, V] | None:
|
90
162
|
"""
|
91
163
|
Converts any given Mapping into a dict.
|
92
164
|
|
@@ -98,9 +170,14 @@ def as_dict[K, V](
|
|
98
170
|
Returns
|
99
171
|
-------
|
100
172
|
dict[K, V]
|
101
|
-
A new dict containing all elements of the input collection
|
102
|
-
|
173
|
+
A new dict containing all elements of the input collection,\
|
174
|
+
or the original dict if it was already one.
|
175
|
+
None if no value was provided.
|
103
176
|
"""
|
177
|
+
|
178
|
+
if collection is None:
|
179
|
+
return None
|
180
|
+
|
104
181
|
if isinstance(collection, dict):
|
105
182
|
return collection
|
106
183
|
|
@@ -1,7 +1,9 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: haiway
|
3
|
-
Version: 0.10.
|
3
|
+
Version: 0.10.11
|
4
4
|
Summary: Framework for dependency injection and state management within structured concurrency model.
|
5
|
+
Project-URL: Homepage, https://miquido.com
|
6
|
+
Project-URL: Repository, https://github.com/miquido/haiway.git
|
5
7
|
Maintainer-email: Kacper Kaliński <kacper.kalinski@miquido.com>
|
6
8
|
License: MIT License
|
7
9
|
|
@@ -24,25 +26,22 @@ License: MIT License
|
|
24
26
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
25
27
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
26
28
|
SOFTWARE.
|
27
|
-
|
28
|
-
Project-URL: Repository, https://github.com/miquido/haiway.git
|
29
|
-
Classifier: License :: OSI Approved :: MIT License
|
29
|
+
License-File: LICENSE
|
30
30
|
Classifier: Intended Audience :: Developers
|
31
|
+
Classifier: License :: OSI Approved :: MIT License
|
31
32
|
Classifier: Programming Language :: Python
|
32
|
-
Classifier: Typing :: Typed
|
33
33
|
Classifier: Topic :: Software Development
|
34
34
|
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
35
|
+
Classifier: Typing :: Typed
|
35
36
|
Requires-Python: >=3.12
|
36
|
-
Description-Content-Type: text/markdown
|
37
|
-
License-File: LICENSE
|
38
37
|
Provides-Extra: dev
|
39
|
-
Requires-Dist:
|
40
|
-
Requires-Dist:
|
41
|
-
Requires-Dist:
|
42
|
-
Requires-Dist:
|
43
|
-
Requires-Dist: pytest~=7.4; extra ==
|
44
|
-
Requires-Dist:
|
45
|
-
|
38
|
+
Requires-Dist: bandit~=1.7; extra == 'dev'
|
39
|
+
Requires-Dist: pyright~=1.1; extra == 'dev'
|
40
|
+
Requires-Dist: pytest-asyncio~=0.23; extra == 'dev'
|
41
|
+
Requires-Dist: pytest-cov~=4.1; extra == 'dev'
|
42
|
+
Requires-Dist: pytest~=7.4; extra == 'dev'
|
43
|
+
Requires-Dist: ruff~=0.9; extra == 'dev'
|
44
|
+
Description-Content-Type: text/markdown
|
46
45
|
|
47
46
|
# 🚗 haiway 🚕 🚚 🚙
|
48
47
|
|
@@ -1,9 +1,9 @@
|
|
1
1
|
haiway/__init__.py,sha256=IEUCyFYKT5IPHnkiUvDVZHdJeHqCaBnG8FhPD20Zgo8,1929
|
2
2
|
haiway/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
3
|
haiway/context/__init__.py,sha256=eRvuhifx7xCd-_6desgk55idzNpD5S5sprmCfGb3_9M,662
|
4
|
-
haiway/context/access.py,sha256=
|
4
|
+
haiway/context/access.py,sha256=Fc2NfoIV2zWE5qPnNgSitK1dy-PME-rJJfUPhoNwJzY,17125
|
5
5
|
haiway/context/disposables.py,sha256=DZjnMp-wMfF-em2Wjhbm1MvXubNpuzFBT70BQNIxC7M,2019
|
6
|
-
haiway/context/identifier.py,sha256=
|
6
|
+
haiway/context/identifier.py,sha256=Fyb6OHx5FPaSLLRK249HUEr_KlBSG5F-eW01Oxg_Ke8,2570
|
7
7
|
haiway/context/logging.py,sha256=ptwgENuyw-WFgokVsYx9OXZGhJENuO_wgfVjcBryUKM,4251
|
8
8
|
haiway/context/metrics.py,sha256=Ve628X39u0rdLm0vYmVZt7aGeoEeRquR6f67vJIXClY,4213
|
9
9
|
haiway/context/state.py,sha256=LCcFxXqDBu6prvPyPicN-ecONSNHyR56PfQ5u5jNFCU,3000
|
@@ -12,7 +12,7 @@ haiway/context/types.py,sha256=VvJA7wAPZ3ISpgyThVguioYUXqhHf0XkPfRd0M1ERiQ,142
|
|
12
12
|
haiway/helpers/__init__.py,sha256=8XRJWNhidWuBKqRZ1Hyc2xqt7DeWLcoOs2V-oexl8VY,579
|
13
13
|
haiway/helpers/asynchrony.py,sha256=9lo9wT3G0TyPb4vfmTnWGBvB_eN6p6nIlj46_9Ag8fQ,6022
|
14
14
|
haiway/helpers/caching.py,sha256=Ok_WE5Whe7XqnIuLZo4rNNBFeWap-aUWX799s4b1JAQ,9536
|
15
|
-
haiway/helpers/metrics.py,sha256=
|
15
|
+
haiway/helpers/metrics.py,sha256=0oFBiO-hAzihyC5jvXevNrYOoTcUGc2yGhE1A_866Mc,13314
|
16
16
|
haiway/helpers/retries.py,sha256=gIkyUlqJLDYaxIZd3qzeqGFY9y5Gp8dgZLlZ6hs8hoc,7538
|
17
17
|
haiway/helpers/throttling.py,sha256=zo0OwFq64si5KUwhd58cFHLmGAmYwRbFRJMbv9suhPs,3844
|
18
18
|
haiway/helpers/timeouted.py,sha256=1xU09hQnFdj6p48BwZl5xUvtIr3zC0ZUXehkdrduCjs,3074
|
@@ -29,15 +29,14 @@ haiway/types/frozen.py,sha256=CZhFCXnWAKEhuWSfILxA8smfdpMd5Ku694ycfLh98R8,76
|
|
29
29
|
haiway/types/missing.py,sha256=rDnyA2wxPkTbJl0L-zbo0owp7IJ04xkCIp6xD6wh8NI,1712
|
30
30
|
haiway/utils/__init__.py,sha256=O7qmAmUktX-X_5D1L5FJMeCFEiOVrrnyYSyiycm4nyg,739
|
31
31
|
haiway/utils/always.py,sha256=2abp8Lm9rQkrfS3rm1Iqhb-IcWyVfH1BULab3KMxgOw,1234
|
32
|
-
haiway/utils/collections.py,sha256=
|
32
|
+
haiway/utils/collections.py,sha256=pKHZhXqTMcOth7gV6mXcC5WcSyBl70MmVIELbDSmMoA,3320
|
33
33
|
haiway/utils/env.py,sha256=vlW21LEp8uOVNnUXpBfPtj3zKi9Kkjoemb_H5hQpYPQ,4433
|
34
34
|
haiway/utils/freezing.py,sha256=K34ZIMzbkpgkHKH-KF73plEbXExsajNRkRTYp9nJEf4,620
|
35
35
|
haiway/utils/logs.py,sha256=oDsc1ZdqKDjlTlctLbDcp9iX98Acr-1tdw-Pyg3DElo,1577
|
36
36
|
haiway/utils/mimic.py,sha256=BkVjTVP2TxxC8GChPGyDV6UXVwJmiRiSWeOYZNZFHxs,1828
|
37
37
|
haiway/utils/noop.py,sha256=qgbZlOKWY6_23Zs43OLukK2HagIQKRyR04zrFVm5rWI,344
|
38
38
|
haiway/utils/queue.py,sha256=oQ3GXCJ-PGNtMEr6EPdgqAvYZoj8lAa7Z2drBKBEoBM,2345
|
39
|
-
haiway-0.10.
|
40
|
-
haiway-0.10.
|
41
|
-
haiway-0.10.
|
42
|
-
haiway-0.10.
|
43
|
-
haiway-0.10.1.dist-info/RECORD,,
|
39
|
+
haiway-0.10.11.dist-info/METADATA,sha256=Xz9EVwzVcqiYBNaDv0QZQ4gXv3482M9eV9n82ba6kJo,3858
|
40
|
+
haiway-0.10.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
41
|
+
haiway-0.10.11.dist-info/licenses/LICENSE,sha256=GehQEW_I1pkmxkkj3NEa7rCTQKYBn7vTPabpDYJlRuo,1063
|
42
|
+
haiway-0.10.11.dist-info/RECORD,,
|
@@ -1 +0,0 @@
|
|
1
|
-
haiway
|
File without changes
|