16
16
from __future__ import annotations
17
17
18
18
from types import GenericAlias , UnionType
19
- from typing import (
20
- Any ,
21
- _LiteralGenericAlias , # type: ignore[attr-defined]
22
- _UnionGenericAlias , # type: ignore[attr-defined]
23
- )
19
+ from typing import Any , Literal , TypeGuard , Union
24
20
25
21
from statica .config import StaticaConfig , default_config
26
22
from statica .exceptions import ConstraintValidationError , TypeValidationError
27
23
24
+ ########################################################################################
25
+ #### MARK: Types
26
+
27
+
28
+ class LiteralGenericAlias :
29
+ """A type used in place of typing._LiteralGenericAlias to avoid private imports."""
30
+
31
+ __origin__ = Literal
32
+ __args__ : tuple [Any , ...]
33
+
34
+
35
+ def is_literal_generic_alias (expected_type : Any ) -> TypeGuard [LiteralGenericAlias ]:
36
+ return hasattr (expected_type , "__origin__" ) and expected_type .__origin__ is Literal
37
+
38
+
39
+ class UnionGenericAlias :
40
+ """A type used in place of typing._UnionGenericAlias to avoid private imports."""
41
+
42
+ __origin__ = Union
43
+ __args__ : tuple [Any , ...]
44
+
45
+
46
+ def is_union_generic_alias (expected_type : Any ) -> TypeGuard [UnionGenericAlias ]:
47
+ return hasattr (expected_type , "__origin__" ) and expected_type .__origin__ is Union
48
+
49
+
28
50
########################################################################################
29
51
#### MARK: Type Validation
30
52
@@ -39,28 +61,28 @@ def validate_or_raise(
39
61
are already initialized Statica objects.
40
62
"""
41
63
42
- # Handle union types
64
+ # Handle generic aliases if native python types, e.g. list[int], dict[str, int]
43
65
44
- if isinstance (expected_type , UnionType ):
45
- validate_type_union (value , expected_type , config )
66
+ if isinstance (expected_type , GenericAlias ):
67
+ validate_type_generic_alias (value , expected_type , config )
46
68
return
47
69
48
- # Handle union generic aliases
70
+ # Handle parameterized generic types
49
71
50
- if isinstance (expected_type , _UnionGenericAlias ):
72
+ if is_union_generic_alias (expected_type ):
51
73
validate_type_union_generic_alias (value , expected_type , config )
52
74
return
53
75
54
- # Handle generic aliases
76
+ # Handle Literal (e.g. Literal["a", "b"], with any number and type of values)
55
77
56
- if isinstance (expected_type , GenericAlias ):
57
- validate_type_generic_alias (value , expected_type , config )
78
+ if is_literal_generic_alias (expected_type ):
79
+ validate_literal (value , expected_type )
58
80
return
59
81
60
- # Handle Literal (e.g. Literal["a", "b"], with any number and type of values)
82
+ # Handle union types
61
83
62
- if isinstance (expected_type , _LiteralGenericAlias ):
63
- validate_literal (value , expected_type )
84
+ if isinstance (expected_type , UnionType ):
85
+ validate_type_union (value , expected_type , config )
64
86
return
65
87
66
88
# Handle all other types
@@ -77,7 +99,7 @@ def validate_or_raise(
77
99
78
100
def validate_literal (
79
101
value : Any ,
80
- expected_type : _LiteralGenericAlias ,
102
+ expected_type : LiteralGenericAlias ,
81
103
) -> None :
82
104
"""
83
105
Validate that the value matches one of the literals in the expected_type.
@@ -114,7 +136,7 @@ def validate_type_union(
114
136
115
137
def validate_type_union_generic_alias (
116
138
value : Any ,
117
- expected_type : _UnionGenericAlias ,
139
+ expected_type : UnionGenericAlias ,
118
140
config : StaticaConfig = default_config ,
119
141
) -> None :
120
142
"""
0 commit comments