haiway 0.14.0__py3-none-any.whl → 0.15.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/context/access.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from asyncio import (
2
2
  CancelledError,
3
3
  Task,
4
+ TaskGroup,
4
5
  current_task,
5
6
  iscoroutinefunction,
6
7
  )
@@ -45,6 +46,7 @@ class ScopeContext:
45
46
  self,
46
47
  label: str,
47
48
  logger: Logger | None,
49
+ task_group: TaskGroup | None,
48
50
  state: tuple[State, ...],
49
51
  disposables: Disposables | None,
50
52
  metrics: MetricsHandler | None,
@@ -64,8 +66,16 @@ class ScopeContext:
64
66
  logger=logger,
65
67
  ),
66
68
  )
67
- # postponing task group creation to include only when needed
68
- self._task_group_context: TaskGroupContext
69
+ self._task_group_context: TaskGroupContext | None
70
+ object.__setattr__(
71
+ self,
72
+ "_task_group_context",
73
+ TaskGroupContext(
74
+ task_group=task_group,
75
+ )
76
+ if task_group is not None or self._identifier.is_root
77
+ else None,
78
+ )
69
79
  # prepare state context to capture current state
70
80
  self._state_context: StateContext
71
81
  object.__setattr__(
@@ -110,6 +120,9 @@ class ScopeContext:
110
120
  )
111
121
 
112
122
  def __enter__(self) -> str:
123
+ assert ( # nosec: B101
124
+ self._task_group_context is None or self._identifier.is_root
125
+ ), "Can't enter synchronous context with task group"
113
126
  assert self._disposables is None, "Can't enter synchronous context with disposables" # nosec: B101
114
127
  self._identifier.__enter__()
115
128
  self._logger_context.__enter__()
@@ -151,23 +164,19 @@ class ScopeContext:
151
164
  async def __aenter__(self) -> str:
152
165
  self._identifier.__enter__()
153
166
  self._logger_context.__enter__()
154
- # lazily initialize group when needed
155
- object.__setattr__(
156
- self,
157
- "_task_group_context",
158
- TaskGroupContext(),
159
- )
160
- await self._task_group_context.__aenter__()
167
+
168
+ if task_group := self._task_group_context:
169
+ await task_group.__aenter__()
161
170
 
162
171
  # lazily initialize state to include disposables results
163
- if self._disposables is not None:
172
+ if disposables := self._disposables:
164
173
  assert self._state_context._token is None # nosec: B101
165
174
  object.__setattr__(
166
175
  self,
167
176
  "_state_context",
168
177
  StateContext(
169
178
  state=self._state_context._state.updated(
170
- await self._disposables.__aenter__(),
179
+ await disposables.__aenter__(),
171
180
  ),
172
181
  ),
173
182
  )
@@ -183,18 +192,19 @@ class ScopeContext:
183
192
  exc_val: BaseException | None,
184
193
  exc_tb: TracebackType | None,
185
194
  ) -> None:
