haiway 0.19.5__py3-none-any.whl → 0.20.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 +2 -0
- haiway/context/__init__.py +2 -0
- haiway/context/access.py +88 -8
- haiway/context/disposables.py +63 -0
- haiway/context/identifier.py +81 -27
- haiway/context/observability.py +303 -7
- haiway/context/state.py +126 -0
- haiway/context/tasks.py +66 -0
- haiway/context/types.py +16 -0
- haiway/helpers/asynchrony.py +61 -12
- haiway/helpers/caching.py +31 -0
- haiway/helpers/observability.py +94 -11
- haiway/helpers/retries.py +59 -18
- haiway/helpers/throttling.py +42 -15
- haiway/helpers/timeouted.py +25 -10
- haiway/helpers/tracing.py +31 -0
- haiway/opentelemetry/observability.py +346 -29
- haiway/state/attributes.py +104 -0
- haiway/state/path.py +427 -12
- haiway/state/requirement.py +196 -0
- haiway/state/structure.py +359 -1
- haiway/state/validation.py +293 -0
- haiway/types/default.py +56 -0
- haiway/types/frozen.py +18 -0
- haiway/types/missing.py +89 -0
- haiway/utils/collections.py +36 -28
- haiway/utils/env.py +145 -13
- haiway/utils/formatting.py +27 -0
- haiway/utils/freezing.py +21 -1
- haiway/utils/noop.py +34 -2
- haiway/utils/queue.py +68 -1
- haiway/utils/stream.py +83 -0
- {haiway-0.19.5.dist-info → haiway-0.20.0.dist-info}/METADATA +1 -1
- haiway-0.20.0.dist-info/RECORD +46 -0
- haiway-0.19.5.dist-info/RECORD +0 -46
- {haiway-0.19.5.dist-info → haiway-0.20.0.dist-info}/WHEEL +0 -0
- {haiway-0.19.5.dist-info → haiway-0.20.0.dist-info}/licenses/LICENSE +0 -0
haiway/state/validation.py
CHANGED
@@ -18,6 +18,13 @@ __all__ = (
|
|
18
18
|
|
19
19
|
|
20
20
|
class AttributeValidation[Type](Protocol):
|
21
|
+
"""
|
22
|
+
Protocol defining the interface for attribute validation functions.
|
23
|
+
|
24
|
+
These functions validate and potentially transform input values to
|
25
|
+
ensure they conform to the expected type or format.
|
26
|
+
"""
|
27
|
+
|
21
28
|
def __call__(
|
22
29
|
self,
|
23
30
|
value: Any,
|
@@ -26,11 +33,26 @@ class AttributeValidation[Type](Protocol):
|
|
26
33
|
|
27
34
|
|
28
35
|
class AttributeValidationError(Exception):
|
36
|
+
"""
|
37
|
+
Exception raised when attribute validation fails.
|
38
|
+
|
39
|
+
This exception indicates that a value failed to meet the
|
40
|
+
validation requirements for an attribute.
|
41
|
+
"""
|
42
|
+
|
29
43
|
pass
|
30
44
|
|
31
45
|
|
32
46
|
@final
|
33
47
|
class AttributeValidator[Type]:
|
48
|
+
"""
|
49
|
+
Creates and manages validation functions for attribute types.
|
50
|
+
|
51
|
+
This class is responsible for creating appropriate validation functions
|
52
|
+
based on type annotations. It handles various types including primitives,
|
53
|
+
containers, unions, and custom types like State classes.
|
54
|
+
"""
|
55
|
+
|
34
56
|
@classmethod
|
35
57
|
def of(
|
36
58
|
cls,
|
@@ -39,6 +61,30 @@ class AttributeValidator[Type]:
|
|
39
61
|
*,
|
40
62
|
recursion_guard: MutableMapping[str, AttributeValidation[Any]],
|
41
63
|
) -> AttributeValidation[Any]:
|
64
|
+
"""
|
65
|
+
Create a validation function for the given type annotation.
|
66
|
+
|
67
|
+
This method analyzes the type annotation and creates an appropriate
|
68
|
+
validation function that can validate and transform values to match
|
69
|
+
the expected type.
|
70
|
+
|
71
|
+
Parameters
|
72
|
+
----------
|
73
|
+
annotation : AttributeAnnotation
|
74
|
+
The type annotation to create a validator for
|
75
|
+
recursion_guard : MutableMapping[str, AttributeValidation[Any]]
|
76
|
+
A mapping used to detect and handle recursive types
|
77
|
+
|
78
|
+
Returns
|
79
|
+
-------
|
80
|
+
AttributeValidation[Any]
|
81
|
+
A validation function for the given type
|
82
|
+
|
83
|
+
Raises
|
84
|
+
------
|
85
|
+
TypeError
|
86
|
+
If the annotation represents an unsupported type
|
87
|
+
"""
|
42
88
|
if isinstance(annotation.origin, NotImplementedError | RuntimeError):
|
43
89
|
raise annotation.origin # raise an error if origin was not properly resolved
|
44
90
|
|
@@ -101,6 +147,16 @@ class AttributeValidator[Type]:
|
|
101
147
|
annotation: AttributeAnnotation,
|
102
148
|
validation: AttributeValidation[Type] | Missing,
|
103
149
|
) -> None:
|
150
|
+
"""
|
151
|
+
Initialize a new attribute validator.
|
152
|
+
|
153
|
+
Parameters
|
154
|
+
----------
|
155
|
+
annotation : AttributeAnnotation
|
156
|
+
The type annotation this validator is for
|
157
|
+
validation : AttributeValidation[Type] | Missing
|
158
|
+
The validation function, or MISSING if not yet set
|
159
|
+
"""
|
104
160
|
self.annotation: AttributeAnnotation
|
105
161
|
object.__setattr__(
|
106
162
|
self,
|
@@ -138,6 +194,26 @@ class AttributeValidator[Type]:
|
|
138
194
|
value: Any,
|
139
195
|
/,
|
140
196
|
) -> Any:
|
197
|
+
"""
|
198
|
+
Validate a value against this validator's type annotation.
|
199
|
+
|
200
|
+
Parameters
|
201
|
+
----------
|
202
|
+
value : Any
|
203
|
+
The value to validate
|
204
|
+
|
205
|
+
Returns
|
206
|
+
-------
|
207
|
+
Any
|
208
|
+
The validated and potentially transformed value
|
209
|
+
|
210
|
+
Raises
|
211
|
+
------
|
212
|
+
AssertionError
|
213
|
+
If the validation function is not set
|
214
|
+
Exception
|
215
|
+
If validation fails
|
216
|
+
"""
|
141
217
|
assert self.validation is not MISSING # nosec: B101
|
142
218
|
return self.validation(value) # pyright: ignore[reportCallIssue, reportUnknownVariableType]
|
143
219
|
|
@@ -153,6 +229,24 @@ def _prepare_validator_of_any(
|
|
153
229
|
/,
|
154
230
|
recursion_guard: MutableMapping[str, AttributeValidation[Any]],
|
155
231
|
) -> AttributeValidation[Any]:
|
232
|
+
"""
|
233
|
+
Create a validator for the Any type.
|
234
|
+
|
235
|
+
Since Any accepts any value, this validator simply returns the input value unchanged.
|
236
|
+
|
237
|
+
Parameters
|
238
|
+
----------
|
239
|
+
annotation : AttributeAnnotation
|
240
|
+
The Any type annotation
|
241
|
+
recursion_guard : MutableMapping[str, AttributeValidation[Any]]
|
242
|
+
Mapping to prevent infinite recursion (unused for Any)
|
243
|
+
|
244
|
+
Returns
|
245
|
+
-------
|
246
|
+
AttributeValidation[Any]
|
247
|
+
A validator that accepts any value
|
248
|
+
"""
|
249
|
+
|
156
250
|
def validator(
|
157
251
|
value: Any,
|
158
252
|
/,
|
@@ -167,6 +261,24 @@ def _prepare_validator_of_none(
|
|
167
261
|
/,
|
168
262
|
recursion_guard: MutableMapping[str, AttributeValidation[Any]],
|
169
263
|
) -> AttributeValidation[Any]:
|
264
|
+
"""
|
265
|
+
Create a validator for the None type.
|
266
|
+
|
267
|
+
This validator only accepts None values.
|
268
|
+
|
269
|
+
Parameters
|
270
|
+
----------
|
271
|
+
annotation : AttributeAnnotation
|
272
|
+
The None type annotation
|
273
|
+
recursion_guard : MutableMapping[str, AttributeValidation[Any]]
|
274
|
+
Mapping to prevent infinite recursion (unused for None)
|
275
|
+
|
276
|
+
Returns
|
277
|
+
-------
|
278
|
+
AttributeValidation[Any]
|
279
|
+
A validator that accepts only None
|
280
|
+
"""
|
281
|
+
|
170
282
|
def validator(
|
171
283
|
value: Any,
|
172
284
|
/,
|
@@ -185,6 +297,24 @@ def _prepare_validator_of_missing(
|
|
185
297
|
/,
|
186
298
|
recursion_guard: MutableMapping[str, AttributeValidation[Any]],
|
187
299
|
) -> AttributeValidation[Any]:
|
300
|
+
"""
|
301
|
+
Create a validator for the Missing type.
|
302
|
+
|
303
|
+
This validator only accepts the MISSING sentinel value.
|
304
|
+
|
305
|
+
Parameters
|
306
|
+
----------
|
307
|
+
annotation : AttributeAnnotation
|
308
|
+
The Missing type annotation
|
309
|
+
recursion_guard : MutableMapping[str, AttributeValidation[Any]]
|
310
|
+
Mapping to prevent infinite recursion (unused for Missing)
|
311
|
+
|
312
|
+
Returns
|
313
|
+
-------
|
314
|
+
AttributeValidation[Any]
|
315
|
+
A validator that accepts only the MISSING sentinel
|
316
|
+
"""
|
317
|
+
|
188
318
|
def validator(
|
189
319
|
value: Any,
|
190
320
|
/,
|
@@ -203,6 +333,24 @@ def _prepare_validator_of_literal(
|
|
203
333
|
/,
|
204
334
|
recursion_guard: MutableMapping[str, AttributeValidation[Any]],
|
205
335
|
) -> AttributeValidation[Any]:
|
336
|
+
"""
|
337
|
+
Create a validator for Literal types.
|
338
|
+
|
339
|
+
This validator checks if the value is one of the literal values
|
340
|
+
specified in the type annotation.
|
341
|
+
|
342
|
+
Parameters
|
343
|
+
----------
|
344
|
+
annotation : AttributeAnnotation
|
345
|
+
The Literal type annotation containing allowed values
|
346
|
+
recursion_guard : MutableMapping[str, AttributeValidation[Any]]
|
347
|
+
Mapping to prevent infinite recursion (unused for Literal)
|
348
|
+
|
349
|
+
Returns
|
350
|
+
-------
|
351
|
+
AttributeValidation[Any]
|
352
|
+
A validator that accepts only the specified literal values
|
353
|
+
"""
|
206
354
|
elements: Sequence[Any] = annotation.arguments
|
207
355
|
formatted_type: str = str(annotation)
|
208
356
|
|
@@ -224,6 +372,24 @@ def _prepare_validator_of_type(
|
|
224
372
|
/,
|
225
373
|
recursion_guard: MutableMapping[str, AttributeValidation[Any]],
|
226
374
|
) -> AttributeValidation[Any]:
|
375
|
+
"""
|
376
|
+
Create a validator for simple types.
|
377
|
+
|
378
|
+
This validator checks if the value is an instance of the specified type.
|
379
|
+
Used for primitive types, enums, and custom classes.
|
380
|
+
|
381
|
+
Parameters
|
382
|
+
----------
|
383
|
+
annotation : AttributeAnnotation
|
384
|
+
The type annotation
|
385
|
+
recursion_guard : MutableMapping[str, AttributeValidation[Any]]
|
386
|
+
Mapping to prevent infinite recursion (unused for simple types)
|
387
|
+
|
388
|
+
Returns
|
389
|
+
-------
|
390
|
+
AttributeValidation[Any]
|
391
|
+
A validator that checks instance type
|
392
|
+
"""
|
227
393
|
validated_type: type[Any] = annotation.origin
|
228
394
|
formatted_type: str = str(annotation)
|
229
395
|
|
@@ -246,6 +412,24 @@ def _prepare_validator_of_set(
|
|
246
412
|
/,
|
247
413
|
recursion_guard: MutableMapping[str, AttributeValidation[Any]],
|
248
414
|
) -> AttributeValidation[Any]:
|
415
|
+
"""
|
416
|
+
Create a validator for set and frozenset types.
|
417
|
+
|
418
|
+
This validator checks if the value is a set and validates each element
|
419
|
+
according to the set's element type.
|
420
|
+
|
421
|
+
Parameters
|
422
|
+
----------
|
423
|
+
annotation : AttributeAnnotation
|
424
|
+
The set type annotation
|
425
|
+
recursion_guard : MutableMapping[str, AttributeValidation[Any]]
|
426
|
+
Mapping to prevent infinite recursion for recursive types
|
427
|
+
|
428
|
+
Returns
|
429
|
+
-------
|
430
|
+
AttributeValidation[Any]
|
431
|
+
A validator that validates sets and their elements
|
432
|
+
"""
|
249
433
|
element_validator: AttributeValidation[Any] = AttributeValidator.of(
|
250
434
|
annotation.arguments[0],
|
251
435
|
recursion_guard=recursion_guard,
|
@@ -270,6 +454,24 @@ def _prepare_validator_of_sequence(
|
|
270
454
|
/,
|
271
455
|
recursion_guard: MutableMapping[str, AttributeValidation[Any]],
|
272
456
|
) -> AttributeValidation[Any]:
|
457
|
+
"""
|
458
|
+
Create a validator for sequence types.
|
459
|
+
|
460
|
+
This validator checks if the value is a sequence and validates each element
|
461
|
+
according to the sequence's element type. Sequences are converted to tuples.
|
462
|
+
|
463
|
+
Parameters
|
464
|
+
----------
|
465
|
+
annotation : AttributeAnnotation
|
466
|
+
The sequence type annotation
|
467
|
+
recursion_guard : MutableMapping[str, AttributeValidation[Any]]
|
468
|
+
Mapping to prevent infinite recursion for recursive types
|
469
|
+
|
470
|
+
Returns
|
471
|
+
-------
|
472
|
+
AttributeValidation[Any]
|
473
|
+
A validator that validates sequences and their elements
|
474
|
+
"""
|
273
475
|
element_validator: AttributeValidation[Any] = AttributeValidator.of(
|
274
476
|
annotation.arguments[0],
|
275
477
|
recursion_guard=recursion_guard,
|
@@ -295,6 +497,24 @@ def _prepare_validator_of_mapping(
|
|
295
497
|
/,
|
296
498
|
recursion_guard: MutableMapping[str, AttributeValidation[Any]],
|
297
499
|
) -> AttributeValidation[Any]:
|
500
|
+
"""
|
501
|
+
Create a validator for mapping types.
|
502
|
+
|
503
|
+
This validator checks if the value is a mapping and validates each key and value
|
504
|
+
according to their respective types.
|
505
|
+
|
506
|
+
Parameters
|
507
|
+
----------
|
508
|
+
annotation : AttributeAnnotation
|
509
|
+
The mapping type annotation
|
510
|
+
recursion_guard : MutableMapping[str, AttributeValidation[Any]]
|
511
|
+
Mapping to prevent infinite recursion for recursive types
|
512
|
+
|
513
|
+
Returns
|
514
|
+
-------
|
515
|
+
AttributeValidation[Any]
|
516
|
+
A validator that validates mappings with their keys and values
|
517
|
+
"""
|
298
518
|
key_validator: AttributeValidation[Any] = AttributeValidator.of(
|
299
519
|
annotation.arguments[0],
|
300
520
|
recursion_guard=recursion_guard,
|
@@ -328,6 +548,24 @@ def _prepare_validator_of_tuple(
|
|
328
548
|
/,
|
329
549
|
recursion_guard: MutableMapping[str, AttributeValidation[Any]],
|
330
550
|
) -> AttributeValidation[Any]:
|
551
|
+
"""
|
552
|
+
Create a validator for tuple types.
|
553
|
+
|
554
|
+
This validator handles both fixed-length tuples (with specific types for each position)
|
555
|
+
and variable-length tuples (with a repeating element type and Ellipsis).
|
556
|
+
|
557
|
+
Parameters
|
558
|
+
----------
|
559
|
+
annotation : AttributeAnnotation
|
560
|
+
The tuple type annotation
|
561
|
+
recursion_guard : MutableMapping[str, AttributeValidation[Any]]
|
562
|
+
Mapping to prevent infinite recursion for recursive types
|
563
|
+
|
564
|
+
Returns
|
565
|
+
-------
|
566
|
+
AttributeValidation[Any]
|
567
|
+
A validator that validates tuples based on their type specification
|
568
|
+
"""
|
331
569
|
if (
|
332
570
|
annotation.arguments[-1].origin == Ellipsis
|
333
571
|
or annotation.arguments[-1].origin == EllipsisType
|
@@ -389,6 +627,24 @@ def _prepare_validator_of_union(
|
|
389
627
|
/,
|
390
628
|
recursion_guard: MutableMapping[str, AttributeValidation[Any]],
|
391
629
|
) -> AttributeValidation[Any]:
|
630
|
+
"""
|
631
|
+
Create a validator for union types.
|
632
|
+
|
633
|
+
This validator tries to validate the value against each type in the union,
|
634
|
+
and succeeds if any validation succeeds.
|
635
|
+
|
636
|
+
Parameters
|
637
|
+
----------
|
638
|
+
annotation : AttributeAnnotation
|
639
|
+
The union type annotation
|
640
|
+
recursion_guard : MutableMapping[str, AttributeValidation[Any]]
|
641
|
+
Mapping to prevent infinite recursion for recursive types
|
642
|
+
|
643
|
+
Returns
|
644
|
+
-------
|
645
|
+
AttributeValidation[Any]
|
646
|
+
A validator that validates against any type in the union
|
647
|
+
"""
|
392
648
|
validators: list[AttributeValidation[Any]] = [
|
393
649
|
AttributeValidator.of(alternative, recursion_guard=recursion_guard)
|
394
650
|
for alternative in annotation.arguments
|
@@ -420,6 +676,24 @@ def _prepare_validator_of_callable(
|
|
420
676
|
/,
|
421
677
|
recursion_guard: MutableMapping[str, AttributeValidation[Any]],
|
422
678
|
) -> AttributeValidation[Any]:
|
679
|
+
"""
|
680
|
+
Create a validator for callable types.
|
681
|
+
|
682
|
+
This validator checks if the value is callable, but does not
|
683
|
+
validate the callable's signature.
|
684
|
+
|
685
|
+
Parameters
|
686
|
+
----------
|
687
|
+
annotation : AttributeAnnotation
|
688
|
+
The callable type annotation
|
689
|
+
recursion_guard : MutableMapping[str, AttributeValidation[Any]]
|
690
|
+
Mapping to prevent infinite recursion (unused for callable)
|
691
|
+
|
692
|
+
Returns
|
693
|
+
-------
|
694
|
+
AttributeValidation[Any]
|
695
|
+
A validator that checks if values are callable
|
696
|
+
"""
|
423
697
|
formatted_type: str = str(annotation)
|
424
698
|
|
425
699
|
def validator(
|
@@ -441,6 +715,25 @@ def _prepare_validator_of_typed_dict(
|
|
441
715
|
/,
|
442
716
|
recursion_guard: MutableMapping[str, AttributeValidation[Any]],
|
443
717
|
) -> AttributeValidation[Any]:
|
718
|
+
"""
|
719
|
+
Create a validator for TypedDict types.
|
720
|
+
|
721
|
+
This validator checks if the value is a mapping with keys and values
|
722
|
+
matching the TypedDict specification. Required keys must be present.
|
723
|
+
|
724
|
+
Parameters
|
725
|
+
----------
|
726
|
+
annotation : AttributeAnnotation
|
727
|
+
The TypedDict type annotation
|
728
|
+
recursion_guard : MutableMapping[str, AttributeValidation[Any]]
|
729
|
+
Mapping to prevent infinite recursion for recursive types
|
730
|
+
|
731
|
+
Returns
|
732
|
+
-------
|
733
|
+
AttributeValidation[Any]
|
734
|
+
A validator that validates TypedDict structures
|
735
|
+
"""
|
736
|
+
|
444
737
|
def key_validator(
|
445
738
|
value: Any,
|
446
739
|
/,
|
haiway/types/default.py
CHANGED
@@ -12,6 +12,16 @@ __all__ = (
|
|
12
12
|
|
13
13
|
@final
|
14
14
|
class DefaultValue[Value]:
|
15
|
+
"""
|
16
|
+
Container for a default value or a factory function that produces a default value.
|
17
|
+
|
18
|
+
This class stores either a direct default value or a factory function that can
|
19
|
+
produce a default value when needed. It ensures the value or factory cannot be
|
20
|
+
modified after initialization.
|
21
|
+
|
22
|
+
The value can be retrieved by calling the instance like a function.
|
23
|
+
"""
|
24
|
+
|
15
25
|
__slots__ = ("_value",)
|
16
26
|
|
17
27
|
@overload
|
@@ -45,6 +55,21 @@ class DefaultValue[Value]:
|
|
45
55
|
*,
|
46
56
|
factory: Callable[[], Value] | Missing = MISSING,
|
47
57
|
) -> None:
|
58
|
+
"""
|
59
|
+
Initialize with either a default value or a factory function.
|
60
|
+
|
61
|
+
Parameters
|
62
|
+
----------
|
63
|
+
value : Value | Missing
|
64
|
+
The default value to store, or MISSING if using a factory
|
65
|
+
factory : Callable[[], Value] | Missing
|
66
|
+
A function that returns the default value when called, or MISSING if using a direct value
|
67
|
+
|
68
|
+
Raises
|
69
|
+
------
|
70
|
+
AssertionError
|
71
|
+
If both value and factory are provided
|
72
|
+
""" # noqa: E501
|
48
73
|
assert ( # nosec: B101
|
49
74
|
value is MISSING or factory is MISSING
|
50
75
|
), "Can't specify both default value and factory"
|
@@ -65,6 +90,14 @@ class DefaultValue[Value]:
|
|
65
90
|
)
|
66
91
|
|
67
92
|
def __call__(self) -> Value | Missing:
|
93
|
+
"""
|
94
|
+
Get the default value.
|
95
|
+
|
96
|
+
Returns
|
97
|
+
-------
|
98
|
+
Value | Missing
|
99
|
+
The stored default value, or the result of calling the factory function
|
100
|
+
"""
|
68
101
|
return self._value()
|
69
102
|
|
70
103
|
def __setattr__(
|
@@ -101,6 +134,29 @@ def Default[Value](
|
|
101
134
|
*,
|
102
135
|
factory: Callable[[], Value] | Missing = MISSING,
|
103
136
|
) -> Value: # it is actually a DefaultValue, but type checker has to be fooled most some cases
|
137
|
+
"""
|
138
|
+
Create a default value container that appears as the actual value type.
|
139
|
+
|
140
|
+
This function creates a DefaultValue instance but returns it typed as the actual
|
141
|
+
value type it contains. This allows type checkers to treat it as if it were the
|
142
|
+
actual value while still maintaining the lazy evaluation behavior.
|
143
|
+
|
144
|
+
Parameters
|
145
|
+
----------
|
146
|
+
value : Value | Missing
|
147
|
+
The default value to store, or MISSING if using a factory
|
148
|
+
factory : Callable[[], Value] | Missing
|
149
|
+
A function that returns the default value when called, or MISSING if using a direct value
|
150
|
+
|
151
|
+
Returns
|
152
|
+
-------
|
153
|
+
Value
|
154
|
+
A DefaultValue instance that appears to be of type Value for type checking purposes
|
155
|
+
|
156
|
+
Notes
|
157
|
+
-----
|
158
|
+
Only one of value or factory should be provided. If both are provided, an exception will be raised.
|
159
|
+
""" # noqa: E501
|
104
160
|
return cast(
|
105
161
|
Value,
|
106
162
|
DefaultValue(
|
haiway/types/frozen.py
CHANGED
@@ -1,3 +1,21 @@
|
|
1
1
|
__all__ = ("frozenlist",)
|
2
2
|
|
3
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
|
+
"""
|
haiway/types/missing.py
CHANGED
@@ -10,6 +10,13 @@ __all__ = (
|
|
10
10
|
|
11
11
|
|
12
12
|
class MissingType(type):
|
13
|
+
"""
|
14
|
+
Metaclass for the Missing type implementing the singleton pattern.
|
15
|
+
|
16
|
+
Ensures that only one instance of the Missing class ever exists,
|
17
|
+
allowing for identity comparison using the 'is' operator.
|
18
|
+
"""
|
19
|
+
|
13
20
|
_instance: Any = None
|
14
21
|
|
15
22
|
def __call__(cls) -> Any:
|
@@ -25,6 +32,13 @@ class MissingType(type):
|
|
25
32
|
class Missing(metaclass=MissingType):
|
26
33
|
"""
|
27
34
|
Type representing absence of a value. Use MISSING constant for its value.
|
35
|
+
|
36
|
+
This is a singleton class that represents the absence of a value, similar to
|
37
|
+
None but semantically different. Where None represents "no value", MISSING
|
38
|
+
represents "no value provided" or "value intentionally omitted".
|
39
|
+
|
40
|
+
The MISSING constant is the only instance of this class and should be used
|
41
|
+
for all comparisons using the 'is' operator, not equality testing.
|
28
42
|
"""
|
29
43
|
|
30
44
|
__slots__ = ()
|
@@ -72,6 +86,30 @@ def is_missing(
|
|
72
86
|
check: Any | Missing,
|
73
87
|
/,
|
74
88
|
) -> TypeGuard[Missing]:
|
89
|
+
"""
|
90
|
+
Check if a value is the MISSING sentinel.
|
91
|
+
|
92
|
+
This function implements a TypeGuard that helps static type checkers
|
93
|
+
understand when a value is confirmed to be the MISSING sentinel.
|
94
|
+
|
95
|
+
Parameters
|
96
|
+
----------
|
97
|
+
check : Any | Missing
|
98
|
+
The value to check
|
99
|
+
|
100
|
+
Returns
|
101
|
+
-------
|
102
|
+
TypeGuard[Missing]
|
103
|
+
True if the value is MISSING, False otherwise
|
104
|
+
|
105
|
+
Examples
|
106
|
+
--------
|
107
|
+
```python
|
108
|
+
if is_missing(value):
|
109
|
+
# Here, type checkers know that value is Missing
|
110
|
+
provide_default()
|
111
|
+
```
|
112
|
+
"""
|
75
113
|
return check is MISSING
|
76
114
|
|
77
115
|
|
@@ -79,6 +117,30 @@ def not_missing[Value](
|
|
79
117
|
check: Value | Missing,
|
80
118
|
/,
|
81
119
|
) -> TypeGuard[Value]:
|
120
|
+
"""
|
121
|
+
Check if a value is not the MISSING sentinel.
|
122
|
+
|
123
|
+
This function implements a TypeGuard that helps static type checkers
|
124
|
+
understand when a value is confirmed not to be the MISSING sentinel.
|
125
|
+
|
126
|
+
Parameters
|
127
|
+
----------
|
128
|
+
check : Value | Missing
|
129
|
+
The value to check
|
130
|
+
|
131
|
+
Returns
|
132
|
+
-------
|
133
|
+
TypeGuard[Value]
|
134
|
+
True if the value is not MISSING, False otherwise
|
135
|
+
|
136
|
+
Examples
|
137
|
+
--------
|
138
|
+
```python
|
139
|
+
if not_missing(value):
|
140
|
+
# Here, type checkers know that value is of type Value
|
141
|
+
process_value(value)
|
142
|
+
```
|
143
|
+
"""
|
82
144
|
return check is not MISSING
|
83
145
|
|
84
146
|
|
@@ -88,6 +150,33 @@ def when_missing[Value](
|
|
88
150
|
*,
|
89
151
|
value: Value,
|
90
152
|
) -> Value:
|
153
|
+
"""
|
154
|
+
Substitute a default value when the input is MISSING.
|
155
|
+
|
156
|
+
This function provides a convenient way to replace the MISSING
|
157
|
+
sentinel with a default value, similar to how the or operator
|
158
|
+
works with None but specifically for the MISSING sentinel.
|
159
|
+
|
160
|
+
Parameters
|
161
|
+
----------
|
162
|
+
check : Value | Missing
|
163
|
+
The value to check
|
164
|
+
value : Value
|
165
|
+
The default value to use if check is MISSING
|
166
|
+
|
167
|
+
Returns
|
168
|
+
-------
|
169
|
+
Value
|
170
|
+
The original value if not MISSING, otherwise the provided default
|
171
|
+
|
172
|
+
Examples
|
173
|
+
--------
|
174
|
+
```python
|
175
|
+
result = when_missing(optional_value, value=default_value)
|
176
|
+
# result will be default_value if optional_value is MISSING
|
177
|
+
# otherwise it will be optional_value
|
178
|
+
```
|
179
|
+
"""
|
91
180
|
if check is MISSING:
|
92
181
|
return value
|
93
182
|
|