haiway 0.22.0__py3-none-any.whl → 0.23.0__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
  ----------
@@ -403,7 +403,7 @@ def _logger_observability(
403
403
  f"[{trace_id_hex}] {scope.unique_name} Recorded attributes: {format_str(attributes)}",
404
404
  )
405
405
 
406
- def scope_entering[Metric: State](
406
+ def scope_entering(
407
407
  scope: ScopeIdentifier,
408
408
  /,
409
409
  ) -> None:
@@ -412,7 +412,7 @@ def _logger_observability(
412
412
  f"[{trace_id_hex}] {scope.unique_name} Entering scope: {scope.label}",
413
413
  )
414
414
 
415
- def scope_exiting[Metric: State](
415
+ def scope_exiting(
416
416
  scope: ScopeIdentifier,
417
417
  /,
418
418
  *,
haiway/context/state.py CHANGED
@@ -37,6 +37,7 @@ class ScopeState:
37
37
  "_state",
38
38
  {type(element): element for element in state},
39
39
  )
40
+ assert all(issubclass(key, State) for key in self._state.keys()) # nosec: B101
40
41
  self._lock: Lock
41
42
  object.__setattr__(
42
43
  self,
@@ -67,6 +68,8 @@ class ScopeState:
67
68
  self,
68
69
  state: type[StateType],
69
70
  /,
71
+ *,
72
+ instantiate_defaults: bool = False,
70
73
  ) -> bool:
71
74
  """
72
75
  Check state object availability by its type.
@@ -79,6 +82,9 @@ class ScopeState:
79
82
  state: type[StateType]
80
83
  The type of state to check
81
84
 
85
+ instantiate_defaults: bool = False
86
+ Control if default value should be instantiated during check.
87
+
82
88
  Returns
83
89
  -------
84
90
  bool
@@ -87,7 +93,7 @@ class ScopeState:
87
93
  if state in self._state:
88
94
  return True
89
95
 
90
- else:
96
+ elif instantiate_defaults:
91
97
  with self._lock:
92
98
  if state in self._state:
93
99
  return True
@@ -100,6 +106,9 @@ class ScopeState:
100
106
  except BaseException:
101
107
  return False # unavailable, we don't care the exception
102
108
 
109
+ else:
110
+ return False
111
+
103
112
  def state[StateType: State](
104
113
  self,
105
114
  state: type[StateType],
@@ -201,6 +210,7 @@ class StateContext:
201
210
  cls,
202
211
  state: type[StateType],
203
212
  /,
213
+ instantiate_defaults: bool = False,
204
214
  ) -> bool:
205
215
  """
206
216
  Check if state object is available in the current context.
@@ -212,13 +222,19 @@ class StateContext:
212
222
  state: type[StateType]
213
223
  The type of state to check
214
224
 
225
+ instantiate_defaults: bool = False
226
+ Control if default value should be instantiated during check.
227
+
215
228
  Returns
216
229
  -------
217
230
  bool
218
231
  True if state is available, otherwise False.
219
232
  """
220
233
  try:
221
- return cls._context.get().check_state(state)
234
+ return cls._context.get().check_state(
235
+ state,
236
+ instantiate_defaults=instantiate_defaults,
237
+ )
222
238
 
223
239
  except LookupError:
224
240
  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__ = (
@@ -6,7 +6,6 @@ from uuid import UUID, uuid4
6
6
 
7
7
  from haiway.context import Observability, ObservabilityLevel, ScopeIdentifier
8
8
  from haiway.context.observability import ObservabilityAttribute
9
- from haiway.state import State
10
9
  from haiway.utils.formatting import format_str
11
10
 
12
11
  __all__ = ("LoggerObservability",)
@@ -232,7 +231,7 @@ def LoggerObservability( # noqa: C901, PLR0915
232
231
  f"[{trace_id_hex}] {scope.unique_name} {attributes_str}",
233
232
  )
234
233
 
235
- def scope_entering[Metric: State](
234
+ def scope_entering(
236
235
  scope: ScopeIdentifier,
237
236
  /,
238
237
  ) -> None:
@@ -255,7 +254,7 @@ def LoggerObservability( # noqa: C901, PLR0915
255
254
  f"[{trace_id_hex}] {scope.unique_name} Entering scope: {scope.label}",
256
255
  )
257
256
 
258
- def scope_exiting[Metric: State](
257
+ def scope_exiting(
259
258
  scope: ScopeIdentifier,
260
259
  /,
261
260
  *,
@@ -1,5 +1,5 @@
1
1
  import os
2
- from collections.abc import Mapping
2
+ from collections.abc import Mapping, Sequence
3
3
  from typing import Any, ClassVar, Self, cast, final
4
4
  from uuid import UUID
5
5
 
@@ -26,12 +26,16 @@ from opentelemetry.sdk.metrics.export import ConsoleMetricExporter, PeriodicExpo
26
26
  from opentelemetry.sdk.resources import Resource
27
27
  from opentelemetry.sdk.trace import TracerProvider
28
28
  from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter, SpanExporter
29
- from opentelemetry.trace import Span, StatusCode, Tracer
30
- from opentelemetry.trace.span import SpanContext
31
-
32
- from haiway.context import Observability, ObservabilityLevel, ScopeIdentifier
33
- from haiway.context.observability import ObservabilityAttribute
34
- from haiway.state import State
29
+ from opentelemetry.sdk.trace.id_generator import RandomIdGenerator
30
+ from opentelemetry.trace import Link, Span, SpanContext, StatusCode, TraceFlags, Tracer
31
+
32
+ from haiway.context import (
33
+ Observability,
34
+ ObservabilityAttribute,
35
+ ObservabilityLevel,
36
+ ScopeIdentifier,
37
+ ctx,
38
+ )
35
39
  from haiway.types import MISSING
36
40
 
37
41
  __all__ = ("OpenTelemetry",)
@@ -437,6 +441,8 @@ class OpenTelemetry:
437
441
  def observability( # noqa: C901, PLR0915
438
442
  cls,
439
443
  level: ObservabilityLevel = ObservabilityLevel.INFO,
444
+ *,
445
+ external_trace_id: str | None = None,
440
446
  ) -> Observability:
441
447
  """
442
448
  Create an Observability implementation using OpenTelemetry.
@@ -449,6 +455,9 @@ class OpenTelemetry:
449
455
  ----------
450
456
  level : ObservabilityLevel, default=ObservabilityLevel.INFO
451
457
  The minimum observability level to record
458
+ external_trace_id : str | None, optional
459
+ External trace ID for distributed tracing context propagation.
460
+ If provided, the root span will be linked to this external trace.
452
461
 
453
462
  Returns
454
463
  -------
@@ -645,7 +654,7 @@ class OpenTelemetry:
645
654
 
646
655
  scopes[scope.scope_id].record_attributes(attributes)
647
656
 
648
- def scope_entering[Metric: State](
657
+ def scope_entering(
649
658
  scope: ScopeIdentifier,
650
659
  /,
651
660
  ) -> None:
@@ -678,17 +687,44 @@ class OpenTelemetry:
678
687
  scope_store: ScopeStore
679
688
  if root_scope is None:
680
689
  meter = metrics.get_meter(scope.label)
681
- context: Context = Context(
682
- **get_current(),
683
- # trace_id=scope.trace_id,
684
- # span_id=scope.scope_id,
685
- )
690
+ context: Context = get_current()
691
+
692
+ # Handle distributed tracing with external trace ID
693
+ links: Sequence[Link] | None = None
694
+ if external_trace_id is not None:
695
+ # Convert external trace ID to OpenTelemetry trace ID format
696
+ try:
697
+ # Generate a proper span ID for the external trace link
698
+ id_generator = RandomIdGenerator()
699
+
700
+ # Create a link to the external trace
701
+ links = (
702
+ Link(
703
+ SpanContext(
704
+ ( # Assume external_trace_id is a hex string, convert to int
705
+ int(external_trace_id, 16)
706
+ if isinstance(external_trace_id, str)
707
+ else int(external_trace_id)
708
+ ),
709
+ id_generator.generate_span_id(), # Generate proper span ID
710
+ True, # is_remote=True
711
+ TraceFlags.SAMPLED, # pyright: ignore[reportArgumentType]
712
+ )
713
+ ),
714
+ )
715
+
716
+ except (ValueError, TypeError):
717
+ ctx.log_warning(
718
+ "Failed to convert external trace ID to OpenTelemetry format"
719
+ )
720
+
686
721
  scope_store = ScopeStore(
687
722
  scope,
688
723
  context=context,
689
724
  span=tracer.start_span(
690
725
  name=scope.label,
691
726
  context=context,
727
+ links=links,
692
728
  ),
693
729
  meter=meter,
694
730
  logger=get_logger(scope.label),
@@ -711,7 +747,7 @@ class OpenTelemetry:
711
747
 
712
748
  scopes[scope.scope_id] = scope_store
713
749
 
714
- def scope_exiting[Metric: State](
750
+ def scope_exiting(
715
751
  scope: ScopeIdentifier,
716
752
  /,
717
753
  *,
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.23.0
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,46 +1,45 @@
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
- haiway/context/observability.py,sha256=gLKbMPNvt5ozrfyc4TGahN8A_dFFtyCjUIMZu9_wZHA,23722
8
- haiway/context/state.py,sha256=Ni6NUbRYKmgi7HhvosrVH62IzfalLDUH7VYRwpUiQ78,11426
7
+ haiway/context/observability.py,sha256=E-TDqqJ_EnHkFTspEjyA61O0iIbEev15YUn5d3yHhvU,23692
8
+ haiway/context/state.py,sha256=Codc_F5Ngsk4x80nkNuwpvXpZ-mht3joOgcgJ7vKpVg,12000
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
15
15
  haiway/helpers/files.py,sha256=L6vXd8gdgWx5jPL8azloU8IGoFq2xnxjMc4ufz-gdl4,11650
16
- haiway/helpers/observability.py,sha256=3G0eRE1WYTGRujS0mxzYbLR4MlKnoYllE8cu2Eb_23w,11073
16
+ haiway/helpers/observability.py,sha256=jCJzOPJ5E3RKJsbbGRR1O-mZydaHNIGkIpppOH7nFBA,11012
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
- haiway/opentelemetry/observability.py,sha256=5fsHsFgjcxUcA0hIOM18lVvVdYSRO91ER52PticyzyU,25734
22
+ haiway/opentelemetry/observability.py,sha256=akGAPX6_958BxCfzlLnoDJHPtEvztdMnfMA1oiJL48Y,27370
23
23
  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.23.0.dist-info/METADATA,sha256=TAlSBtVIn8VCcK_qsmQ9how4K-ULVga-lP04ZS9M1AQ,4919
43
+ haiway-0.23.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
44
+ haiway-0.23.0.dist-info/licenses/LICENSE,sha256=3phcpHVNBP8jsi77gOO0E7rgKeDeu99Pi7DSnK9YHoQ,1069
45
+ haiway-0.23.0.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