haiway 0.2.0__py3-none-any.whl → 0.3.1__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/__init__.py +3 -1
- haiway/context/__init__.py +3 -0
- haiway/context/access.py +79 -23
- haiway/{helpers → context}/disposables.py +3 -0
- haiway/helpers/__init__.py +2 -5
- haiway/helpers/{asynchronous.py → asynchrony.py} +12 -28
- haiway/types/missing.py +3 -3
- {haiway-0.2.0.dist-info → haiway-0.3.1.dist-info}/METADATA +1 -1
- {haiway-0.2.0.dist-info → haiway-0.3.1.dist-info}/RECORD +13 -13
- /haiway/helpers/{cached.py → caching.py} +0 -0
- {haiway-0.2.0.dist-info → haiway-0.3.1.dist-info}/LICENSE +0 -0
- {haiway-0.2.0.dist-info → haiway-0.3.1.dist-info}/WHEEL +0 -0
- {haiway-0.2.0.dist-info → haiway-0.3.1.dist-info}/top_level.txt +0 -0
haiway/__init__.py
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
from haiway.context import (
|
2
|
+
Disposable,
|
3
|
+
Disposables,
|
2
4
|
MissingContext,
|
3
5
|
MissingState,
|
4
6
|
ScopeMetrics,
|
5
7
|
ctx,
|
6
8
|
)
|
7
|
-
from haiway.helpers import
|
9
|
+
from haiway.helpers import asynchronous, cache, retry, throttle, timeout
|
8
10
|
from haiway.state import State
|
9
11
|
from haiway.types import (
|
10
12
|
MISSING,
|
haiway/context/__init__.py
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
from haiway.context.access import ctx
|
2
|
+
from haiway.context.disposables import Disposable, Disposables
|
2
3
|
from haiway.context.metrics import ScopeMetrics
|
3
4
|
from haiway.context.types import MissingContext, MissingState
|
4
5
|
|
5
6
|
__all__ = [
|
6
7
|
"ctx",
|
8
|
+
"Disposable",
|
9
|
+
"Disposables",
|
7
10
|
"MissingContext",
|
8
11
|
"MissingState",
|
9
12
|
"ScopeMetrics",
|
haiway/context/access.py
CHANGED
@@ -5,11 +5,13 @@ from asyncio import (
|
|
5
5
|
from collections.abc import (
|
6
6
|
Callable,
|
7
7
|
Coroutine,
|
8
|
+
Iterable,
|
8
9
|
)
|
9
10
|
from logging import Logger
|
10
11
|
from types import TracebackType
|
11
12
|
from typing import Any, final
|
12
13
|
|
14
|
+
from haiway.context.disposables import Disposable, Disposables
|
13
15
|
from haiway.context.metrics import MetricsContext, ScopeMetrics
|
14
16
|
from haiway.context.state import StateContext
|
15
17
|
from haiway.context.tasks import TaskGroupContext
|
@@ -23,25 +25,41 @@ __all__ = [
|
|
23
25
|
|
24
26
|
@final
|
25
27
|
class ScopeContext:
|
26
|
-
def __init__(
|
28
|
+
def __init__( # noqa: PLR0913
|
27
29
|
self,
|
30
|
+
trace_id: str | None,
|
31
|
+
name: str,
|
32
|
+
logger: Logger | None,
|
33
|
+
state: tuple[State, ...],
|
34
|
+
disposables: Disposables | None,
|
28
35
|
task_group: TaskGroupContext,
|
29
|
-
state: StateContext,
|
30
|
-
metrics: MetricsContext,
|
31
36
|
completion: Callable[[ScopeMetrics], Coroutine[None, None, None]] | None,
|
32
37
|
) -> None:
|
33
38
|
self._task_group: TaskGroupContext = task_group
|
34
|
-
self.
|
35
|
-
self.
|
39
|
+
self._logger: Logger | None = logger
|
40
|
+
self._trace_id: str | None = trace_id
|
41
|
+
self._name: str = name
|
42
|
+
self._state_context: StateContext
|
43
|
+
self._state: tuple[State, ...] = state
|
44
|
+
self._disposables: Disposables | None = disposables
|
45
|
+
self._metrics_context: MetricsContext
|
36
46
|
self._completion: Callable[[ScopeMetrics], Coroutine[None, None, None]] | None = completion
|
37
47
|
|
38
48
|
freeze(self)
|
39
49
|
|
40
50
|
def __enter__(self) -> None:
|
41
51
|
assert self._completion is None, "Can't enter synchronous context with completion" # nosec: B101
|
52
|
+
assert self._disposables is None, "Can't enter synchronous context with disposables" # nosec: B101
|
53
|
+
|
54
|
+
self._state_context = StateContext.updated(self._state)
|
55
|
+
self._metrics_context = MetricsContext.scope(
|
56
|
+
self._name,
|
57
|
+
logger=self._logger,
|
58
|
+
trace_id=self._trace_id,
|
59
|
+
)
|
42
60
|
|
43
|
-
self.
|
44
|
-
self.
|
61
|
+
self._state_context.__enter__()
|
62
|
+
self._metrics_context.__enter__()
|
45
63
|
|
46
64
|
def __exit__(
|
47
65
|
self,
|
@@ -49,49 +67,71 @@ class ScopeContext:
|
|
49
67
|
exc_val: BaseException | None,
|
50
68
|
exc_tb: TracebackType | None,
|
51
69
|
) -> None:
|
52
|
-
self.
|
70
|
+
self._metrics_context.__exit__(
|
53
71
|
exc_type=exc_type,
|
54
72
|
exc_val=exc_val,
|
55
73
|
exc_tb=exc_tb,
|
56
74
|
)
|
57
75
|
|
58
|
-
self.
|
76
|
+
self._state_context.__exit__(
|
59
77
|
exc_type=exc_type,
|
60
78
|
exc_val=exc_val,
|
61
79
|
exc_tb=exc_tb,
|
62
80
|
)
|
63
81
|
|
64
82
|
async def __aenter__(self) -> None:
|
65
|
-
self._state.__enter__()
|
66
|
-
self._metrics.__enter__()
|
67
83
|
await self._task_group.__aenter__()
|
68
84
|
|
85
|
+
if self._disposables:
|
86
|
+
self._state_context = StateContext.updated(
|
87
|
+
(*self._state, *await self._disposables.__aenter__())
|
88
|
+
)
|
89
|
+
|
90
|
+
else:
|
91
|
+
self._state_context = StateContext.updated(self._state)
|
92
|
+
|
93
|
+
self._metrics_context = MetricsContext.scope(
|
94
|
+
self._name,
|
95
|
+
logger=self._logger,
|
96
|
+
trace_id=self._trace_id,
|
97
|
+
)
|
98
|
+
|
99
|
+
self._state_context.__enter__()
|
100
|
+
self._metrics_context.__enter__()
|
101
|
+
|
69
102
|
async def __aexit__(
|
70
103
|
self,
|
71
104
|
exc_type: type[BaseException] | None,
|
72
105
|
exc_val: BaseException | None,
|
73
106
|
exc_tb: TracebackType | None,
|
74
107
|
) -> None:
|
108
|
+
if self._disposables:
|
109
|
+
await self._disposables.__aexit__(
|
110
|
+
exc_type=exc_type,
|
111
|
+
exc_val=exc_val,
|
112
|
+
exc_tb=exc_tb,
|
113
|
+
)
|
114
|
+
|
75
115
|
await self._task_group.__aexit__(
|
76
116
|
exc_type=exc_type,
|
77
117
|
exc_val=exc_val,
|
78
118
|
exc_tb=exc_tb,
|
79
119
|
)
|
80
120
|
|
81
|
-
self.
|
121
|
+
self._metrics_context.__exit__(
|
82
122
|
exc_type=exc_type,
|
83
123
|
exc_val=exc_val,
|
84
124
|
exc_tb=exc_tb,
|
85
125
|
)
|
86
126
|
|
87
|
-
self.
|
127
|
+
self._state_context.__exit__(
|
88
128
|
exc_type=exc_type,
|
89
129
|
exc_val=exc_val,
|
90
130
|
exc_tb=exc_tb,
|
91
131
|
)
|
92
132
|
|
93
133
|
if completion := self._completion:
|
94
|
-
await completion(self.
|
134
|
+
await completion(self._metrics_context._metrics) # pyright: ignore[reportPrivateUsage]
|
95
135
|
|
96
136
|
|
97
137
|
@final
|
@@ -101,6 +141,7 @@ class ctx:
|
|
101
141
|
name: str,
|
102
142
|
/,
|
103
143
|
*state: State,
|
144
|
+
disposables: Disposables | Iterable[Disposable] | None = None,
|
104
145
|
logger: Logger | None = None,
|
105
146
|
trace_id: str | None = None,
|
106
147
|
completion: Callable[[ScopeMetrics], Coroutine[None, None, None]] | None = None,
|
@@ -114,9 +155,14 @@ class ctx:
|
|
114
155
|
name: Value
|
115
156
|
name of the scope context
|
116
157
|
|
117
|
-
*state: State
|
118
|
-
state propagated within the scope context, will be merged with current
|
119
|
-
|
158
|
+
*state: State | Disposable
|
159
|
+
state propagated within the scope context, will be merged with current state by\
|
160
|
+
replacing current with provided on conflict.
|
161
|
+
|
162
|
+
disposables: Disposables | list[Disposable] | None
|
163
|
+
disposables consumed within the context when entered. Produced state will automatically\
|
164
|
+
be added to the scope state. Using asynchronous context is required if any disposables\
|
165
|
+
were provided.
|
120
166
|
|
121
167
|
logger: Logger | None
|
122
168
|
logger used within the scope context, when not provided current logger will be used\
|
@@ -138,14 +184,24 @@ class ctx:
|
|
138
184
|
context object intended to enter context manager with it
|
139
185
|
"""
|
140
186
|
|
187
|
+
resolved_disposables: Disposables | None
|
188
|
+
match disposables:
|
189
|
+
case None:
|
190
|
+
resolved_disposables = None
|
191
|
+
|
192
|
+
case Disposables() as disposables:
|
193
|
+
resolved_disposables = disposables
|
194
|
+
|
195
|
+
case iterable:
|
196
|
+
resolved_disposables = Disposables(*iterable)
|
197
|
+
|
141
198
|
return ScopeContext(
|
199
|
+
trace_id=trace_id,
|
200
|
+
name=name,
|
201
|
+
logger=logger,
|
202
|
+
state=state,
|
203
|
+
disposables=resolved_disposables,
|
142
204
|
task_group=TaskGroupContext(),
|
143
|
-
metrics=MetricsContext.scope(
|
144
|
-
name,
|
145
|
-
logger=logger,
|
146
|
-
trace_id=trace_id,
|
147
|
-
),
|
148
|
-
state=StateContext.updated(state),
|
149
205
|
completion=completion,
|
150
206
|
)
|
151
207
|
|
haiway/helpers/__init__.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1
|
-
from haiway.helpers.
|
2
|
-
from haiway.helpers.
|
3
|
-
from haiway.helpers.disposables import Disposable, Disposables
|
1
|
+
from haiway.helpers.asynchrony import asynchronous
|
2
|
+
from haiway.helpers.caching import cache
|
4
3
|
from haiway.helpers.retries import retry
|
5
4
|
from haiway.helpers.throttling import throttle
|
6
5
|
from haiway.helpers.timeouted import timeout
|
@@ -8,8 +7,6 @@ from haiway.helpers.timeouted import timeout
|
|
8
7
|
__all__ = [
|
9
8
|
"asynchronous",
|
10
9
|
"cache",
|
11
|
-
"Disposable",
|
12
|
-
"Disposables",
|
13
10
|
"retry",
|
14
11
|
"throttle",
|
15
12
|
"timeout",
|
@@ -3,9 +3,9 @@ from collections.abc import Callable, Coroutine
|
|
3
3
|
from concurrent.futures import Executor
|
4
4
|
from contextvars import Context, copy_context
|
5
5
|
from functools import partial
|
6
|
-
from typing import Any,
|
6
|
+
from typing import Any, cast, overload
|
7
7
|
|
8
|
-
from haiway.types.missing import MISSING, Missing
|
8
|
+
from haiway.types.missing import MISSING, Missing
|
9
9
|
|
10
10
|
__all__ = [
|
11
11
|
"asynchronous",
|
@@ -25,7 +25,7 @@ def asynchronous[**Args, Result]() -> (
|
|
25
25
|
def asynchronous[**Args, Result](
|
26
26
|
*,
|
27
27
|
loop: AbstractEventLoop | None = None,
|
28
|
-
executor: Executor
|
28
|
+
executor: Executor,
|
29
29
|
) -> Callable[
|
30
30
|
[Callable[Args, Result]],
|
31
31
|
Callable[Args, Coroutine[None, None, Result]],
|
@@ -43,7 +43,7 @@ def asynchronous[**Args, Result](
|
|
43
43
|
function: Callable[Args, Result] | None = None,
|
44
44
|
/,
|
45
45
|
loop: AbstractEventLoop | None = None,
|
46
|
-
executor: Executor |
|
46
|
+
executor: Executor | Missing = MISSING,
|
47
47
|
) -> (
|
48
48
|
Callable[
|
49
49
|
[Callable[Args, Result]],
|
@@ -63,10 +63,9 @@ def asynchronous[**Args, Result](
|
|
63
63
|
loop: AbstractEventLoop | None
|
64
64
|
loop used to call the function. When None was provided the loop currently running while \
|
65
65
|
executing the function will be used. Default is None.
|
66
|
-
executor: Executor |
|
67
|
-
executor used to run the function.
|
68
|
-
|
69
|
-
(function will by just wrapped as an async function without any executor)
|
66
|
+
executor: Executor | Missing
|
67
|
+
executor used to run the function. When not provided (Missing) default loop executor\
|
68
|
+
will be used.
|
70
69
|
|
71
70
|
Returns
|
72
71
|
-------
|
@@ -79,26 +78,11 @@ def asynchronous[**Args, Result](
|
|
79
78
|
) -> Callable[Args, Coroutine[None, None, Result]]:
|
80
79
|
assert not iscoroutinefunction(wrapped), "Cannot wrap async function in executor" # nosec: B101
|
81
80
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
)
|
88
|
-
|
89
|
-
else:
|
90
|
-
|
91
|
-
async def wrapper(
|
92
|
-
*args: Args.args,
|
93
|
-
**kwargs: Args.kwargs,
|
94
|
-
) -> Result:
|
95
|
-
return wrapped(
|
96
|
-
*args,
|
97
|
-
**kwargs,
|
98
|
-
)
|
99
|
-
|
100
|
-
_mimic_async(wrapped, within=wrapper)
|
101
|
-
return wrapper
|
81
|
+
return _ExecutorWrapper(
|
82
|
+
wrapped,
|
83
|
+
loop=loop,
|
84
|
+
executor=cast(Executor | None, None if executor is MISSING else executor),
|
85
|
+
)
|
102
86
|
|
103
87
|
if function := function:
|
104
88
|
return wrap(wrapped=function)
|
haiway/types/missing.py
CHANGED
@@ -46,20 +46,20 @@ class Missing(metaclass=MissingType):
|
|
46
46
|
self,
|
47
47
|
name: str,
|
48
48
|
) -> Any:
|
49
|
-
raise
|
49
|
+
raise AttributeError("Missing has no attributes")
|
50
50
|
|
51
51
|
def __setattr__(
|
52
52
|
self,
|
53
53
|
__name: str,
|
54
54
|
__value: Any,
|
55
55
|
) -> None:
|
56
|
-
raise
|
56
|
+
raise AttributeError("Missing can't be modified")
|
57
57
|
|
58
58
|
def __delattr__(
|
59
59
|
self,
|
60
60
|
__name: str,
|
61
61
|
) -> None:
|
62
|
-
raise
|
62
|
+
raise AttributeError("Missing can't be modified")
|
63
63
|
|
64
64
|
|
65
65
|
MISSING: Final[Missing] = Missing()
|
@@ -1,15 +1,15 @@
|
|
1
|
-
haiway/__init__.py,sha256=
|
1
|
+
haiway/__init__.py,sha256=tjFQ9bVnUHs2BMyCPxeNYxqHtqyIZQDk1Wk2nFB_G2U,1138
|
2
2
|
haiway/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
-
haiway/context/__init__.py,sha256=
|
4
|
-
haiway/context/access.py,sha256=
|
3
|
+
haiway/context/__init__.py,sha256=21Y3zvRo1bHASZD6B_FNkU28k1-g88RdmUyqxvYXJxg,336
|
4
|
+
haiway/context/access.py,sha256=E9aIC1RUupKk2LXik5qb13oHpW2s_tNQC0UxGcO9xr0,12761
|
5
|
+
haiway/context/disposables.py,sha256=VQX9jVo1pjqkmOYzWpsbYyF45y0XtpjorIIaeMBCwTU,1771
|
5
6
|
haiway/context/metrics.py,sha256=upkqUp47NymDJE8UQznr99AgaE9yw6i28l_cdCE1IeM,8612
|
6
7
|
haiway/context/state.py,sha256=GxGwPQTK8FdSprBd83lQbA9veubp0o93_1Yk3gb7HMc,3000
|
7
8
|
haiway/context/tasks.py,sha256=xXtXIUwXOra0EePTdkcEbMOmpWwFcO3hCRfR_IfvAHk,1978
|
8
9
|
haiway/context/types.py,sha256=VvJA7wAPZ3ISpgyThVguioYUXqhHf0XkPfRd0M1ERiQ,142
|
9
|
-
haiway/helpers/__init__.py,sha256=
|
10
|
-
haiway/helpers/
|
11
|
-
haiway/helpers/
|
12
|
-
haiway/helpers/disposables.py,sha256=zygeghLaQF77orawLpOjUOKKCsN1S5CwwVrNtS7A5G0,1696
|
10
|
+
haiway/helpers/__init__.py,sha256=mXTpvTqRqmKiCE2ZHKDgSo8i9gRbEWGw-Qj2a_M0sD4,317
|
11
|
+
haiway/helpers/asynchrony.py,sha256=FPqmFFRDtAn8migwYHFKViKHypNHZW3cJCrh9y03AwI,5526
|
12
|
+
haiway/helpers/caching.py,sha256=Ok_WE5Whe7XqnIuLZo4rNNBFeWap-aUWX799s4b1JAQ,9536
|
13
13
|
haiway/helpers/retries.py,sha256=gIkyUlqJLDYaxIZd3qzeqGFY9y5Gp8dgZLlZ6hs8hoc,7538
|
14
14
|
haiway/helpers/throttling.py,sha256=zo0OwFq64si5KUwhd58cFHLmGAmYwRbFRJMbv9suhPs,3844
|
15
15
|
haiway/helpers/timeouted.py,sha256=1xU09hQnFdj6p48BwZl5xUvtIr3zC0ZUXehkdrduCjs,3074
|
@@ -19,7 +19,7 @@ haiway/state/structure.py,sha256=G-Ln72hoQtE0FmKHeZdNmXf_FA3f5-e5AGbmJ2yMNb4,700
|
|
19
19
|
haiway/state/validation.py,sha256=V4Q94Ik4p9t7f-7EIwK3Q9Zki8VkLOjPIGWGwLRVCoc,2873
|
20
20
|
haiway/types/__init__.py,sha256=cAJQzDgFi8AKRqpzY3HWrutaPR69tnJqeJK_mQVtYUk,252
|
21
21
|
haiway/types/frozen.py,sha256=CZhFCXnWAKEhuWSfILxA8smfdpMd5Ku694ycfLh98R8,76
|
22
|
-
haiway/types/missing.py,sha256=
|
22
|
+
haiway/types/missing.py,sha256=xR5Hzk134_htlfac4OBWg6Xkobu71hF9CSVA3qeHBYY,1666
|
23
23
|
haiway/utils/__init__.py,sha256=UA9h8YDvYI5rYujvsIS9t5Q-SWYImmk30uhR_42flqs,608
|
24
24
|
haiway/utils/always.py,sha256=2abp8Lm9rQkrfS3rm1Iqhb-IcWyVfH1BULab3KMxgOw,1234
|
25
25
|
haiway/utils/env.py,sha256=lKPOBZWyRD_gQariDGBjVLYTm0740nytPCSQpK2oRyE,3136
|
@@ -28,8 +28,8 @@ haiway/utils/logs.py,sha256=oDsc1ZdqKDjlTlctLbDcp9iX98Acr-1tdw-Pyg3DElo,1577
|
|
28
28
|
haiway/utils/mimic.py,sha256=BkVjTVP2TxxC8GChPGyDV6UXVwJmiRiSWeOYZNZFHxs,1828
|
29
29
|
haiway/utils/noop.py,sha256=qgbZlOKWY6_23Zs43OLukK2HagIQKRyR04zrFVm5rWI,344
|
30
30
|
haiway/utils/queue.py,sha256=WGW8kSusIwRYHsYRIKD2CaqhhC1pUtVgtNHFDXDtYrw,2443
|
31
|
-
haiway-0.
|
32
|
-
haiway-0.
|
33
|
-
haiway-0.
|
34
|
-
haiway-0.
|
35
|
-
haiway-0.
|
31
|
+
haiway-0.3.1.dist-info/LICENSE,sha256=GehQEW_I1pkmxkkj3NEa7rCTQKYBn7vTPabpDYJlRuo,1063
|
32
|
+
haiway-0.3.1.dist-info/METADATA,sha256=ElVgToccvxi6C6UcuG3iqGKPAyJUcacRclp6YJ9A4hw,3872
|
33
|
+
haiway-0.3.1.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
|
34
|
+
haiway-0.3.1.dist-info/top_level.txt,sha256=_LdXVLzUzgkvAGQnQJj5kQfoFhpPW6EF4Kj9NapniLg,7
|
35
|
+
haiway-0.3.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|