0
# Type System Compatibility
1
2
Comprehensive type introspection and compatibility utilities for working with Python's type system, generics, complex nested types, and modern typing features. This module provides the foundation for pyserde's extensive type support.
3
4
## Capabilities
5
6
### Type Predicates
7
8
Functions to test for specific type categories and patterns.
9
10
```python { .api }
11
def is_union(typ) -> bool:
12
"""Test if type is a union type (Union[A, B] or A | B)."""
13
14
def is_opt(typ) -> bool:
15
"""Test if type is Optional (Union[T, None])."""
16
17
def is_list(typ) -> bool:
18
"""Test if type is a list type."""
19
20
def is_set(typ) -> bool:
21
"""Test if type is a set type."""
22
23
def is_tuple(typ) -> bool:
24
"""Test if type is a tuple type."""
25
26
def is_dict(typ) -> bool:
27
"""Test if type is a dict type."""
28
29
def is_bare_list(typ) -> bool:
30
"""Test if type is unparameterized list."""
31
32
def is_bare_set(typ) -> bool:
33
"""Test if type is unparameterized set."""
34
35
def is_bare_tuple(typ) -> bool:
36
"""Test if type is unparameterized tuple."""
37
38
def is_bare_dict(typ) -> bool:
39
"""Test if type is unparameterized dict."""
40
41
def is_variable_tuple(typ) -> bool:
42
"""Test if type is variable-length tuple (Tuple[T, ...])."""
43
44
def is_frozen_set(typ) -> bool:
45
"""Test if type is frozenset."""
46
47
def is_default_dict(typ) -> bool:
48
"""Test if type is defaultdict."""
49
50
def is_none(typ) -> bool:
51
"""Test if type is None/NoneType."""
52
53
def is_any(typ) -> bool:
54
"""Test if type is typing.Any."""
55
56
def is_generic(typ) -> bool:
57
"""Test if type is a generic type."""
58
59
def is_literal(typ) -> bool:
60
"""Test if type is typing.Literal."""
61
62
def is_class_var(typ) -> bool:
63
"""Test if type is typing.ClassVar."""
64
65
def is_primitive(typ) -> bool:
66
"""Test if type is a primitive type (int, float, str, bool)."""
67
68
def is_enum(typ) -> bool:
69
"""Test if type is an Enum."""
70
71
def is_datetime(typ) -> bool:
72
"""Test if type is a datetime-related type."""
73
74
def is_str_serializable(typ) -> bool:
75
"""Test if type can be serialized as string (UUID, Path, etc.)."""
76
```
77
78
### Type Introspection
79
80
Functions for extracting type information and metadata.
81
82
```python { .api }
83
def get_origin(typ):
84
"""
85
Get origin type from generic type.
86
87
Parameters:
88
- typ: Type to analyze
89
90
Returns:
91
Origin type (e.g., list from List[int])
92
"""
93
94
def get_args(typ):
95
"""
96
Get type arguments from generic type.
97
98
Parameters:
99
- typ: Type to analyze
100
101
Returns:
102
Tuple of type arguments (e.g., (int,) from List[int])
103
"""
104
105
def typename(typ) -> str:
106
"""
107
Get string representation of type.
108
109
Parameters:
110
- typ: Type to represent
111
112
Returns:
113
String name of the type
114
"""
115
116
def type_args(typ):
117
"""
118
Get type arguments with fallback handling.
119
120
Parameters:
121
- typ: Type to analyze
122
123
Returns:
124
Type arguments or empty tuple if none
125
"""
126
127
def dataclass_fields(cls):
128
"""
129
Get resolved dataclass fields with type information.
130
131
Parameters:
132
- cls: Dataclass to analyze
133
134
Returns:
135
Dictionary of field names to field objects
136
"""
137
```
138
139
### Type Iteration
140
141
Functions for traversing and analyzing complex type structures.
142
143
```python { .api }
144
def iter_types(cls):
145
"""
146
Recursively iterate over all field types in a dataclass.
147
148
Parameters:
149
- cls: Dataclass to analyze
150
151
Yields:
152
Type objects found in the class hierarchy
153
"""
154
155
def iter_unions(cls):
156
"""
157
Find all union types in a dataclass.
158
159
Parameters:
160
- cls: Dataclass to analyze
161
162
Yields:
163
Union type objects found in the class
164
"""
165
166
def iter_literals(cls):
167
"""
168
Find all literal types in a dataclass.
169
170
Parameters:
171
- cls: Dataclass to analyze
172
173
Yields:
174
Literal type objects found in the class
175
"""
176
```
177
178
### Generic Type Support
179
180
Functions for working with generic types and type variables.
181
182
```python { .api }
183
def get_type_var_names(cls) -> List[str]:
184
"""
185
Get type variable names from generic class.
186
187
Parameters:
188
- cls: Generic class to analyze
189
190
Returns:
191
List of type variable names
192
"""
193
194
def find_generic_arg(typ, type_var) -> int:
195
"""
196
Find position of type variable in generic type.
197
198
Parameters:
199
- typ: Generic type to search
200
- type_var: Type variable to find
201
202
Returns:
203
Index of type variable or -1 if not found
204
"""
205
206
def get_generic_arg(typ, type_var):
207
"""
208
Resolve generic type argument for a type variable.
209
210
Parameters:
211
- typ: Generic type instance
212
- type_var: Type variable to resolve
213
214
Returns:
215
Resolved type argument
216
"""
217
```
218
219
### Exception Handling
220
221
Exception classes for type system errors.
222
223
```python { .api }
224
class SerdeError(Exception):
225
"""Base exception for serde errors."""
226
227
class SerdeSkip(Exception):
228
"""Exception to skip field serialization in custom serializers."""
229
230
class UserError(Exception):
231
"""Wrapper for errors in user-defined custom serializers/deserializers."""
232
```
233
234
## Usage Examples
235
236
### Type Checking
237
238
```python
239
from serde.compat import is_union, is_opt, is_list, get_origin, get_args
240
from typing import Union, Optional, List
241
242
# Test union types
243
print(is_union(Union[int, str])) # True
244
print(is_union(int)) # False
245
246
# Test optional types
247
print(is_opt(Optional[str])) # True
248
print(is_opt(Union[str, None])) # True
249
print(is_opt(str)) # False
250
251
# Test container types
252
print(is_list(List[int])) # True
253
print(is_list(list)) # True
254
print(is_list(int)) # False
255
256
# Extract type information
257
list_type = List[str]
258
print(get_origin(list_type)) # <class 'list'>
259
print(get_args(list_type)) # (<class 'str'>,)
260
```
261
262
### Working with Generic Types
263
264
```python
265
from serde import serde
266
from serde.compat import get_type_var_names, get_generic_arg
267
from typing import TypeVar, Generic, List
268
269
T = TypeVar('T')
270
271
@serde
272
class Container(Generic[T]):
273
items: List[T]
274
275
# Analyze generic type
276
print(get_type_var_names(Container)) # ['T']
277
278
# Work with concrete generic instances
279
IntContainer = Container[int]
280
print(get_generic_arg(IntContainer, T)) # <class 'int'>
281
```
282
283
### Type Iteration
284
285
```python
286
from serde import serde
287
from serde.compat import iter_types, iter_unions
288
from typing import Union, List, Dict
289
290
@serde
291
class ComplexData:
292
id: int
293
name: str
294
tags: List[str]
295
metadata: Dict[str, Union[str, int]]
296
optional_field: Union[str, None]
297
298
# Iterate over all types
299
for typ in iter_types(ComplexData):
300
print(f"Found type: {typ}")
301
302
# Find union types specifically
303
for union_typ in iter_unions(ComplexData):
304
print(f"Found union: {union_typ}")
305
```
306
307
### Custom Type Handling
308
309
```python
310
from serde import serde, field
311
from serde.compat import is_datetime, typename
312
from datetime import datetime, date
313
from typing import Any
314
315
def custom_datetime_handler(obj: Any) -> str:
316
"""Custom serializer that handles any datetime-like object."""
317
if is_datetime(type(obj)):
318
return obj.isoformat()
319
return str(obj)
320
321
@serde
322
class Event:
323
name: str
324
created_at: datetime = field(serializer=custom_datetime_handler)
325
event_date: date = field(serializer=custom_datetime_handler)
326
327
event = Event("Meeting", datetime.now(), date.today())
328
# Both datetime fields will be serialized using the custom handler
329
```
330
331
### Advanced Type Analysis
332
333
```python
334
from serde.compat import *
335
from typing import Dict, List, Union, Optional, Literal, Any
336
from dataclasses import dataclass
337
338
# Analyze complex nested types
339
complex_type = Dict[str, List[Union[int, str, Optional[bool]]]]
340
341
print(f"Is dict: {is_dict(complex_type)}")
342
print(f"Origin: {get_origin(complex_type)}")
343
print(f"Args: {get_args(complex_type)}")
344
345
# Check for specific type patterns
346
value_type = get_args(complex_type)[1] # List[Union[int, str, Optional[bool]]]
347
print(f"Is list: {is_list(value_type)}")
348
349
inner_union = get_args(value_type)[0] # Union[int, str, Optional[bool]]
350
print(f"Is union: {is_union(inner_union)}")
351
352
# Test literal types
353
status_type = Literal["active", "inactive", "pending"]
354
print(f"Is literal: {is_literal(status_type)}")
355
356
# Test Any type
357
print(f"Is any: {is_any(Any)}")
358
```