haiway 0.1.0__tar.gz → 0.3.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.
Files changed (49) hide show
  1. {haiway-0.1.0/src/haiway.egg-info → haiway-0.3.0}/PKG-INFO +1 -1
  2. {haiway-0.1.0 → haiway-0.3.0}/pyproject.toml +1 -1
  3. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/__init__.py +10 -18
  4. haiway-0.3.0/src/haiway/context/__init__.py +13 -0
  5. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/context/access.py +85 -51
  6. haiway-0.3.0/src/haiway/context/disposables.py +68 -0
  7. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/context/metrics.py +11 -11
  8. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/context/state.py +15 -17
  9. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/context/types.py +0 -5
  10. haiway-0.3.0/src/haiway/helpers/__init__.py +13 -0
  11. haiway-0.1.0/src/haiway/helpers/cache.py → haiway-0.3.0/src/haiway/helpers/cached.py +4 -4
  12. haiway-0.1.0/src/haiway/helpers/retry.py → haiway-0.3.0/src/haiway/helpers/retries.py +20 -7
  13. haiway-0.1.0/src/haiway/helpers/timeout.py → haiway-0.3.0/src/haiway/helpers/timeouted.py +2 -2
  14. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/state/__init__.py +2 -2
  15. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/state/attributes.py +1 -1
  16. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/state/structure.py +17 -17
  17. {haiway-0.1.0 → haiway-0.3.0/src/haiway.egg-info}/PKG-INFO +1 -1
  18. {haiway-0.1.0 → haiway-0.3.0}/src/haiway.egg-info/SOURCES.txt +5 -5
  19. {haiway-0.1.0 → haiway-0.3.0}/tests/test_auto_retry.py +18 -18
  20. {haiway-0.1.0 → haiway-0.3.0}/tests/test_cache.py +18 -18
  21. {haiway-0.1.0 → haiway-0.3.0}/tests/test_context.py +2 -2
  22. haiway-0.1.0/tests/test_structure.py → haiway-0.3.0/tests/test_state.py +7 -7
  23. {haiway-0.1.0 → haiway-0.3.0}/tests/test_timeout.py +5 -5
  24. haiway-0.1.0/src/haiway/context/__init__.py +0 -14
  25. haiway-0.1.0/src/haiway/context/dependencies.py +0 -61
  26. haiway-0.1.0/src/haiway/helpers/__init__.py +0 -13
  27. {haiway-0.1.0 → haiway-0.3.0}/LICENSE +0 -0
  28. {haiway-0.1.0 → haiway-0.3.0}/README.md +0 -0
  29. {haiway-0.1.0 → haiway-0.3.0}/setup.cfg +0 -0
  30. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/context/tasks.py +0 -0
  31. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/helpers/asynchronous.py +0 -0
  32. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/helpers/throttling.py +0 -0
  33. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/py.typed +0 -0
  34. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/state/validation.py +0 -0
  35. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/types/__init__.py +0 -0
  36. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/types/frozen.py +0 -0
  37. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/types/missing.py +0 -0
  38. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/utils/__init__.py +0 -0
  39. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/utils/always.py +0 -0
  40. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/utils/env.py +0 -0
  41. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/utils/immutable.py +0 -0
  42. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/utils/logs.py +0 -0
  43. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/utils/mimic.py +0 -0
  44. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/utils/noop.py +0 -0
  45. {haiway-0.1.0 → haiway-0.3.0}/src/haiway/utils/queue.py +0 -0
  46. {haiway-0.1.0 → haiway-0.3.0}/src/haiway.egg-info/dependency_links.txt +0 -0
  47. {haiway-0.1.0 → haiway-0.3.0}/src/haiway.egg-info/requires.txt +0 -0
  48. {haiway-0.1.0 → haiway-0.3.0}/src/haiway.egg-info/top_level.txt +0 -0
  49. {haiway-0.1.0 → haiway-0.3.0}/tests/test_async_queue.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: haiway
