haiway 0.19.4__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.
@@ -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