haiway 0.20.0__py3-none-any.whl → 0.21.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
@@ -5,15 +5,8 @@ from haiway.context import (
5
5
  MissingState,
6
6
  Observability,
7
7
  ObservabilityAttribute,
8
- ObservabilityAttributesRecording,
9
8
  ObservabilityContext,
10
- ObservabilityEventRecording,
11
9
  ObservabilityLevel,
12
- ObservabilityLogRecording,
13
- ObservabilityMetricRecording,
14
- ObservabilityScopeEntering,
15
- ObservabilityScopeExiting,
16
- ObservabilityTraceIdentifying,
17
10
  ScopeContext,
18
11
  ScopeIdentifier,
19
12
  StateContext,
@@ -28,7 +21,6 @@ from haiway.helpers import (
28
21
  throttle,
29
22
  timeout,
30
23
  traced,
31
- wrap_async,
32
24
  )
33
25
  from haiway.state import AttributePath, AttributeRequirement, State
34
26
  from haiway.types import (
@@ -36,7 +28,6 @@ from haiway.types import (
36
28
  Default,
37
29
  DefaultValue,
38
30
  Missing,
39
- frozenlist,
40
31
  is_missing,
41
32
  not_missing,
42
33
  when_missing,
@@ -51,14 +42,12 @@ from haiway.utils import (
51
42
  as_tuple,
52
43
  async_always,
53
44
  async_noop,
54
- freeze,
55
45
  getenv_base64,
56
46
  getenv_bool,
57
47
  getenv_float,
58
48
  getenv_int,
59
49
  getenv_str,
60
50
  load_env,
61
- mimic_function,
62
51
  noop,
63
52
  setup_logging,
64
53
  without_missing,
@@ -80,15 +69,8 @@ __all__ = (
80
69
  "MissingState",
81
70
  "Observability",
82
71
  "ObservabilityAttribute",
83
- "ObservabilityAttributesRecording",
84
72
  "ObservabilityContext",
85
- "ObservabilityEventRecording",
86
73
  "ObservabilityLevel",
87
- "ObservabilityLogRecording",
88
- "ObservabilityMetricRecording",
89
- "ObservabilityScopeEntering",
90
- "ObservabilityScopeExiting",
91
- "ObservabilityTraceIdentifying",
92
74
  "ScopeContext",
93
75
  "ScopeIdentifier",
94
76
  "State",
@@ -103,8 +85,6 @@ __all__ = (
103
85
  "asynchronous",
104
86
  "cache",
105
87
  "ctx",
106
- "freeze",
107
- "frozenlist",
108
88
  "getenv_base64",
109
89
  "getenv_bool",
110
90
  "getenv_float",
@@ -112,7 +92,6 @@ __all__ = (
112
92
  "getenv_str",
113
93
  "is_missing",
114
94
  "load_env",
115
- "mimic_function",
116
95
  "noop",
117
96
  "not_missing",
118
97
  "process_concurrently",
@@ -123,5 +102,4 @@ __all__ = (
123
102
  "traced",
124
103
  "when_missing",
125
104
  "without_missing",
126
- "wrap_async",
127
105
  )
@@ -1,4 +1,4 @@
1
- from haiway.helpers.asynchrony import asynchronous, wrap_async
1
+ from haiway.helpers.asynchrony import asynchronous
2
2
  from haiway.helpers.caching import CacheMakeKey, CacheRead, CacheWrite, cache
3
3
  from haiway.helpers.concurrent import process_concurrently
4
4
  from haiway.helpers.observability import LoggerObservability
@@ -19,5 +19,4 @@ __all__ = (
19
19
  "throttle",
20
20
  "timeout",
21
21
  "traced",
22
- "wrap_async",
23
22
  )
@@ -7,51 +7,16 @@ from typing import Any, cast, overload
7
7
 
8
8
  from haiway.types.missing import MISSING, Missing
9
9
 
10
- __all__ = (
11
- "asynchronous",
12
- "wrap_async",
13
- )
14
-
15
-
16
- def wrap_async[**Args, Result](
17
- function: Callable[Args, Coroutine[Any, Any, Result]] | Callable[Args, Result],
18
- /,
19
- ) -> Callable[Args, Coroutine[Any, Any, Result]]:
20
- """
21
- Convert a synchronous function to an asynchronous one if it isn't already.
22
-
23
- Takes a function that may be either synchronous or asynchronous and ensures it
24
- returns a coroutine. If the input function is already asynchronous, it is returned
25
- unchanged. If it's synchronous, it wraps it in an async function that executes
26
- the original function and returns its result.
27
-
28
- Parameters
29
- ----------
30
- function: Callable[Args, Coroutine[Any, Any, Result]] | Callable[Args, Result]
31
- The function to ensure is asynchronous, can be either sync or async
32
-
33
- Returns
34
- -------
35
- Callable[Args, Coroutine[Any, Any, Result]]
36
- An asynchronous function that returns a coroutine
37
- """
38
- if iscoroutinefunction(function):
39
- return function
40
-
41
- else:
42
-
43
- async def async_function(*args: Args.args, **kwargs: Args.kwargs) -> Result:
44
- return cast(Callable[Args, Result], function)(*args, **kwargs)
45
-
46
- _mimic_async(function, within=async_function)
47
- return async_function
10
+ __all__ = ("asynchronous",)
48
11
 
49
12
 
50
13
  @overload
51
- def asynchronous[**Args, Result]() -> Callable[
52
- [Callable[Args, Result]],
53
- Callable[Args, Coroutine[Any, Any, Result]],
54
- ]: ...
14
+ def asynchronous[**Args, Result]() -> (
15
+ Callable[
16
+ [Callable[Args, Result]],
17
+ Callable[Args, Coroutine[Any, Any, Result]],
18
+ ]
19
+ ): ...
55
20
 
56
21
 
57
22
  @overload
@@ -142,11 +107,18 @@ def asynchronous[**Args, Result](
142
107
  ) -> Callable[Args, Coroutine[Any, Any, Result]]:
143
108
  assert not iscoroutinefunction(wrapped), "Cannot wrap async function in executor" # nosec: B101
144
109
 
145
- return _ExecutorWrapper(
146
- wrapped,
147
- loop=loop,
148
- executor=cast(Executor | None, None if executor is MISSING else executor),
149
- )
110
+ async def asynchronous(
111
+ *args: Args.args,
112
+ **kwargs: Args.kwargs,
113
+ ) -> Result:
114
+ context: Context = copy_context()
115
+ return await (loop or get_running_loop()).run_in_executor(
116
+ cast(Executor | None, None if executor is MISSING else executor),
117
+ context.run,
118
+ partial(wrapped, *args, **kwargs),
119
+ )
120
+
121
+ return _mimic_async(wrapped, within=asynchronous)
150
122
 
151
123
  if function := function:
152
124
  return wrap(wrapped=function)
@@ -155,77 +127,6 @@ def asynchronous[**Args, Result](
155
127
  return wrap
156
128
 
157
129
 
158
- class _ExecutorWrapper[**Args, Result]:
159
- __slots__ = (
160
- "__annotations__",
161
- "__defaults__",
162
- "__doc__",
163
- "__globals__",
164
- "__kwdefaults__",
165
- "__name__",
166
- "__qualname__",
167
- "__wrapped__",
168
- "_executor",
169
- "_function",
170
- "_loop",
171
- )
172
-
173
- def __init__(
174
- self,
175
- function: Callable[Args, Result],
176
- /,
177
- loop: AbstractEventLoop | None,
178
- executor: Executor | None,
179
- ) -> None:
180
- self._function: Callable[Args, Result] = function
181
- self._loop: AbstractEventLoop | None = loop
182
- self._executor: Executor | None = executor
183
-
184
- # mimic function attributes if able
185
- _mimic_async(function, within=self)
186
-
187
- async def __call__(
188
- self,
189
- *args: Args.args,
190
- **kwargs: Args.kwargs,
191
- ) -> Result:
192
- context: Context = copy_context()
193
- return await (self._loop or get_running_loop()).run_in_executor(
194
- self._executor,
195
- context.run,
196
- partial(self._function, *args, **kwargs),
197
- )
198
-
199
- def __get__(
200
- self,
201
- instance: object,
202
- owner: type | None = None,
203
- /,
204
- ) -> Callable[Args, Coroutine[Any, Any, Result]]:
205
- if owner is None:
206
- return self
207
-
208
- else:
209
- return _mimic_async(
210
- self._function,
211
- within=partial(
212
- self.__method_call__,
213
- instance,
214
- ),
215
- )
216
-
217
- async def __method_call__(
218
- self,
219
- __method_self: object,
220
- *args: Args.args,
221
- **kwargs: Args.kwargs,
222
- ) -> Result:
223
- return await (self._loop or get_running_loop()).run_in_executor(
224
- self._executor,
225
- partial(self._function, __method_self, *args, **kwargs),
226
- )
227
-
228
-
229
130
  def _mimic_async[**Args, Result](
230
131
  function: Callable[Args, Result],
231
132
  /,
@@ -8,7 +8,7 @@ from haiway.context import ctx
8
8
  __all__ = ("process_concurrently",)
9
9
 
10
10
 
11
- async def process_concurrently[Element]( # noqa: C901
11
+ async def process_concurrently[Element]( # noqa: C901, PLR0912
12
12
  source: AsyncIterator[Element],
13
13
  /,
14
14
  handler: Callable[[Element], Coroutine[Any, Any, None]],
@@ -37,12 +37,16 @@ async def process_concurrently[Element]( # noqa: C901
37
37
  assert concurrent_tasks > 0 # nosec: B101
38
38
  running: set[Task[None]] = set()
39
39
  try:
40
- while element := await anext(source, None):
40
+ while True:
41
+ element: Element = await anext(source)
42
+ running.add(ctx.spawn(handler, element))
41
43
  if len(running) < concurrent_tasks:
42
- running.add(ctx.spawn(handler, element))
43
44
  continue # keep spawning tasks
44
45
 
45
- completed, running = await wait(running, return_when=FIRST_COMPLETED)
46
+ completed, running = await wait(
47
+ running,
48
+ return_when=FIRST_COMPLETED,
49
+ )
46
50
 
47
51
  for task in completed:
48
52
  if exc := task.exception():
@@ -61,14 +65,21 @@ async def process_concurrently[Element]( # noqa: C901
61
65
 
62
66
  raise exc
63
67
 
68
+ except StopAsyncIteration:
69
+ pass # just stop and proceed to finally
70
+
64
71
  finally:
65
- completed, _ = await wait(running, return_when=ALL_COMPLETED)
66
- for task in completed:
67
- if exc := task.exception():
68
- if not ignore_exceptions:
69
- raise exc
70
-
71
- ctx.log_error(
72
- f"Concurrent processing error - {type(exc)}: {exc}",
73
- exception=exc,
74
- )
72
+ if running:
73
+ completed, _ = await wait(
74
+ running,
75
+ return_when=ALL_COMPLETED,
76
+ )
77
+ for task in completed:
78
+ if exc := task.exception():
79
+ if not ignore_exceptions:
80
+ raise exc
81
+
82
+ ctx.log_error(
83
+ f"Concurrent processing error - {type(exc)}: {exc}",
84
+ exception=exc,
85
+ )
@@ -7,7 +7,7 @@ from collections import deque
7
7
  from collections.abc import Callable, Coroutine
8
8
  from datetime import timedelta
9
9
  from time import monotonic
10
- from typing import Any, cast, overload
10
+ from typing import Any, overload
11
11
 
12
12
  from haiway.utils.mimic import mimic_function
13
13
 
@@ -97,14 +97,38 @@ def throttle[**Args, Result](
97
97
  function: Callable[Args, Coroutine[Any, Any, Result]],
98
98
  ) -> Callable[Args, Coroutine[Any, Any, Result]]:
99
99
  assert iscoroutinefunction(function) # nosec: B101
100
- return cast(
101
- Callable[Args, Coroutine[Any, Any, Result]],
102
- _AsyncThrottle(
103
- function,
104
- limit=limit,
105
- period=period,
106
- ),
107
- )
100
+ entries: deque[float] = deque()
101
+ lock: Lock = Lock()
102
+ throttle_period: float
103
+ match period:
104
+ case timedelta() as delta:
105
+ throttle_period = delta.total_seconds()
106
+
107
+ case period_seconds:
108
+ throttle_period = period_seconds
109
+
110
+ async def throttle(
111
+ *args: Args.args,
112
+ **kwargs: Args.kwargs,
113
+ ) -> Result:
114
+ async with lock:
115
+ time_now: float = monotonic()
116
+ while entries: # cleanup old entries
117
+ if entries[0] + throttle_period <= time_now:
118
+ entries.popleft()
119
+
120
+ else:
121
+ break
122
+
123
+ if len(entries) >= limit:
124
+ await sleep(entries[0] - time_now)
125
+
126
+ entries.append(monotonic())
127
+
128
+ return await function(*args, **kwargs)
129
+
130
+ # mimic function attributes if able
131
+ return mimic_function(function, within=throttle)
108
132
 
109
133
  if function := function:
110
134
  return _wrap(function)
@@ -199,7 +199,7 @@ class AttributeRequirement[Root]:
199
199
 
200
200
  def check_contains_any(root: Root) -> None:
201
201
  checked: Any = cast(AttributePath[Root, Parameter], path)(root)
202
- if any(element in checked for element in value):
202
+ if not any(element in checked for element in value):
203
203
  raise ValueError(
204
204
  f"{checked} does not contain any of {value} for '{path.__repr__()}'"
205
205
  )
haiway/state/structure.py CHANGED
@@ -551,6 +551,14 @@ class State(metaclass=StateMeta):
551
551
  case _:
552
552
  raise TypeError(f"Expected '{cls.__name__}', received '{type(value).__name__}'")
553
553
 
554
+ @classmethod
555
+ def from_mapping(
556
+ cls,
557
+ value: Mapping[str, Any],
558
+ /,
559
+ ) -> Self:
560
+ return cls(**value)
561
+
554
562
  def __init__(
555
563
  self,
556
564
  **kwargs: Any,
haiway/types/__init__.py CHANGED
@@ -1,5 +1,4 @@
1
1
  from haiway.types.default import Default, DefaultValue
2
- from haiway.types.frozen import frozenlist
3
2
  from haiway.types.missing import MISSING, Missing, is_missing, not_missing, when_missing
4
3
 
5
4
  __all__ = (
@@ -7,7 +6,6 @@ __all__ = (
7
6
  "Default",
8
7
  "DefaultValue",
9
8
  "Missing",
10
- "frozenlist",
11
9
  "is_missing",
12
10
  "not_missing",
13
11
  "when_missing",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: haiway
3
- Version: 0.20.0
3
+ Version: 0.21.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
@@ -42,13 +42,17 @@ Requires-Dist: pytest-cov~=6.1; extra == 'dev'
42
42
  Requires-Dist: pytest~=8.3; extra == 'dev'
43
43
  Requires-Dist: ruff~=0.11; extra == 'dev'
44
44
  Provides-Extra: opentelemetry
45
- Requires-Dist: opentelemetry-api; extra == 'opentelemetry'
46
- Requires-Dist: opentelemetry-exporter-otlp-proto-grpc; extra == 'opentelemetry'
47
- Requires-Dist: opentelemetry-sdk; extra == 'opentelemetry'
45
+ Requires-Dist: opentelemetry-api~=1.33; extra == 'opentelemetry'
46
+ Requires-Dist: opentelemetry-exporter-otlp-proto-grpc~=1.33; extra == 'opentelemetry'
47
+ Requires-Dist: opentelemetry-sdk~=1.33; extra == 'opentelemetry'
48
48
  Description-Content-Type: text/markdown
49
49
 
50
50
  # 🚗 haiway 🚕 🚚 🚙
51
51
 
52
+ ![Python Version](https://img.shields.io/badge/Python-3.12+-blue)
53
+ ![License](https://img.shields.io/badge/License-MIT-green)
54
+ ![CodeRabbit Pull Request Reviews](https://img.shields.io/coderabbit/prs/github/miquido/haiway?utm_source=oss&utm_medium=github&utm_campaign=miquido%2Fhaiway&labelColor=171717&color=FF570A&link=https%3A%2F%2Fcoderabbit.ai&label=CodeRabbit+Reviews)
55
+
52
56
  haiway is a framework designed to facilitate the development of applications using the functional programming paradigm combined with structured concurrency concepts. Unlike traditional object-oriented frameworks, haiway emphasizes immutability, pure functions, and context-based state management, enabling developers to build scalable and maintainable applications. By leveraging context managers combined with context vars, haiway ensures safe state propagation in concurrent environments and simplifies dependency injection through function implementation propagation.
53
57
 
54
58
  ## 🖥️ Install
@@ -1,4 +1,4 @@
1
- haiway/__init__.py,sha256=swH9O_-cvHnZ8hC2AyxxL02M8cGldI0f_Be_l9C1rUY,2479
1
+ haiway/__init__.py,sha256=keuz9FN8VqLamqrzvjK2IAjkdyyFcnboDrB9xkFPgXk,1861
2
2
  haiway/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  haiway/context/__init__.py,sha256=1N_SvdPkTfIZDZybm3y0rY2dGrDLWTm0ryzUz2XD4f8,1174
4
4
  haiway/context/access.py,sha256=lDvkMoqUOwzBt-P8mI-VggS2wrP_BJLmYrArdj8z4SE,21644
@@ -8,13 +8,13 @@ haiway/context/observability.py,sha256=gLKbMPNvt5ozrfyc4TGahN8A_dFFtyCjUIMZu9_wZ
8
8
  haiway/context/state.py,sha256=tRJRvd07XObhdayz-1OcNxABqcHQRD_k_yUGsn72wDU,9541
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=_A-JYAPemd-2o4NxxchaZENu8gANL8QDxK5ADzInXUU,670
12
- haiway/helpers/asynchrony.py,sha256=2NtuMklKHyU2o7H_Y_wyN6mxa13wdgI6yETjPbgSHPA,8136
11
+ haiway/helpers/__init__.py,sha256=WzQFUHAX0NtpbdKycHywTyxfMGmid91y0vfmdIHX-NE,640
12
+ haiway/helpers/asynchrony.py,sha256=FGJA4BhTa5qcA9PTxsloC5mReoSfkEY6uieLU2K3bCs,5376
13
13
  haiway/helpers/caching.py,sha256=BqgcUGQSAmXsuLi5V8EwlZzuGyutHOn1V4k7BHsGKeg,14347
14
- haiway/helpers/concurrent.py,sha256=04pWpS7qOQDD1pa2ifhFwedPcl4sRinhe-KgyDe5GF0,2296
14
+ haiway/helpers/concurrent.py,sha256=xGMcan_tiETAHQs1YFmgYpA4YMFo6rIbFKvNeMlRFG8,2551
15
15
  haiway/helpers/observability.py,sha256=3G0eRE1WYTGRujS0mxzYbLR4MlKnoYllE8cu2Eb_23w,11073
16
16
  haiway/helpers/retries.py,sha256=52LA85HejTiSmCmTMAA9c8oUqD_VnhbTn1b3kwlU52c,9032
17
- haiway/helpers/throttling.py,sha256=hwhruBXepve2TJA4vsaO4WwTFkclt5eNiZ8U0mo-mlI,5015
17
+ haiway/helpers/throttling.py,sha256=KBWUSHdKVMC5_nRMmmoPNwfp-3AcerQ6OczJa9gNLM0,5796
18
18
  haiway/helpers/timeouted.py,sha256=GQ8-btb36f0Jq7TnorAPYXyKScNmf0nxHXCYxqGl-o8,3949
19
19
  haiway/helpers/tracing.py,sha256=NHipA5UlngwFcAaKhXg1jTuJ-ti6AqSNxE7u7-92vWo,5409
20
20
  haiway/opentelemetry/__init__.py,sha256=TV-1C14mDAtcHhFZ29ActFQdrGH6x5KuGV9w-JlKYJg,91
@@ -22,12 +22,11 @@ haiway/opentelemetry/observability.py,sha256=5fsHsFgjcxUcA0hIOM18lVvVdYSRO91ER52
22
22
  haiway/state/__init__.py,sha256=AaMqlMhO4zKS_XNevy3A7BHh5PxmguA-Sk_FnaNDY1Q,355
23
23
  haiway/state/attributes.py,sha256=sububiFP23aBB8RGk6OvTUp7BEY6S0kER_uHC09yins,26733
24
24
  haiway/state/path.py,sha256=bv5MI3HmUyku78k0Sz5lc7Q_Bay53iom1l3AL5KZs-4,32143
25
- haiway/state/requirement.py,sha256=_tA6CPyFX6WTjJ0Yk2jeMs-At17ex8Yl8y1-s24idas,12793
26
- haiway/state/structure.py,sha256=wZqTcX3BaKbjMSKjAukPHfR9A_nQibLW9i_BWpWUVYs,23118
25
+ haiway/state/requirement.py,sha256=NbXL7JrB-zGE6KShcRRtq-wJbKu5lHlhFdmfhyJZdkc,12797
26
+ haiway/state/structure.py,sha256=KKIId-mrHAzGjYKKlvnlscMijVZVM8nDLnAwCFn1sTc,23259
27
27
  haiway/state/validation.py,sha256=eDOZKRrfd-dmdbqoHcLacdCVKmVCEpwt239EG6ljNF8,23557
28
- haiway/types/__init__.py,sha256=73DMgf60Ftf1gLRCSQG66Nyu3_QFjdRJggBtS4-RQkY,342
28
+ haiway/types/__init__.py,sha256=jFr5kf36SvVGdgngvik6_HzG8YNa3NVsdDDSqxVuGm4,281
29
29
  haiway/types/default.py,sha256=59chcOaoGqI2to08RamCCLluimfYbJp5xbYl3fWaLrM,4153
30
- haiway/types/frozen.py,sha256=Zb9P0IpB-YgOrnHwiGqPk8AvyH-ABX7jajS9m3kzjBk,701
31
30
  haiway/types/missing.py,sha256=bVlOJN0Z04gALKj01Ah6_sWbC94mwRatdEcW7neLAsY,4188
32
31
  haiway/utils/__init__.py,sha256=HOylRgBEa0uNxEuPBupaJ28l4wEQiy98cGJi2Gtirr4,972
33
32
  haiway/utils/always.py,sha256=dd6jDQ1j4DpJjTKO1J2Tv5xS8X1LnMC4kQ0D7DtKUvw,1230
@@ -40,7 +39,7 @@ haiway/utils/mimic.py,sha256=L5AS4WEL2aPMZAQZlvLvRzHl0cipI7ivky60_eL4iwY,1822
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.20.0.dist-info/METADATA,sha256=QbQTKdDVsoT878zfWl1NwrbEPo8z5dPvC1EO29OiBMk,4527
44
- haiway-0.20.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
45
- haiway-0.20.0.dist-info/licenses/LICENSE,sha256=3phcpHVNBP8jsi77gOO0E7rgKeDeu99Pi7DSnK9YHoQ,1069
46
- haiway-0.20.0.dist-info/RECORD,,
42
+ haiway-0.21.0.dist-info/METADATA,sha256=WzaFZVy8PEbnLUC-Hqy6YUcPcStmzj3KVdM6sE4DdM0,4919
43
+ haiway-0.21.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
44
+ haiway-0.21.0.dist-info/licenses/LICENSE,sha256=3phcpHVNBP8jsi77gOO0E7rgKeDeu99Pi7DSnK9YHoQ,1069
45
+ haiway-0.21.0.dist-info/RECORD,,
haiway/types/frozen.py DELETED
@@ -1,21 +0,0 @@
1
- __all__ = ("frozenlist",)
2
-
3
- type frozenlist[Value] = tuple[Value, ...]
4
- """
5
- A type alias for an immutable sequence of values.
6
-
7
- This type represents an immutable list-like structure (implemented as a tuple)
8
- that can be used when an immutable sequence is required. It provides the same
9
- indexing and iteration capabilities as a list, but cannot be modified after creation.
10
-
11
- The generic parameter Value specifies the type of elements stored in the sequence.
12
-
13
- Examples
14
- --------
15
- ```python
16
- items: frozenlist[int] = (1, 2, 3) # Create a frozen list of integers
17
- first_item = items[0] # Access elements by index
18
- for item in items: # Iterate over elements
19
- process(item)
20
- ```
21
- """