3
- Version: 0.1.0
3
+ Version: 0.3.0
4
4
  Summary: Framework for dependency injection and state management within structured concurrency model.
5
5
  Maintainer-email: Kacper Kaliński <kacper.kalinski@miquido.com>
6
6
  License: MIT License
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "haiway"
7
7
  description = "Framework for dependency injection and state management within structured concurrency model."
8
- version = "0.1.0"
8
+ version = "0.3.0"
9
9
  readme = "README.md"
10
10
  maintainers = [
11
11
  { name = "Kacper Kaliński", email = "kacper.kalinski@miquido.com" },
@@ -1,20 +1,13 @@
1
1
  from haiway.context import (
2
- Dependencies,
3
- Dependency,
2
+ Disposable,
3
+ Disposables,
4
4
  MissingContext,
5
- MissingDependency,
6
5
  MissingState,
7
6
  ScopeMetrics,
8
7
  ctx,
9
8
  )
10
- from haiway.helpers import (
11
- asynchronous,
12
- auto_retry,
13
- cached,
14
- throttle,
15
- with_timeout,
16
- )
17
- from haiway.state import Structure
9
+ from haiway.helpers import asynchronous, cache, retry, throttle, timeout
10
+ from haiway.state import State
18
11
  from haiway.types import (
19
12
  MISSING,
20
13
  Missing,
@@ -45,11 +38,10 @@ __all__ = [
45
38
  "async_noop",
46
39
  "asynchronous",
47
40
  "AsyncQueue",
48
- "auto_retry",
49
- "cached",
41
+ "cache",
50
42
  "ctx",
51
- "Dependencies",
52
- "Dependency",
43
+ "Disposable",
44
+ "Disposables",
53
45
  "freeze",
54
46
  "frozenlist",
55
47
  "getenv_bool",
@@ -62,14 +54,14 @@ __all__ = [
62
54
  "Missing",
63
55
  "MISSING",
64
56
  "MissingContext",
65
- "MissingDependency",
66
57
  "MissingState",
67
58
  "noop",
68
59
  "not_missing",
60
+ "retry",
69
61
  "ScopeMetrics",
70
62
  "setup_logging",
71
- "Structure",
63
+ "State",
72
64
  "throttle",
65
+ "timeout",
73
66
  "when_missing",
74
- "with_timeout",
75
67
  ]
@@ -0,0 +1,13 @@
1
+ from haiway.context.access import ctx
2
+ from haiway.context.disposables import Disposable, Disposables
3
+ from haiway.context.metrics import ScopeMetrics
4
+ from haiway.context.types import MissingContext, MissingState
5
+
6
+ __all__ = [
7
+ "ctx",
8
+ "Disposable",
9
+ "Disposables",
10
+ "MissingContext",
11
+ "MissingState",
12
+ "ScopeMetrics",
13
+ ]
@@ -5,16 +5,17 @@ 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
 
13
- from haiway.context.dependencies import Dependencies, Dependency
14
+ from haiway.context.disposables import Disposable, Disposables
14
15
  from haiway.context.metrics import MetricsContext, ScopeMetrics
15
16
  from haiway.context.state import StateContext
16
17
  from haiway.context.tasks import TaskGroupContext
17
- from haiway.state import Structure
18
+ from haiway.state import State
18
19
  from haiway.utils import freeze
19
20
 
20
21
  __all__ = [
@@ -24,25 +25,41 @@ __all__ = [
24
25
 
25
26
  @final
26
27
  class ScopeContext:
27
- def __init__(
28
+ def __init__( # noqa: PLR0913
28
29
  self,
30
+ trace_id: str | None,
31
+ name: str,
32
+ logger: Logger | None,
33
+ state: tuple[State, ...],
34
+ disposables: Disposables | None,
29
35
  task_group: TaskGroupContext,
30
- state: StateContext,
31
- metrics: MetricsContext,
32
36
  completion: Callable[[ScopeMetrics], Coroutine[None, None, None]] | None,
33
37
  ) -> None:
34
38
  self._task_group: TaskGroupContext = task_group
35
- self._state: StateContext = state
36
- self._metrics: MetricsContext = metrics
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
37
46
  self._completion: Callable[[ScopeMetrics], Coroutine[None, None, None]] | None = completion
38
47
 
39
48
  freeze(self)
40
49
 
41
50
  def __enter__(self) -> None:
42
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
+ )
43
60
 
44
- self._state.__enter__()
45
- self._metrics.__enter__()
61
+ self._state_context.__enter__()
62
+ self._metrics_context.__enter__()
46
63
 
47
64
  def __exit__(
48
65
  self,
@@ -50,49 +67,71 @@ class ScopeContext:
50
67
  exc_val: BaseException | None,
51
68
  exc_tb: TracebackType | None,
52
69
  ) -> None:
53
- self._metrics.__exit__(
70
+ self._metrics_context.__exit__(
54
71
  exc_type=exc_type,
55
72
  exc_val=exc_val,
56
73
  exc_tb=exc_tb,
57
74
  )
58
75
 
59
- self._state.__exit__(
76
+ self._state_context.__exit__(
60
77
  exc_type=exc_type,
61
78
  exc_val=exc_val,
62
79
  exc_tb=exc_tb,
63
80
  )
64
81
 
65
82
  async def __aenter__(self) -> None:
66
- self._state.__enter__()
67
- self._metrics.__enter__()
68
83
  await self._task_group.__aenter__()
69
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
+
70
102
  async def __aexit__(
71
103
  self,
72
104
  exc_type: type[BaseException] | None,
73
105
  exc_val: BaseException | None,
74
106
  exc_tb: TracebackType | None,
75
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
+
76
115
  await self._task_group.__aexit__(
77
116
  exc_type=exc_type,
78
117
  exc_val=exc_val,
79
118
  exc_tb=exc_tb,
80
119
  )
81
120
 
82
- self._metrics.__exit__(
121
+ self._metrics_context.__exit__(
83
122
  exc_type=exc_type,
84
123
  exc_val=exc_val,
85
124
  exc_tb=exc_tb,
86
125
  )
87
126
 
88
- self._state.__exit__(
127
+ self._state_context.__exit__(
89
128
  exc_type=exc_type,
90
129
  exc_val=exc_val,
91
130
  exc_tb=exc_tb,
92
131
  )
93
132
 
94
133
  if completion := self._completion:
95
- await completion(self._metrics._metrics) # pyright: ignore[reportPrivateUsage]
134
+ await completion(self._metrics_context._metrics) # pyright: ignore[reportPrivateUsage]
96
135
 
97
136
 
98
137
  @final
@@ -101,7 +140,8 @@ class ctx:
101
140
  def scope(
102
141
  name: str,
103
142
  /,
104
- *state: Structure,
143
+ *state: State,
144
+ disposables: Disposables | Iterable[Disposable] | None = None,
105
145
  logger: Logger | None = None,
106
146
  trace_id: str | None = None,
107
147
  completion: Callable[[ScopeMetrics], Coroutine[None, None, None]] | None = None,
@@ -115,9 +155,14 @@ class ctx:
115
155
  name: Value
116
156
  name of the scope context
117
157
 
118
- *state: Structure
119
- state propagated within the scope context, will be merged with current if any\
120
- by replacing current with provided on conflict
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.
121
166
 
122
167
  logger: Logger | None
123
168
  logger used within the scope context, when not provided current logger will be used\
@@ -139,20 +184,30 @@ class ctx:
139
184
  context object intended to enter context manager with it
140
185
  """
141
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
+
142
198
  return ScopeContext(
199
+ trace_id=trace_id,
200
+ name=name,
201
+ logger=logger,
202
+ state=state,
203
+ disposables=resolved_disposables,
143
204
  task_group=TaskGroupContext(),
144
- metrics=MetricsContext.scope(
145
- name,
146
- logger=logger,
147
- trace_id=trace_id,
148
- ),
149
- state=StateContext.updated(state),
150
205
  completion=completion,
151
206
  )
152
207
 
153
208
  @staticmethod
154
209
  def updated(
155
- *state: Structure,
210
+ *state: State,
156
211
  ) -> StateContext:
157
212
  """
158
213
  Update scope context with given state. When called within an existing context\
@@ -160,7 +215,7 @@ class ctx:
160
215
 
161
216
  Parameters
162
217
  ----------
163
- *state: Structure
218
+ *state: State
164
219
  state propagated within the updated scope context, will be merged with current if any\
165
220
  by replacing current with provided on conflict
166
221
 
@@ -215,28 +270,7 @@ class ctx:
215
270
  raise RuntimeError("Attempting to cancel context out of asyncio task")
216
271
 
217
272
  @staticmethod
218
- async def dependency[DependencyType: Dependency](
219
- dependency: type[DependencyType],
220
- /,
221
- ) -> DependencyType:
222
- """
223
- Access current dependency by its type.
224
-
225
- Parameters
226
- ----------
227
- dependency: type[DependencyType]
228
- type of requested dependency
229
-
230
- Returns
231
- -------
232
- DependencyType
233
- resolved dependency instance
234
- """
235
-
236
- return await Dependencies.dependency(dependency)
237
-
238
- @staticmethod
239
- def state[StateType: Structure](
273
+ def state[StateType: State](
240
274
  state: type[StateType],
241
275
  /,
242
276
  default: StateType | None = None,
@@ -261,7 +295,7 @@ class ctx:
261
295
  )
262
296
 
263
297
  @staticmethod
264
- def record[Metric: Structure](
298
+ def record[Metric: State](
265
299
  metric: Metric,
266
300
  /,
267
301
  merge: Callable[[Metric, Metric], Metric] = lambda lhs, rhs: rhs,
@@ -0,0 +1,68 @@
1
+ from asyncio import gather, shield
2
+ from collections.abc import Iterable
3
+ from types import TracebackType
4
+ from typing import Protocol, final, runtime_checkable
5
+
6
+ from haiway.state import State
7
+
8
+ __all__ = [
9
+ "Disposable",
10
+ "Disposables",
11
+ ]
12
+
13
+
14
+ @runtime_checkable
15
+ class Disposable(Protocol):
16
+ async def initialize(self) -> State | None: ...
17
+ async def dispose(self) -> None: ...
18
+
19
+
20
+ @final
21
+ class Disposables:
22
+ def __init__(
23
+ self,
24
+ *disposables: Disposable,
25
+ ) -> None:
26
+ self._disposables: tuple[Disposable, ...] = disposables
27
+
28
+ async def initialize(self) -> Iterable[State]:
29
+ return [
30
+ state
31
+ for state in await gather(
32
+ *[disposable.initialize() for disposable in self._disposables],
33
+ )
34
+ if state is not None
35
+ ]
36
+
37
+ async def dispose(self) -> None:
38
+ results: list[BaseException | None] = await shield(
39
+ gather(
40
+ *[disposable.dispose() for disposable in self._disposables],
41
+ return_exceptions=True,
42
+ ),
43
+ )
44
+
45
+ self._disposables = ()
46
+ exceptions: list[BaseException] = [
47
+ exception for exception in results if exception is not None
48
+ ]
49
+
50
+ if len(exceptions) > 1:
51
+ raise BaseExceptionGroup("Disposing errors", exceptions)
52
+
53
+ elif exceptions:
54
+ raise exceptions[0]
55
+
56
+ def __bool__(self) -> bool:
57
+ return len(self._disposables) > 0
58
+
59
+ async def __aenter__(self) -> Iterable[State]:
60
+ return await self.initialize()
61
+
62
+ async def __aexit__(
63
+ self,
64
+ exc_type: type[BaseException] | None,
65
+ exc_val: BaseException | None,
66
+ exc_tb: TracebackType | None,
67
+ ) -> None:
68
+ await self.dispose()
@@ -9,7 +9,7 @@ from types import TracebackType
9
9
  from typing import Any, Self, cast, final, overload
10
10
  from uuid import uuid4
11
11
 
12
- from haiway.state import Structure
12
+ from haiway.state import State
13
13
  from haiway.utils import freeze
14
14
 
15
15
  __all__ = [
@@ -30,7 +30,7 @@ class ScopeMetrics:
30
30
  self.trace_id: str = trace_id or uuid4().hex
31
31
  self._label: str = f"{self.trace_id}|{scope}" if scope else self.trace_id
32
32
  self._logger: Logger = logger or getLogger(name=scope)
33
- self._metrics: dict[type[Structure], Structure] = {}
33
+ self._metrics: dict[type[State], State] = {}
34
34
  self._nested: list[ScopeMetrics] = []
35
35
  self._timestamp: float = monotonic()
36
36
  self._completed: Future[float] = get_event_loop().create_future()
@@ -46,11 +46,11 @@ class ScopeMetrics:
46
46
  def metrics(
47
47
  self,
48
48
  *,
49
- merge: Callable[[Structure, Structure], Structure] = lambda lhs, rhs: lhs,
50
- ) -> list[Structure]:
51
- metrics: dict[type[Structure], Structure] = copy(self._metrics)
49
+ merge: Callable[[State, State], State] = lambda lhs, rhs: lhs,
50
+ ) -> list[State]:
51
+ metrics: dict[type[State], State] = copy(self._metrics)
52
52
  for metric in chain.from_iterable(nested.metrics(merge=merge) for nested in self._nested):
53
- metric_type: type[Structure] = type(metric)
53
+ metric_type: type[State] = type(metric)
54
54
  if current := metrics.get(metric_type):
55
55
  metrics[metric_type] = merge(current, metric)
56
56
 
@@ -60,21 +60,21 @@ class ScopeMetrics:
60
60
  return list(metrics.values())
61
61
 
62
62
  @overload
63
- def read[Metric: Structure](
63
+ def read[Metric: State](
64
64
  self,
65
65
  metric: type[Metric],
66
66
  /,
67
67
  ) -> Metric | None: ...
68
68
 
69
69
  @overload
70
- def read[Metric: Structure](
70
+ def read[Metric: State](
71
71
  self,
72
72
  metric: type[Metric],
73
73
  /,
74
74
  default: Metric,
75
75
  ) -> Metric: ...
76
76
 
77
- def read[Metric: Structure](
77
+ def read[Metric: State](
78
78
  self,
79
79
  metric: type[Metric],
80
80
  /,
@@ -82,7 +82,7 @@ class ScopeMetrics:
82
82
  ) -> Metric | None:
83
83
  return cast(Metric | None, self._metrics.get(metric, default))
84
84
 
85
- def record[Metric: Structure](
85
+ def record[Metric: State](
86
86
  self,
87
87
  metric: Metric,
88
88
  /,
@@ -187,7 +187,7 @@ class MetricsContext:
187
187
  )
188
188
 
189
189
  @classmethod
190
- def record[Metric: Structure](
190
+ def record[Metric: State](
191
191
  cls,
192
192
  metric: Metric,
193
193
  /,
@@ -4,7 +4,7 @@ from types import TracebackType
4
4
  from typing import Self, cast, final
5
5
 
6
6
  from haiway.context.types import MissingContext, MissingState
7
- from haiway.state import Structure
7
+ from haiway.state import State
8
8
  from haiway.utils import freeze
9
9
 
10
10
  __all__ = [
@@ -17,28 +17,26 @@ __all__ = [
17
17
  class ScopeState:
18
18
  def __init__(
19
19
  self,
20
- state: Iterable[Structure],
20
+ state: Iterable[State],
21
21
  ) -> None:
22
- self._state: dict[type[Structure], Structure] = {
23
- type(element): element for element in state
24
- }
22
+ self._state: dict[type[State], State] = {type(element): element for element in state}
25
23
  freeze(self)
26
24
 
27
- def state[State: Structure](
25
+ def state[StateType: State](
28
26
  self,
29
- state: type[State],
27
+ state: type[StateType],
30
28
  /,
31
- default: State | None = None,
32
- ) -> State:
29
+ default: StateType | None = None,
30
+ ) -> StateType:
33
31
  if state in self._state:
34
- return cast(State, self._state[state])
32
+ return cast(StateType, self._state[state])
35
33
 
36
34
  elif default is not None:
37
35
  return default
38
36
 
39
37
  else:
40
38
  try:
41
- initialized: State = state()
39
+ initialized: StateType = state()
42
40
  self._state[state] = initialized
43
41
  return initialized
44
42
 
@@ -50,7 +48,7 @@ class ScopeState:
50
48
 
51
49
  def updated(
52
50
  self,
53
- state: Iterable[Structure],
51
+ state: Iterable[State],
54
52
  ) -> Self:
55
53
  if state:
56
54
  return self.__class__(
@@ -69,12 +67,12 @@ class StateContext:
69
67
  _context = ContextVar[ScopeState]("StateContext")
70
68
 
71
69
  @classmethod
72
- def current[State: Structure](
70
+ def current[StateType: State](
73
71
  cls,
74
- state: type[State],
72
+ state: type[StateType],
75
73
  /,
76
- default: State | None = None,
77
- ) -> State:
74
+ default: StateType | None = None,
75
+ ) -> StateType:
78
76
  try:
79
77
  return cls._context.get().state(state, default=default)
80
78
 
@@ -84,7 +82,7 @@ class StateContext:
84
82
  @classmethod
85
83
  def updated(
86
84
  cls,
87
- state: Iterable[Structure],
85
+ state: Iterable[State],
88
86
  /,
89
87
  ) -> Self:
90
88
  try:
@@ -1,6 +1,5 @@
1
1
  __all__ = [
2
2
  "MissingContext",
3
- "MissingDependency",
4
3
  "MissingState",
5
4
  ]
6
5
 
@@ -9,9 +8,5 @@ class MissingContext(Exception):
9
8
  pass
10
9
 
11
10
 
12
- class MissingDependency(Exception):
13
- pass
14
-
15
-
16
11
  class MissingState(Exception):
17
12
  pass
@@ -0,0 +1,13 @@
1
+ from haiway.helpers.asynchronous import asynchronous
2
+ from haiway.helpers.cached import cache
3
+ from haiway.helpers.retries import retry
4
+ from haiway.helpers.throttling import throttle
5
+ from haiway.helpers.timeouted import timeout
6
+
7
+ __all__ = [
8
+ "asynchronous",
9
+ "cache",
10
+ "retry",
11
+ "throttle",
12
+ "timeout",
13
+ ]
@@ -9,26 +9,26 @@ from weakref import ref
9
9
  from haiway.utils.mimic import mimic_function
10
10
 
11
11
  __all__ = [
12
- "cached",
12
+ "cache",
13
13
  ]
14
14
 
15
15
 
16
16
  @overload
17
- def cached[**Args, Result](
17
+ def cache[**Args, Result](
18
18
  function: Callable[Args, Result],
19
19
  /,
20
20
  ) -> Callable[Args, Result]: ...
21
21
 
22
22
 
23
23
  @overload
24
- def cached[**Args, Result](
24
+ def cache[**Args, Result](
25
25
  *,
26
26
  limit: int = 1,
27
27
  expiration: float | None = None,
28
28
  ) -> Callable[[Callable[Args, Result]], Callable[Args, Result]]: ...
29
29
 
30
30
 
31
- def cached[**Args, Result](
31
+ def cache[**Args, Result](
32
32
  function: Callable[Args, Result] | None = None,
33
33
  *,
34
34
  limit: int = 1,