186
- if self._disposables is not None:
187
- await self._disposables.__aexit__(
195
+ if disposables := self._disposables:
196
+ await disposables.__aexit__(
188
197
  exc_type=exc_type,
189
198
  exc_val=exc_val,
190
199
  exc_tb=exc_tb,
191
200
  )
192
201
 
193
- await self._task_group_context.__aexit__(
194
- exc_type=exc_type,
195
- exc_val=exc_val,
196
- exc_tb=exc_tb,
197
- )
202
+ if task_group := self._task_group_context:
203
+ await task_group.__aexit__(
204
+ exc_type=exc_type,
205
+ exc_val=exc_val,
206
+ exc_tb=exc_tb,
207
+ )
198
208
 
199
209
  self._metrics_context.__exit__(
200
210
  exc_type=exc_type,
@@ -278,6 +288,7 @@ class ctx:
278
288
  *state: State,
279
289
  disposables: Disposables | Iterable[Disposable] | None = None,
280
290
  logger: Logger | None = None,
291
+ task_group: TaskGroup | None = None,
281
292
  metrics: MetricsHandler | None = None,
282
293
  ) -> ScopeContext:
283
294
  """
@@ -302,6 +313,10 @@ class ctx:
302
313
  logger used within the scope context, when not provided current logger will be used\
303
314
  if any, otherwise the logger with the scope name will be requested.
304
315
 
316
+ task_group: TaskGroup | None
317
+ task group used for spawning and joining tasks within the context. Root scope will
318
+ always have task group created even when not set.
319
+
305
320
  metrics_store: MetricsStore | None = None
306
321
  metrics storage solution responsible for recording and storing metrics.\
307
322
  Metrics recroding will be ignored if storage is not provided.
@@ -328,6 +343,7 @@ class ctx:
328
343
  return ScopeContext(
329
344
  label=label,
330
345
  logger=logger,
346
+ task_group=task_group,
331
347
  state=state,
332
348
  disposables=resolved_disposables,
333
349
  metrics=metrics,
haiway/context/state.py CHANGED
@@ -1,10 +1,12 @@
1
- from collections.abc import Iterable, MutableMapping
1
+ from asyncio import iscoroutinefunction
2
+ from collections.abc import Callable, Coroutine, Iterable, MutableMapping
2
3
  from contextvars import ContextVar, Token
3
4
  from types import TracebackType
4
- from typing import Any, Self, cast, final
5
+ from typing import Any, Self, cast, final, overload
5
6
 
6
7
  from haiway.context.types import MissingContext, MissingState
7
8
  from haiway.state import State
9
+ from haiway.utils.mimic import mimic_function
8
10
 
9
11
  __all__ = [
10
12
  "ScopeState",
@@ -179,3 +181,41 @@ class StateContext:
179
181
  "_token",
180
182
  None,
181
183
  )
184
+
185
+ @overload
186
+ def __call__[Result, **Arguments](
187
+ self,
188
+ function: Callable[Arguments, Coroutine[Any, Any, Result]],
189
+ ) -> Callable[Arguments, Coroutine[Any, Any, Result]]: ...
190
+
191
+ @overload
192
+ def __call__[Result, **Arguments](
193
+ self,
194
+ function: Callable[Arguments, Result],
195
+ ) -> Callable[Arguments, Result]: ...
196
+
197
+ def __call__[Result, **Arguments](
198
+ self,
199
+ function: Callable[Arguments, Coroutine[Any, Any, Result]] | Callable[Arguments, Result],
200
+ ) -> Callable[Arguments, Coroutine[Any, Any, Result]] | Callable[Arguments, Result]:
201
+ if iscoroutinefunction(function):
202
+
203
+ async def async_context(
204
+ *args: Arguments.args,
205
+ **kwargs: Arguments.kwargs,
206
+ ) -> Result:
207
+ with self:
208
+ return await function(*args, **kwargs)
209
+
210
+ return mimic_function(function, within=async_context)
211
+
212
+ else:
213
+
214
+ def sync_context(
215
+ *args: Arguments.args,
216
+ **kwargs: Arguments.kwargs,
217
+ ) -> Result:
218
+ with self:
219
+ return function(*args, **kwargs) # pyright: ignore[reportReturnType]
220
+
221
+ return mimic_function(function, within=sync_context) # pyright: ignore[reportReturnType]
haiway/context/tasks.py CHANGED
@@ -40,12 +40,13 @@ class TaskGroupContext:
40
40
 
41
41
  def __init__(
42
42
  self,
43
+ task_group: TaskGroup | None = None,
43
44
  ) -> None:
44
45
  self._group: TaskGroup
45
46
  object.__setattr__(
46
47
  self,
47
48
  "_group",
48
- TaskGroup(),
49
+ task_group if task_group is not None else TaskGroup(),
49
50
  )
50
51
  self._token: Token[TaskGroup] | None
51
52
  object.__setattr__(
@@ -30,12 +30,10 @@ def wrap_async[**Args, Result](
30
30
 
31
31
 
32
32
  @overload
33
- def asynchronous[**Args, Result]() -> (
34
- Callable[
35
- [Callable[Args, Result]],
36
- Callable[Args, Coroutine[Any, Any, Result]],
37
- ]
38
- ): ...
33
+ def asynchronous[**Args, Result]() -> Callable[
34
+ [Callable[Args, Result]],
35
+ Callable[Args, Coroutine[Any, Any, Result]],
36
+ ]: ...
39
37
 
40
38
 
41
39
  @overload
haiway/helpers/caching.py CHANGED
@@ -66,7 +66,7 @@ def cache[**Args, Result, Key](
66
66
  ]: ...
67
67
 
68
68
 
69
- def cache[**Args, Result, Key]( # noqa: PLR0913
69
+ def cache[**Args, Result, Key](
70
70
  function: Callable[Args, Result] | None = None,
71
71
  *,
72
72
  limit: int | None = None,
haiway/utils/queue.py CHANGED
@@ -143,3 +143,7 @@ class AsyncQueue[Element](AsyncIterator[Element]):
143
143
  "_waiting",
144
144
  None,
145
145
  )
146
+
147
+ def clear(self) -> None:
148
+ if self._waiting is None or self._waiting.done():
149
+ self._queue.clear()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: haiway
3
- Version: 0.14.0
3
+ Version: 0.15.1
4
4
  Summary: Framework for dependency injection and state management within structured concurrency model.
5
5
  Project-URL: Homepage, https://miquido.com
6
6
  Project-URL: Repository, https://github.com/miquido/haiway.git
@@ -1,17 +1,17 @@
1
1
  haiway/__init__.py,sha256=RhW9HOIAVQ3srQ-v23tPghJ20dWcn_uAyt8U8Hhn868,2081
2
2
  haiway/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  haiway/context/__init__.py,sha256=feqd0eJnGQwh4B8BZXpS0fQRE-DqoFCFOHipF1jOY8A,762
4
- haiway/context/access.py,sha256=1Oq70pcp54bC9NNp-zMocDewVJpcZgepi99_xeqz98o,18502
4
+ haiway/context/access.py,sha256=yW6GNZtSWaxtBRTViP3BiJJYEsLbKkS6Zyzrp1uKgvo,19122
5
5
  haiway/context/disposables.py,sha256=vcsh8jRaJ8Q1ob7oh5LsrSPw9f5AMTcaD_p_Gb7tXAI,2588
6
6
  haiway/context/identifier.py,sha256=lz-FuspOtsaEsfb7QPrEVWYfbcMJgd3A6BGG3kLbaV0,3914
7
7
  haiway/context/logging.py,sha256=F3dr6MLjodg3MX5WTInxn3r3JuihG-giBzumI0GGUQw,5590
8
8
  haiway/context/metrics.py,sha256=N20XQtC8au_e_3iWrsZdej78YBEIWF44fdtWcZBWono,5223
9
- haiway/context/state.py,sha256=7pXb5gvyPOWiRbxX-sSfO-hjaHcTUIp_uTKhjaSLeRo,4552
10
- haiway/context/tasks.py,sha256=MKfsa-921cIpQ_BKskwokjR27suCHkHZa3O9kOE8UOg,2826
9
+ haiway/context/state.py,sha256=61SndKeMF3uS_HNeF-6gZUyVI6f4hi5pUXNG95VZLA8,5981
10
+ haiway/context/tasks.py,sha256=VjYrsf9OxQb_m0etmEO0BAs0syLGC728E5TjkdMUMEE,2913
11
11
  haiway/context/types.py,sha256=VvJA7wAPZ3ISpgyThVguioYUXqhHf0XkPfRd0M1ERiQ,142
12
12
  haiway/helpers/__init__.py,sha256=ZKDlL3twDqXyI1a9FDgRy3m1-Dfycvke6BJ4C3CndEk,671
13
- haiway/helpers/asynchrony.py,sha256=YHLK5Hjc-5UWlQRypC11yHeEQyeAtHqrMoBTBfqQBvQ,6286
14
- haiway/helpers/caching.py,sha256=EU5usTHGDzf0SO3bMW4hHB9oZlLlE7BxO_2ckbjYBw8,13274
13
+ haiway/helpers/asynchrony.py,sha256=pmPvlH4UiIaHXfQNsHvlDmzu5gCa8Pzc0_gNBAPgirU,6266
14
+ haiway/helpers/caching.py,sha256=3M5JVI6dq-Xx6qI2DbLw2wek8U7xVjqbCZowldApXnc,13257
15
15
  haiway/helpers/metrics.py,sha256=VNxgPgV8pgt-51f2CANy1IVx8VMYIAxT3F849t3IeQs,14604
16
16
  haiway/helpers/retries.py,sha256=3m1SsJW_YY_HPufX9LEzcd_MEyRRFNXvSExLeEti8W8,7539
17
17
  haiway/helpers/throttling.py,sha256=r9HnUuo4nX36Pf-oMFHUJk-ZCDeXQ__JTDHlkSltRhA,4121
@@ -35,9 +35,9 @@ 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
- haiway/utils/queue.py,sha256=Tk1bXvuNbEgapeC3-h_PYBASqVjhEoL8mUvtJnM29xI,4000
38
+ haiway/utils/queue.py,sha256=mF0wayKg6MegfBkgxghPDVCbX2rka6sX7KCzQCGl10s,4120
39
39
  haiway/utils/stream.py,sha256=Vqyi0EwcupkVyKQ7eple6z9DkcbSHkE-6yMw85mak9Q,2832
40
- haiway-0.14.0.dist-info/METADATA,sha256=e01xN8K8-d8RiPRaV2ibtsxEHfITllUZmxZA_VzEpBs,4299
41
- haiway-0.14.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
42
- haiway-0.14.0.dist-info/licenses/LICENSE,sha256=3phcpHVNBP8jsi77gOO0E7rgKeDeu99Pi7DSnK9YHoQ,1069
43
- haiway-0.14.0.dist-info/RECORD,,
40
+ haiway-0.15.1.dist-info/METADATA,sha256=785O6a47Z95dCqf32Lcz-qRITFRnaj-4LiK1gMIz4mc,4299
41
+ haiway-0.15.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
42
+ haiway-0.15.1.dist-info/licenses/LICENSE,sha256=3phcpHVNBP8jsi77gOO0E7rgKeDeu99Pi7DSnK9YHoQ,1069
43
+ haiway-0.15.1.dist-info/RECORD,,