haiway 0.22.0__py3-none-any.whl → 0.22.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
@@ -539,6 +539,8 @@ class ctx:
539
539
  def check_state[StateType: State](
540
540
  state: type[StateType],
541
541
  /,
542
+ *,
543
+ instantiate_defaults: bool = False,
542
544
  ) -> bool:
543
545
  """
544
546
  Check if state object is available in the current context.
@@ -551,12 +553,18 @@ class ctx:
551
553
  state: type[StateType]
552
554
  The type of state to check
553
555
 
556
+ instantiate_defaults: bool = False
557
+ Control if default value should be instantiated during check.
558
+
554
559
  Returns
555
560
  -------
556
561
  bool
557
562
  True if state is available, otherwise False.
558
563
  """
559
- return StateContext.check_state(state)
564
+ return StateContext.check_state(
565
+ state,
566
+ instantiate_defaults=instantiate_defaults,
567
+ )
560
568
 
561
569
  @staticmethod
562
570
  def state[StateType: State](
@@ -12,7 +12,7 @@ from itertools import chain
12
12
  from types import TracebackType
13
13
  from typing import Any, final
14
14
 
15
- from haiway.context.state import ScopeState, StateContext
15
+ from haiway.context.state import StateContext
16
16
  from haiway.state import State
17
17
  from haiway.utils.mimic import mimic_function
18
18
 
@@ -195,19 +195,25 @@ class Disposables:
195
195
  return multiple
196
196
 
197
197
  async def prepare(self) -> Iterable[State]:
198
+ """
199
+ Enter all contained disposables asynchronously.
200
+
201
+ Enters all disposables in parallel and collects any State objects they return.
202
+ """
198
203
  assert self._loop is None # nosec: B101
199
204
  object.__setattr__(
200
205
  self,
201
206
  "_loop",
202
207
  get_running_loop(),
203
208
  )
204
- return [
205
- *chain.from_iterable(
209
+
210
+ return tuple(
211
+ chain.from_iterable(
206
212
  await gather(
207
213
  *[self._setup(disposable) for disposable in self._disposables],
208
214
  )
209
215
  )
210
- ]
216
+ )
211
217
 
212
218
  async def __aenter__(self) -> None:
213
219
  """
@@ -218,7 +224,7 @@ class Disposables:
218
224
  """
219
225
 
220
226
  assert self._state_context is None, "Context reentrance is not allowed" # nosec: B101
221
- state_context = StateContext(state=ScopeState(await self.prepare()))
227
+ state_context = StateContext.updated(await self.prepare())
222
228
  state_context.__enter__()
223
229
  object.__setattr__(
224
230
  self,
@@ -252,6 +258,26 @@ class Disposables:
252
258
  exc_val: BaseException | None = None,
253
259
  exc_tb: TracebackType | None = None,
254
260
  ) -> None:
261
+ """
262
+ Exit all contained disposables asynchronously.
263
+
264
+ Properly disposes of all resources by calling their __aexit__ methods in parallel.
265
+ If multiple disposables raise exceptions, they are collected into a BaseExceptionGroup.
266
+
267
+ Parameters
268
+ ----------
269
+ exc_type: type[BaseException] | None
270
+ The type of exception that caused the context to be exited
271
+ exc_val: BaseException | None
272
+ The exception that caused the context to be exited
273
+ exc_tb: TracebackType | None
274
+ The traceback for the exception that caused the context to be exited
275
+
276
+ Raises
277
+ ------
278
+ BaseExceptionGroup
279
+ If multiple disposables raise exceptions during exit
280
+ """
255
281
  assert self._loop is not None # nosec: B101
256
282
  results: list[bool | BaseException | None]
257
283
 
@@ -306,6 +332,7 @@ class Disposables:
306
332
 
307
333
  Properly disposes of all resources by calling their __aexit__ methods in parallel.
308
334
  If multiple disposables raise exceptions, they are collected into a BaseExceptionGroup.
335
+ Additionally, produced state context will be also exited resetting state to previous.
309
336
 
310
337
  Parameters
311
338
  ----------
haiway/context/state.py CHANGED
@@ -67,6 +67,8 @@ class ScopeState:
67
67
  self,
68
68
  state: type[StateType],
69
69
  /,
70
+ *,
71
+ instantiate_defaults: bool = False,
70
72
  ) -> bool:
71
73
  """
72
74
  Check state object availability by its type.
@@ -79,6 +81,9 @@ class ScopeState:
79
81
  state: type[StateType]
80
82
  The type of state to check
81
83
 
84
+ instantiate_defaults: bool = False
85
+ Control if default value should be instantiated during check.
86
+
82
87
  Returns
83
88
  -------
84
89
  bool
@@ -87,7 +92,7 @@ class ScopeState:
87
92
  if state in self._state:
88
93
  return True
89
94
 
90
- else:
95
+ elif instantiate_defaults:
91
96
  with self._lock:
92
97
  if state in self._state:
93
98
  return True
@@ -100,6 +105,9 @@ class ScopeState:
100
105
  except BaseException:
101
106
  return False # unavailable, we don't care the exception
102
107
 
108
+ else:
109
+ return False
110
+
103
111
  def state[StateType: State](
104
112
  self,
105
113
  state: type[StateType],
@@ -201,6 +209,7 @@ class StateContext:
201
209
  cls,
202
210
  state: type[StateType],
203
211
  /,
212
+ instantiate_defaults: bool = False,
204
213
  ) -> bool:
205
214
  """
206
215
  Check if state object is available in the current context.
@@ -212,13 +221,19 @@ class StateContext:
212
221
  state: type[StateType]
213
222
  The type of state to check
214
223
 
224
+ instantiate_defaults: bool = False
225
+ Control if default value should be instantiated during check.
226
+
215
227
  Returns
216
228
  -------
217
229
  bool
218
230
  True if state is available, otherwise False.
219
231
  """
220
232
  try:
221
- return cls._context.get().check_state(state)
233
+ return cls._context.get().check_state(
234
+ state,
235
+ instantiate_defaults=instantiate_defaults,
236
+ )
222
237
 
223
238
  except LookupError:
224
239
  return False # no context no state
@@ -5,7 +5,7 @@ from haiway.helpers.files import File, FileAccess
5
5
  from haiway.helpers.observability import LoggerObservability
6
6
  from haiway.helpers.retries import retry
7
7
  from haiway.helpers.throttling import throttle
8
- from haiway.helpers.timeouted import timeout
8
+ from haiway.helpers.timeouting import timeout
9
9
  from haiway.helpers.tracing import traced
10
10
 
11
11
  __all__ = (
haiway/state/structure.py CHANGED
@@ -729,12 +729,22 @@ class State(metaclass=StateMeta):
729
729
  )
730
730
 
731
731
  def __hash__(self) -> int:
732
- return hash(
733
- (
734
- self.__class__,
735
- *tuple(getattr(self, key, MISSING) for key in sorted(self.__ATTRIBUTES__.keys())),
736
- )
737
- )
732
+ hash_values: list[int] = []
733
+ for key in self.__ATTRIBUTES__.keys():
734
+ value: Any = getattr(self, key, MISSING)
735
+
736
+ # Skip MISSING values to ensure consistent hashing
737
+ if value is MISSING:
738
+ continue
739
+
740
+ # Convert to hashable representation
741
+ try:
742
+ hash_values.append(hash(value))
743
+
744
+ except TypeError:
745
+ continue # skip unhashable
746
+
747
+ return hash((self.__class__, tuple(hash_values)))
738
748
 
739
749
  def __setattr__(
740
750
  self,
haiway/utils/__init__.py CHANGED
@@ -9,7 +9,6 @@ from haiway.utils.env import (
9
9
  load_env,
10
10
  )
11
11
  from haiway.utils.formatting import format_str
12
- from haiway.utils.freezing import freeze
13
12
  from haiway.utils.logs import setup_logging
14
13
  from haiway.utils.mimic import mimic_function
15
14
  from haiway.utils.noop import async_noop, noop
@@ -27,7 +26,6 @@ __all__ = (
27
26
  "async_always",
28
27
  "async_noop",
29
28
  "format_str",
30
- "freeze",
31
29
  "getenv_base64",
32
30
  "getenv_bool",
33
31
  "getenv_float",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: haiway
3
- Version: 0.22.0
3
+ Version: 0.22.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,14 +1,14 @@
1
1
  haiway/__init__.py,sha256=FiOAMHHawyGk9FfZU-1UflT8nmwu9J0CrG2QwrJGccw,1917
2
2
  haiway/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  haiway/context/__init__.py,sha256=1N_SvdPkTfIZDZybm3y0rY2dGrDLWTm0ryzUz2XD4f8,1174
4
- haiway/context/access.py,sha256=j5wC0kluFEb1NpTsUG7fgFVklfeNCqb0dygK1VIdLuo,25485
5
- haiway/context/disposables.py,sha256=yRABVbUJIMP6r5oqO-Yl4y20ulhlDuQ2lLnI25QCltg,10495
4
+ haiway/context/access.py,sha256=QCabyZtqqJjGTgAod1ZC3Fz3IfPsyurLo_i68RnCm4Q,25736
5
+ haiway/context/disposables.py,sha256=AP9eZ0BPHJZfjrrfrjSzr4jONMKkR6YmhjOfnBp37so,11504
6
6
  haiway/context/identifier.py,sha256=dCCwLneXJzH__ZWFlGRUHvoCmbT4lM0QVbyokYIbUHg,5255
7
7
  haiway/context/observability.py,sha256=gLKbMPNvt5ozrfyc4TGahN8A_dFFtyCjUIMZu9_wZHA,23722
8
- haiway/context/state.py,sha256=Ni6NUbRYKmgi7HhvosrVH62IzfalLDUH7VYRwpUiQ78,11426
8
+ haiway/context/state.py,sha256=DuCtI0rMLWYbnBGXxpkbQgrX4aAftGkuK8XSd1JtdVc,11912
9
9
  haiway/context/tasks.py,sha256=pScFgeiyrXSJRDFZiYbBLi3k_DHkSlhB8rgAnYtgyrU,4925
10
10
  haiway/context/types.py,sha256=VDWXJySihfvSSPzY09PaGk6j5S9HgmAUboBGCZ8o_4k,766
11
- haiway/helpers/__init__.py,sha256=uEJATJOiqRWeOPMjrGdn_CmWvwrlUQ1gmrau4XsBgUk,720
11
+ haiway/helpers/__init__.py,sha256=PTWpavAveEB2V9Au1QuaRZwh3Rkb1bQSNvo_mxuGqlE,721
12
12
  haiway/helpers/asynchrony.py,sha256=Ddj8UdXhVczAbAC-rLpyhWa4RJ_W2Eolo45Veorq7_4,5362
13
13
  haiway/helpers/caching.py,sha256=BqgcUGQSAmXsuLi5V8EwlZzuGyutHOn1V4k7BHsGKeg,14347
14
14
  haiway/helpers/concurrent.py,sha256=xGMcan_tiETAHQs1YFmgYpA4YMFo6rIbFKvNeMlRFG8,2551
@@ -16,7 +16,7 @@ haiway/helpers/files.py,sha256=L6vXd8gdgWx5jPL8azloU8IGoFq2xnxjMc4ufz-gdl4,11650
16
16
  haiway/helpers/observability.py,sha256=3G0eRE1WYTGRujS0mxzYbLR4MlKnoYllE8cu2Eb_23w,11073
17
17
  haiway/helpers/retries.py,sha256=52LA85HejTiSmCmTMAA9c8oUqD_VnhbTn1b3kwlU52c,9032
18
18
  haiway/helpers/throttling.py,sha256=KBWUSHdKVMC5_nRMmmoPNwfp-3AcerQ6OczJa9gNLM0,5796
19
- haiway/helpers/timeouted.py,sha256=GQ8-btb36f0Jq7TnorAPYXyKScNmf0nxHXCYxqGl-o8,3949
19
+ haiway/helpers/timeouting.py,sha256=GQ8-btb36f0Jq7TnorAPYXyKScNmf0nxHXCYxqGl-o8,3949
20
20
  haiway/helpers/tracing.py,sha256=NHipA5UlngwFcAaKhXg1jTuJ-ti6AqSNxE7u7-92vWo,5409
21
21
  haiway/opentelemetry/__init__.py,sha256=TV-1C14mDAtcHhFZ29ActFQdrGH6x5KuGV9w-JlKYJg,91
22
22
  haiway/opentelemetry/observability.py,sha256=5fsHsFgjcxUcA0hIOM18lVvVdYSRO91ER52PticyzyU,25734
@@ -24,23 +24,22 @@ haiway/state/__init__.py,sha256=AaMqlMhO4zKS_XNevy3A7BHh5PxmguA-Sk_FnaNDY1Q,355
24
24
  haiway/state/attributes.py,sha256=sububiFP23aBB8RGk6OvTUp7BEY6S0kER_uHC09yins,26733
25
25
  haiway/state/path.py,sha256=bv5MI3HmUyku78k0Sz5lc7Q_Bay53iom1l3AL5KZs-4,32143
26
26
  haiway/state/requirement.py,sha256=zNTx7s8FiMZKu9EV3T6f1SOJpR4SC9X5hhL--PVWPCY,15641
27
- haiway/state/structure.py,sha256=XzPDCrFUSy-PKVzI9G6TqechRW3nXSbTK7f_AhxCzq4,23481
27
+ haiway/state/structure.py,sha256=CTf1l0TyKA7vkVDqA9RMdxaOVNSHwQduN2jb6H015hg,23798
28
28
  haiway/state/validation.py,sha256=eDOZKRrfd-dmdbqoHcLacdCVKmVCEpwt239EG6ljNF8,23557
29
29
  haiway/types/__init__.py,sha256=jFr5kf36SvVGdgngvik6_HzG8YNa3NVsdDDSqxVuGm4,281
30
30
  haiway/types/default.py,sha256=59chcOaoGqI2to08RamCCLluimfYbJp5xbYl3fWaLrM,4153
31
31
  haiway/types/missing.py,sha256=OfiyYUnzTk3arKWu8S6ORCEYGvcRu_mdL4j1ExdSvgI,4256
32
- haiway/utils/__init__.py,sha256=HOylRgBEa0uNxEuPBupaJ28l4wEQiy98cGJi2Gtirr4,972
32
+ haiway/utils/__init__.py,sha256=Zs4mJnoRL_4ssGSZqvCFuhllxMDww_8-McsI2xB0mug,917
33
33
  haiway/utils/always.py,sha256=dd6jDQ1j4DpJjTKO1J2Tv5xS8X1LnMC4kQ0D7DtKUvw,1230
34
34
  haiway/utils/collections.py,sha256=gF5tC1EaEzBfPpXrHqR0mZh8e4pRwEPSVactvfN-30M,4737
35
35
  haiway/utils/env.py,sha256=Z0uHJDFegvgzy-gM-f0uPMha9_1ldUglrD5SKNJsvYE,9445
36
36
  haiway/utils/formatting.py,sha256=jgSIGalGUBZVo2ziiNC5Y7vBYbAEwPugOiwEOrNFTcI,4039
37
- haiway/utils/freezing.py,sha256=HJH0SOgPCreb9o0wPeaMPMxhS9JDuzzey6UsKhuvUJU,1292
38
37
  haiway/utils/logs.py,sha256=NuwoqKQnMNi1FMIA91cVFnAPefUFeg3UIT50IOl3sJk,1571
39
38
  haiway/utils/mimic.py,sha256=xaZiUKp096QFfdSw7cNIKEWt2UIS7vf880KF54gny38,1831
40
39
  haiway/utils/noop.py,sha256=U8ocfoCgt-pY0owJDPtrRrj53cabeIXH9qCKWMQnoRk,1336
41
40
  haiway/utils/queue.py,sha256=6v2u3pA6A44IuCCTOjmCt3yLyOcm7PCRnrIGo25j-1o,6402
42
41
  haiway/utils/stream.py,sha256=lXaeveTY0-AYG5xVzcQYaiC6SUD5fUtHoMXiQcrQAAM,5723
43
- haiway-0.22.0.dist-info/METADATA,sha256=6__3ZCA0Klv8j7coosQhvQY9GWNqyVlUKSIRbh1f7Jw,4919
44
- haiway-0.22.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
45
- haiway-0.22.0.dist-info/licenses/LICENSE,sha256=3phcpHVNBP8jsi77gOO0E7rgKeDeu99Pi7DSnK9YHoQ,1069
46
- haiway-0.22.0.dist-info/RECORD,,
42
+ haiway-0.22.1.dist-info/METADATA,sha256=5M6G9KRMDiidXN6qWibXcpns40x11JTHCHNx5WOdD2U,4919
43
+ haiway-0.22.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
44
+ haiway-0.22.1.dist-info/licenses/LICENSE,sha256=3phcpHVNBP8jsi77gOO0E7rgKeDeu99Pi7DSnK9YHoQ,1069
45
+ haiway-0.22.1.dist-info/RECORD,,
haiway/utils/freezing.py DELETED
@@ -1,46 +0,0 @@
1
- from typing import Any
2
-
3
- __all__ = ("freeze",)
4
-
5
-
6
- def freeze(
7
- instance: object,
8
- /,
9
- ) -> None:
10
- """
11
- Make an object instance immutable by preventing attribute modification.
12
-
13
- This function modifies the given object to prevent further changes to its attributes.
14
- It replaces the object's __setattr__ and __delattr__ methods with ones that raise
15
- exceptions, effectively making the object immutable after this function is called.
16
-
17
- Parameters
18
- ----------
19
- instance : object
20
- The object instance to make immutable
21
-
22
- Returns
23
- -------
24
- None
25
- The object is modified in-place
26
-
27
- Notes
28
- -----
29
- - This only affects direct attribute assignments and deletions
30
- - Mutable objects contained within the instance can still be modified internally
31
- - The object's class remains unchanged, only the specific instance is affected
32
- """
33
-
34
- def frozen_set(
35
- __name: str,
36
- __value: Any,
37
- ) -> None:
38
- raise RuntimeError(f"{instance.__class__.__qualname__} is frozen and can't be modified")
39
-
40
- def frozen_del(
41
- __name: str,
42
- ) -> None:
43
- raise RuntimeError(f"{instance.__class__.__qualname__} is frozen and can't be modified")
44
-
45
- instance.__delattr__ = frozen_del
46
- instance.__setattr__ = frozen_set
File without changes