haiway 0.10.16__py3-none-any.whl → 0.11.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/__init__.py CHANGED
@@ -9,7 +9,9 @@ from haiway.context import (
9
9
  MetricsScopeExiting,
10
10
  MissingContext,
11
11
  MissingState,
12
+ ScopeContext,
12
13
  ScopeIdentifier,
14
+ StateContext,
13
15
  ctx,
14
16
  )
15
17
  from haiway.helpers import (
@@ -78,8 +80,10 @@ __all__ = [
78
80
  "MissingContext",
79
81
  "MissingState",
80
82
  "ResultTrace",
83
+ "ScopeContext",
81
84
  "ScopeIdentifier",
82
85
  "State",
86
+ "StateContext",
83
87
  "always",
84
88
  "as_dict",
85
89
  "as_list",
@@ -1,4 +1,4 @@
1
- from haiway.context.access import ctx
1
+ from haiway.context.access import ScopeContext, ctx
2
2
  from haiway.context.disposables import Disposable, Disposables
3
3
  from haiway.context.identifier import ScopeIdentifier
4
4
  from haiway.context.metrics import (
@@ -9,6 +9,7 @@ from haiway.context.metrics import (
9
9
  MetricsScopeEntering,
10
10
  MetricsScopeExiting,
11
11
  )
12
+ from haiway.context.state import StateContext
12
13
  from haiway.context.types import MissingContext, MissingState
13
14
 
14
15
  __all__ = [
@@ -22,6 +23,8 @@ __all__ = [
22
23
  "MetricsScopeExiting",
23
24
  "MissingContext",
24
25
  "MissingState",
26
+ "ScopeContext",
25
27
  "ScopeIdentifier",
28
+ "StateContext",
26
29
  "ctx",
27
30
  ]
haiway/context/access.py CHANGED
@@ -1,4 +1,9 @@
1
- from asyncio import CancelledError, Task, current_task, iscoroutinefunction
1
+ from asyncio import (
2
+ CancelledError,
3
+ Task,
4
+ current_task,
5
+ iscoroutinefunction,
6
+ )
2
7
  from collections.abc import (
3
8
  AsyncGenerator,
4
9
  AsyncIterator,
haiway/state/path.py CHANGED
@@ -6,7 +6,7 @@ from collections import abc as collections_abc
6
6
  from collections import deque
7
7
  from collections.abc import Callable, Mapping, Sequence
8
8
  from copy import copy
9
- from typing import Any, final, get_args, get_origin, overload
9
+ from typing import Any, TypeAliasType, final, get_args, get_origin, overload
10
10
 
11
11
  from haiway.types import MISSING, Missing, not_missing
12
12
 
@@ -48,8 +48,8 @@ class PropertyAttributePathComponent(AttributePathComponent):
48
48
  attribute: type[Attribute],
49
49
  name: str,
50
50
  ) -> None:
51
- root_origin: Any = get_origin(root) or root
52
- attribute_origin: Any = get_origin(attribute) or attribute
51
+ root_origin: Any = _unaliased_origin(root)
52
+ attribute_origin: Any = _unaliased_origin(attribute)
53
53
 
54
54
  def access(
55
55
  subject: Root,
@@ -144,8 +144,8 @@ class SequenceItemAttributePathComponent(AttributePathComponent):
144
144
  attribute: type[Attribute],
145
145
  index: int,
146
146
  ) -> None:
147
- root_origin: Any = get_origin(root) or root
148
- attribute_origin: Any = get_origin(attribute) or attribute
147
+ root_origin: Any = _unaliased_origin(root)
148
+ attribute_origin: Any = _unaliased_origin(attribute)
149
149
 
150
150
  def access(
151
151
  subject: Root,
@@ -218,8 +218,8 @@ class MappingItemAttributePathComponent(AttributePathComponent):
218
218
  attribute: type[Attribute],
219
219
  key: str | int,
220
220
  ) -> None:
221
- root_origin: Any = get_origin(root) or root
222
- attribute_origin: Any = get_origin(attribute) or attribute
221
+ root_origin: Any = _unaliased_origin(root)
222
+ attribute_origin: Any = _unaliased_origin(attribute)
223
223
 
224
224
  def access(
225
225
  subject: Root,
@@ -373,9 +373,9 @@ class AttributePath[Root, Attribute]:
373
373
  self,
374
374
  key: str | int,
375
375
  ) -> Any:
376
- match get_origin(self.__attribute__) or self.__attribute__:
376
+ match _unaliased_origin(self.__attribute__):
377
377
  case collections_abc.Mapping | typing.Mapping | builtins.dict:
378
- match get_args(self.__attribute__):
378
+ match get_args(_unaliased(self.__attribute__)):
379
379
  case (builtins.str | builtins.int, element_annotation):
380
380
  return AttributePath[Root, Any](
381
381
  self.__root__,
@@ -403,7 +403,7 @@ class AttributePath[Root, Attribute]:
403
403
  self.__attribute__.__name__,
404
404
  )
405
405
 
406
- match get_args(self.__attribute__):
406
+ match get_args(_unaliased(self.__attribute__)):
407
407
  case (element_annotation, builtins.Ellipsis | types.EllipsisType):
408
408
  return AttributePath[Root, Any](
409
409
  self.__root__,
@@ -439,7 +439,7 @@ class AttributePath[Root, Attribute]:
439
439
  self.__attribute__.__name__,
440
440
  )
441
441
 
442
- match get_args(self.__attribute__):
442
+ match get_args(_unaliased(self.__attribute__)):
443
443
  case (element_annotation,):
444
444
  return AttributePath[Root, Any](
445
445
  self.__root__,
@@ -484,13 +484,13 @@ class AttributePath[Root, Attribute]:
484
484
  /,
485
485
  updated: Attribute | Missing = MISSING,
486
486
  ) -> Root | Attribute:
487
- assert isinstance(root, get_origin(self.__root__) or self.__root__), ( # nosec: B101
487
+ assert isinstance(root, _unaliased_origin(self.__root__)), ( # nosec: B101
488
488
  f"AttributePath '{self.__repr__()}' used on unexpected root of "
489
489
  f"'{type(root).__name__}' instead of '{self.__root__.__name__}'"
490
490
  )
491
491
 
492
492
  if not_missing(updated):
493
- assert isinstance(updated, get_origin(self.__attribute__) or self.__attribute__), ( # nosec: B101
493
+ assert isinstance(updated, _unaliased_origin(self.__attribute__)), ( # nosec: B101
494
494
  f"AttributePath '{self.__repr__()}' assigning to unexpected value of "
495
495
  f"'{type(updated).__name__}' instead of '{self.__attribute__.__name__}'"
496
496
  )
@@ -516,9 +516,27 @@ class AttributePath[Root, Attribute]:
516
516
  for component in self.__components__:
517
517
  resolved = component.access(resolved)
518
518
 
519
- assert isinstance(resolved, get_origin(self.__attribute__) or self.__attribute__), ( # nosec: B101
519
+ assert isinstance(resolved, _unaliased_origin(self.__attribute__)), ( # nosec: B101
520
520
  f"AttributePath '{self.__repr__()}' pointing to unexpected value of "
521
521
  f"'{type(resolved).__name__}' instead of '{self.__attribute__.__name__}'"
522
522
  )
523
523
 
524
524
  return resolved
525
+
526
+
527
+ def _unaliased_origin(base: type[Any]) -> type[Any]:
528
+ match base:
529
+ case TypeAliasType() as aliased:
530
+ return get_origin(aliased.__value__) or aliased.__value__
531
+
532
+ case concrete:
533
+ return get_origin(concrete) or concrete
534
+
535
+
536
+ def _unaliased(base: type[Any]) -> type[Any]:
537
+ match base:
538
+ case TypeAliasType() as aliased:
539
+ return aliased.__value__
540
+
541
+ case concrete:
542
+ return concrete
haiway/utils/queue.py CHANGED
@@ -23,9 +23,6 @@ class AsyncQueue[Element](AsyncIterator[Element]):
23
23
  self._waiting: Future[Element] | None = None
24
24
  self._finish_reason: BaseException | None = None
25
25
 
26
- def __del__(self) -> None:
27
- self.finish()
28
-
29
26
  @property
30
27
  def is_finished(self) -> bool:
31
28
  return self._finish_reason is not None
@@ -34,7 +31,6 @@ class AsyncQueue[Element](AsyncIterator[Element]):
34
31
  self,
35
32
  element: Element,
36
33
  /,
37
- *elements: Element,
38
34
  ) -> None:
39
35
  if self.is_finished:
40
36
  raise RuntimeError("AsyncQueue is already finished")
@@ -45,8 +41,6 @@ class AsyncQueue[Element](AsyncIterator[Element]):
45
41
  else:
46
42
  self._queue.append(element)
47
43
 
48
- self._queue.extend(elements)
49
-
50
44
  def finish(
51
45
  self,
52
46
  exception: BaseException | None = None,
@@ -57,7 +51,17 @@ class AsyncQueue[Element](AsyncIterator[Element]):
57
51
  self._finish_reason = exception or StopAsyncIteration()
58
52
 
59
53
  if self._waiting is not None and not self._waiting.done():
60
- self._waiting.set_exception(self._finish_reason)
54
+ # checking loop only on finish as the rest of operations
55
+ # should always have a valid loop in a typical environment
56
+ # and we are not supporting multithreading yet
57
+ if get_running_loop() is not self._loop:
58
+ self._loop.call_soon_threadsafe(
59
+ self._waiting.set_exception,
60
+ self._finish_reason,
61
+ )
62
+
63
+ else:
64
+ self._waiting.set_exception(self._finish_reason)
61
65
 
62
66
  def cancel(self) -> None:
63
67
  self.finish(exception=CancelledError())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: haiway
3
- Version: 0.10.16
3
+ Version: 0.11.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,7 +1,7 @@
1
- haiway/__init__.py,sha256=IEUCyFYKT5IPHnkiUvDVZHdJeHqCaBnG8FhPD20Zgo8,1929
1
+ haiway/__init__.py,sha256=PYMHx7JZwwSsALewho7v6EgIb5MUwYgZEWrVH-OhVx0,2005
2
2
  haiway/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- haiway/context/__init__.py,sha256=eRvuhifx7xCd-_6desgk55idzNpD5S5sprmCfGb3_9M,662
4
- haiway/context/access.py,sha256=Fc2NfoIV2zWE5qPnNgSitK1dy-PME-rJJfUPhoNwJzY,17125
3
+ haiway/context/__init__.py,sha256=feqd0eJnGQwh4B8BZXpS0fQRE-DqoFCFOHipF1jOY8A,762
4
+ haiway/context/access.py,sha256=KeAgxGf78TufqEUSwvw2LPY2aPE00z6xo3hvQ8L6QO4,17146
5
5
  haiway/context/disposables.py,sha256=DZjnMp-wMfF-em2Wjhbm1MvXubNpuzFBT70BQNIxC7M,2019
6
6
  haiway/context/identifier.py,sha256=Fyb6OHx5FPaSLLRK249HUEr_KlBSG5F-eW01Oxg_Ke8,2570
7
7
  haiway/context/logging.py,sha256=ptwgENuyw-WFgokVsYx9OXZGhJENuO_wgfVjcBryUKM,4251
@@ -19,7 +19,7 @@ haiway/helpers/timeouted.py,sha256=1xU09hQnFdj6p48BwZl5xUvtIr3zC0ZUXehkdrduCjs,3
19
19
  haiway/helpers/tracing.py,sha256=VDOAhdVELaYs92HxHreEo_ZV8b7e6ZQs10lTNn8xOtQ,3383
20
20
  haiway/state/__init__.py,sha256=emTuwGFn7HyjyTJ_ass69J5jQIA7_WHO4teZz_dR05Y,355
21
21
  haiway/state/attributes.py,sha256=plCcYGE5LVU1Nvo0GHkhThqFG96uLR3tFsisQyK1jK0,23122
22
- haiway/state/path.py,sha256=4vh-fYQv8_xRWjS0ErMQslKDWRI6-KVECAr8JhYk0UY,17503
22
+ haiway/state/path.py,sha256=p-ZVSDU02qAUDln12SDc1pGWzhZ88-1zYEBC0hqceXM,17930
23
23
  haiway/state/requirement.py,sha256=3iQqzp5Q7w6y5uClamJGH7S5Hib9pciuTAV27PP5lS8,6161
24
24
  haiway/state/structure.py,sha256=bSIj0S_HG-F1Z5GxSlY6VpGtrtiwG82-AIL_PL1lRLo,12465
25
25
  haiway/state/validation.py,sha256=r0EMIs-nvoXsmSA74oGu6Lrbw8lkzmseaY82_-E8ous,13814
@@ -35,8 +35,8 @@ 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=oQ3GXCJ-PGNtMEr6EPdgqAvYZoj8lAa7Z2drBKBEoBM,2345
39
- haiway-0.10.16.dist-info/METADATA,sha256=j02RHfNVzjysuMNaLot1JxcgYIWyqLfSJf2iInhHjyU,3858
40
- haiway-0.10.16.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
41
- haiway-0.10.16.dist-info/licenses/LICENSE,sha256=GehQEW_I1pkmxkkj3NEa7rCTQKYBn7vTPabpDYJlRuo,1063
42
- haiway-0.10.16.dist-info/RECORD,,
38
+ haiway/utils/queue.py,sha256=jmz5b4cDvdXpuFnAfrNsGB5wXx4ThCgLHbFlH54o8UY,2657
39
+ haiway-0.11.0.dist-info/METADATA,sha256=HWxQi7lFsvowR9D-wF-zNBHnIfMVq0i5Jlze3BAbVEo,3857
40
+ haiway-0.11.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
41
+ haiway-0.11.0.dist-info/licenses/LICENSE,sha256=GehQEW_I1pkmxkkj3NEa7rCTQKYBn7vTPabpDYJlRuo,1063
42
+ haiway-0.11.0.dist-info/RECORD,,