0
# Serialization
1
2
Robust serialization and deserialization system supporting complex data types, XML/JSON formats, date/time handling, custom model classes, and comprehensive validation. The serialization system converts between Python objects and REST API wire formats while maintaining type safety and validation.
3
4
## Capabilities
5
6
### Serialization
7
8
Convert Python objects to REST API formats (JSON/XML) with comprehensive type support.
9
10
```python { .api }
11
class Serializer:
12
def __init__(self, classes=None):
13
"""
14
Initialize serializer with optional model classes.
15
16
Parameters:
17
- classes: Dict of model classes for complex type serialization
18
"""
19
20
basic_types: dict = {str: 'str', int: 'int', bool: 'bool', float: 'float'}
21
client_side_validation: bool = True
22
23
def body(self, data, data_type: str, **kwargs):
24
"""
25
Serialize data for request body.
26
27
Parameters:
28
- data: Python object to serialize
29
- data_type: Target data type string
30
- kwargs: Serialization options (is_xml, etc.)
31
32
Returns:
33
Serialized data (dict for JSON, ET.Element for XML)
34
35
Raises:
36
SerializationError if serialization fails
37
ValidationError if data is None for required field
38
"""
39
40
def url(self, name: str, data, data_type: str, **kwargs) -> str:
41
"""
42
Serialize data for URL path parameters.
43
44
Parameters:
45
- name: Parameter name for error reporting
46
- data: Data to serialize
47
- data_type: Target type ('str', 'int', 'bool', etc.)
48
- kwargs: Options (skip_quote for no URL encoding)
49
50
Returns:
51
URL-encoded string
52
"""
53
54
def query(self, name: str, data, data_type: str, **kwargs) -> str:
55
"""
56
Serialize data for URL query parameters.
57
58
Parameters:
59
- name: Parameter name
60
- data: Data to serialize
61
- data_type: Target type or array type like '[str]'
62
- kwargs: Options (skip_quote for no URL encoding)
63
64
Returns:
65
Query parameter string
66
"""
67
68
def header(self, name: str, data, data_type: str, **kwargs) -> str:
69
"""
70
Serialize data for HTTP headers.
71
72
Parameters:
73
- name: Header name
74
- data: Data to serialize
75
- data_type: Target type
76
- kwargs: Serialization options
77
78
Returns:
79
Header value string
80
"""
81
82
def serialize_data(self, data, data_type: str, **kwargs):
83
"""
84
Core serialization method handling all data types.
85
86
Parameters:
87
- data: Data to serialize
88
- data_type: Target type string
89
- kwargs: Serialization options
90
91
Returns:
92
Serialized data
93
"""
94
95
def serialize_iter(self, data, iter_type: str, **kwargs):
96
"""
97
Serialize iterables (lists, sets, etc.) with XML support.
98
99
Parameters:
100
- data: Iterable to serialize
101
- iter_type: Item type string
102
- kwargs: Options including XML configuration
103
104
Returns:
105
Serialized iterable
106
"""
107
108
def serialize_dict(self, data, dict_type: str, **kwargs):
109
"""
110
Serialize dictionaries with XML support.
111
112
Parameters:
113
- data: Dictionary to serialize
114
- dict_type: Value type string
115
- kwargs: Options including XML configuration
116
117
Returns:
118
Serialized dictionary
119
"""
120
121
def serialize_object(self, data, object_type: str, **kwargs):
122
"""
123
Serialize complex objects/models.
124
125
Parameters:
126
- data: Object to serialize
127
- object_type: Object type string
128
- kwargs: Serialization options
129
130
Returns:
131
Serialized object
132
"""
133
134
def serialize_enum(self, data, enum_obj=None):
135
"""
136
Serialize enum values.
137
138
Parameters:
139
- data: Enum value to serialize
140
- enum_obj: Optional enum class for validation
141
142
Returns:
143
Serialized enum value
144
"""
145
```
146
147
### Deserialization
148
149
Convert REST API responses back to Python objects with type inference and validation.
150
151
```python { .api }
152
class Deserializer:
153
def __init__(self, classes=None):
154
"""
155
Initialize deserializer with model classes.
156
157
Parameters:
158
- classes: Dict of model classes for complex type deserialization
159
"""
160
161
basic_types: dict = {str: 'str', int: 'int', bool: 'bool', float: 'float'}
162
additional_properties_detection: bool = True
163
key_extractors: list
164
165
def __call__(self, target_obj: str, response_data, content_type=None):
166
"""
167
Deserialize response data to target object type.
168
169
Parameters:
170
- target_obj: Target class name or type
171
- response_data: Raw response data
172
- content_type: Response content type
173
174
Returns:
175
Deserialized Python object
176
177
Raises:
178
DeserializationError if deserialization fails
179
"""
180
181
def failsafe_deserialize(self, target_obj: str, data, content_type=None):
182
"""
183
Deserialize with error tolerance for error handling scenarios.
184
185
Parameters:
186
- target_obj: Target object type
187
- data: Response data
188
- content_type: Content type hint
189
190
Returns:
191
Deserialized object or None if deserialization fails
192
"""
193
194
def deserialize_data(self, data, data_type: str):
195
"""
196
Core deserialization method handling all data types.
197
198
Parameters:
199
- data: Data to deserialize
200
- data_type: Target type string
201
202
Returns:
203
Deserialized Python object
204
"""
205
206
def deserialize_iter(self, data, iter_type: str):
207
"""
208
Deserialize iterables from JSON arrays or XML.
209
210
Parameters:
211
- data: Iterable data to deserialize
212
- iter_type: Item type string
213
214
Returns:
215
List of deserialized items
216
"""
217
218
def deserialize_dict(self, data, dict_type: str):
219
"""
220
Deserialize dictionaries from JSON objects or XML.
221
222
Parameters:
223
- data: Dict data to deserialize
224
- dict_type: Value type string
225
226
Returns:
227
Dictionary with deserialized values
228
"""
229
230
def deserialize_object(self, data, object_type: str):
231
"""
232
Deserialize complex objects/models.
233
234
Parameters:
235
- data: Object data to deserialize
236
- object_type: Target object type
237
238
Returns:
239
Deserialized model instance
240
"""
241
242
def deserialize_enum(self, data, enum_obj):
243
"""
244
Deserialize enum values with comprehensive handling.
245
246
Parameters:
247
- data: Enum data to deserialize
248
- enum_obj: Enum class for validation
249
250
Returns:
251
Enum value or string if enum doesn't match
252
"""
253
```
254
255
### Model Base Class
256
257
Base class for request/response model objects with serialization and validation support.
258
259
```python { .api }
260
class Model:
261
_attribute_map: dict = {}
262
_validation: dict = {}
263
_subtype_map: dict = {}
264
265
def __init__(self, **kwargs):
266
"""
267
Initialize model with keyword arguments.
268
269
Parameters:
270
- kwargs: Model field values
271
"""
272
273
def validate(self) -> list:
274
"""
275
Validate model recursively.
276
277
Returns:
278
List of ValidationError objects (empty if valid)
279
"""
280
281
def serialize(self, keep_readonly=False, **kwargs) -> dict:
282
"""
283
Serialize model to JSON-compatible dict.
284
285
Parameters:
286
- keep_readonly: Include readonly fields
287
- kwargs: Serialization options (is_xml, etc.)
288
289
Returns:
290
JSON-compatible dictionary
291
"""
292
293
def as_dict(self, keep_readonly=True, key_transformer=None, **kwargs) -> dict:
294
"""
295
Convert model to dictionary with custom key transformation.
296
297
Parameters:
298
- keep_readonly: Include readonly fields
299
- key_transformer: Function to transform keys
300
- kwargs: Serialization options
301
302
Returns:
303
Dictionary representation
304
"""
305
306
def __eq__(self, other) -> bool:
307
"""Compare models for equality."""
308
309
def __ne__(self, other) -> bool:
310
"""Compare models for inequality."""
311
312
def __str__(self) -> str:
313
"""String representation of model."""
314
315
def is_xml_model(self) -> bool:
316
"""Check if model supports XML serialization."""
317
318
@classmethod
319
def deserialize(cls, data: str, content_type=None):
320
"""
321
Parse string data to create model instance.
322
323
Parameters:
324
- data: JSON/XML string data
325
- content_type: Data format ('application/json' or 'application/xml')
326
327
Returns:
328
Model instance
329
330
Raises:
331
DeserializationError if parsing fails
332
"""
333
334
@classmethod
335
def from_dict(cls, data: dict, key_extractors=None, content_type=None):
336
"""
337
Create model instance from dictionary.
338
339
Parameters:
340
- data: Dictionary data
341
- key_extractors: List of key extraction functions
342
- content_type: Content type hint
343
344
Returns:
345
Model instance
346
"""
347
348
@classmethod
349
def enable_additional_properties_sending(cls):
350
"""Enable serialization of additional properties."""
351
```
352
353
### Utility Classes
354
355
Timezone and datetime utility classes for proper date/time handling.
356
357
```python { .api }
358
class UTC:
359
"""UTC timezone implementation."""
360
361
def utcoffset(self, dt):
362
"""Return UTC offset (always zero)."""
363
364
def tzname(self, dt):
365
"""Return timezone name."""
366
367
def dst(self, dt):
368
"""Return daylight saving time offset."""
369
370
class _FixedOffset:
371
"""Fixed UTC offset timezone."""
372
373
def __init__(self, offset_hours: int, name: str):
374
"""Initialize with hour offset and name."""
375
376
def utcoffset(self, dt):
377
"""Return the fixed UTC offset."""
378
379
def tzname(self, dt):
380
"""Return timezone name."""
381
382
def dst(self, dt):
383
"""Return DST offset (always zero for fixed offset)."""
384
```
385
386
### Key Extractors
387
388
Functions for extracting and transforming dictionary keys during deserialization.
389
390
```python { .api }
391
def rest_key_extractor(attr: str, attr_desc: dict, data: dict):
392
"""
393
Extract REST API key from response data.
394
395
Parameters:
396
- attr: Attribute name
397
- attr_desc: Attribute description from _attribute_map
398
- data: Response data dictionary
399
400
Returns:
401
Extracted key or KeyError
402
"""
403
404
def rest_key_case_insensitive_extractor(attr: str, attr_desc: dict, data: dict):
405
"""Case-insensitive REST key extraction."""
406
407
def last_rest_key_extractor(attr: str, attr_desc: dict, data: dict):
408
"""Extract last matching REST key."""
409
410
def xml_key_extractor(attr: str, attr_desc: dict, data):
411
"""
412
Extract keys from XML data with namespace support.
413
414
Supports XML attributes, elements, text content, and namespaces.
415
"""
416
417
def attribute_key_extractor(attr: str, attr_desc: dict, data: dict):
418
"""Extract using Python attribute names."""
419
420
def attribute_key_case_insensitive_extractor(attr: str, attr_desc: dict, data: dict):
421
"""Case-insensitive attribute key extraction."""
422
```
423
424
### Data Type Support
425
426
Comprehensive support for various data types including dates, times, binary data, and collections.
427
428
```python { .api }
429
# Static serialization methods
430
@staticmethod
431
def serialize_iso(attr, **kwargs) -> str:
432
"""Serialize datetime to ISO-8601 string."""
433
434
@staticmethod
435
def serialize_rfc(attr, **kwargs) -> str:
436
"""Serialize datetime to RFC-1123 string."""
437
438
@staticmethod
439
def serialize_unix(attr, **kwargs) -> int:
440
"""Serialize datetime to Unix timestamp."""
441
442
@staticmethod
443
def serialize_date(attr, **kwargs) -> str:
444
"""Serialize date to ISO format string."""
445
446
@staticmethod
447
def serialize_time(attr, **kwargs) -> str:
448
"""Serialize time to ISO format string."""
449
450
@staticmethod
451
def serialize_duration(attr, **kwargs) -> str:
452
"""Serialize timedelta to ISO-8601 duration."""
453
454
@staticmethod
455
def serialize_decimal(attr, **kwargs) -> float:
456
"""Serialize Decimal to float."""
457
458
@staticmethod
459
def serialize_base64(attr, **kwargs) -> str:
460
"""Serialize bytes to base64 string."""
461
462
@staticmethod
463
def serialize_bytearray(attr, **kwargs) -> str:
464
"""Serialize bytearray to base64 string."""
465
466
# Static deserialization methods
467
@staticmethod
468
def deserialize_iso(attr) -> datetime:
469
"""Deserialize ISO-8601 string to datetime."""
470
471
@staticmethod
472
def deserialize_rfc(attr) -> datetime:
473
"""Deserialize RFC-1123 string to datetime."""
474
475
@staticmethod
476
def deserialize_unix(attr) -> datetime:
477
"""Deserialize Unix timestamp to datetime."""
478
479
@staticmethod
480
def deserialize_date(attr) -> date:
481
"""Deserialize ISO date string to date object."""
482
483
@staticmethod
484
def deserialize_time(attr) -> time:
485
"""Deserialize ISO time string to time object."""
486
487
@staticmethod
488
def deserialize_duration(attr) -> timedelta:
489
"""Deserialize ISO duration to timedelta."""
490
491
@staticmethod
492
def deserialize_decimal(attr) -> Decimal:
493
"""Deserialize string to Decimal object."""
494
495
@staticmethod
496
def deserialize_base64(attr) -> bytes:
497
"""Deserialize base64 string to bytes."""
498
499
@staticmethod
500
def deserialize_bytearray(attr) -> bytearray:
501
"""Deserialize base64 string to bytearray."""
502
```
503
504
### Key Transformers
505
506
Functions for transforming object keys during serialization/deserialization.
507
508
```python { .api }
509
def attribute_transformer(key: str, attr_desc: dict, value) -> tuple:
510
"""
511
Transform using Python attribute names.
512
513
Parameters:
514
- key: Attribute name
515
- attr_desc: Attribute metadata
516
- value: Attribute value
517
518
Returns:
519
Tuple of (key, value)
520
"""
521
522
def full_restapi_key_transformer(key: str, attr_desc: dict, value) -> tuple:
523
"""
524
Transform using full REST API key path.
525
526
Parameters:
527
- key: Attribute name
528
- attr_desc: Attribute metadata
529
- value: Attribute value
530
531
Returns:
532
Tuple of (key_list, value) for nested structures
533
"""
534
535
def last_restapi_key_transformer(key: str, attr_desc: dict, value) -> tuple:
536
"""
537
Transform using last component of REST API key.
538
539
Parameters:
540
- key: Attribute name
541
- attr_desc: Attribute metadata
542
- value: Attribute value
543
544
Returns:
545
Tuple of (last_key, value)
546
"""
547
```
548
549
### Validation
550
551
Comprehensive validation system with multiple validation rules.
552
553
```python { .api }
554
@classmethod
555
def validate(cls, data, name: str, **kwargs):
556
"""
557
Validate data against specified rules.
558
559
Parameters:
560
- data: Data to validate
561
- name: Field name for error reporting
562
- kwargs: Validation rules (required, min_length, max_length, etc.)
563
564
Returns:
565
Validated data
566
567
Raises:
568
ValidationError if validation fails
569
"""
570
571
# Validation rules supported in kwargs:
572
# - required: bool - Field cannot be None
573
# - min_length: int - Minimum string/array length
574
# - max_length: int - Maximum string/array length
575
# - minimum: int/float - Minimum numeric value
576
# - maximum: int/float - Maximum numeric value
577
# - min_items: int - Minimum array items
578
# - max_items: int - Maximum array items
579
# - pattern: str - Regex pattern to match
580
# - unique: bool - Array items must be unique
581
# - multiple: int/float - Value must be multiple of this
582
```
583
584
## Usage Examples
585
586
### Basic Serialization
587
588
```python
589
from msrest.serialization import Serializer
590
591
# Create serializer
592
serializer = Serializer()
593
594
# Serialize for URL parameter
595
user_id = 123
596
url_param = serializer.url('user_id', user_id, 'int') # "123"
597
598
# Serialize for query parameter
599
tags = ['python', 'rest', 'api']
600
query_param = serializer.query('tags', tags, '[str]') # "python,rest,api"
601
602
# Serialize for request body
603
data = {'name': 'John', 'age': 30}
604
body = serializer.body(data, 'UserModel')
605
```
606
607
### Model Class Usage
608
609
```python
610
from msrest.serialization import Model
611
612
class User(Model):
613
_attribute_map = {
614
'name': {'key': 'name', 'type': 'str'},
615
'email': {'key': 'email', 'type': 'str'},
616
'age': {'key': 'age', 'type': 'int'}
617
}
618
_validation = {
619
'name': {'required': True, 'min_length': 1},
620
'email': {'required': True, 'pattern': r'^[^@]+@[^@]+\.[^@]+$'},
621
'age': {'minimum': 0, 'maximum': 150}
622
}
623
624
# Create and validate model
625
user = User(name='John Doe', email='john@example.com', age=30)
626
validation_errors = user.validate()
627
628
if not validation_errors:
629
# Serialize to JSON
630
json_data = user.serialize()
631
632
# Convert to dictionary
633
user_dict = user.as_dict()
634
```
635
636
### Deserialization
637
638
```python
639
from msrest.serialization import Deserializer
640
641
# Create deserializer with model classes
642
classes = {'User': User, 'Address': Address}
643
deserializer = Deserializer(classes)
644
645
# Deserialize JSON response
646
json_response = '{"name": "John", "email": "john@example.com", "age": 30}'
647
user = deserializer('User', json_response)
648
649
# Deserialize from dictionary
650
response_dict = {'name': 'Jane', 'email': 'jane@example.com', 'age': 25}
651
user = User.from_dict(response_dict)
652
```
653
654
### Date/Time Handling
655
656
```python
657
from datetime import datetime, date, timedelta
658
from msrest.serialization import Serializer
659
660
serializer = Serializer()
661
662
# Serialize datetime to ISO-8601
663
dt = datetime(2023, 12, 25, 15, 30, 0)
664
iso_string = serializer.serialize_iso(dt) # "2023-12-25T15:30:00Z"
665
666
# Serialize date
667
d = date(2023, 12, 25)
668
date_string = serializer.serialize_date(d) # "2023-12-25"
669
670
# Serialize duration
671
delta = timedelta(hours=2, minutes=30)
672
duration_string = serializer.serialize_duration(delta) # "PT2H30M"
673
```
674
675
### XML Serialization
676
677
```python
678
from msrest.serialization import Model
679
680
class Product(Model):
681
_attribute_map = {
682
'name': {'key': 'name', 'type': 'str'},
683
'price': {'key': 'price', 'type': 'float'}
684
}
685
_xml_map = {
686
'name': 'Product',
687
'ns': 'http://example.com/products'
688
}
689
690
product = Product(name='Widget', price=19.99)
691
692
# Serialize to XML
693
xml_data = product.serialize(is_xml=True)
694
```
695
696
### Custom Validation
697
698
```python
699
from msrest.serialization import Model
700
from msrest.exceptions import ValidationError
701
702
class OrderItem(Model):
703
_attribute_map = {
704
'quantity': {'key': 'quantity', 'type': 'int'},
705
'price': {'key': 'price', 'type': 'float'}
706
}
707
_validation = {
708
'quantity': {'required': True, 'minimum': 1, 'maximum': 1000},
709
'price': {'required': True, 'minimum': 0.01}
710
}
711
712
# This will raise ValidationError
713
try:
714
item = OrderItem(quantity=0, price=-5.00)
715
item.validate()
716
except ValidationError as e:
717
print(f"Validation failed: {e}")
718
```
719
720
## Exception Handling
721
722
```python
723
from msrest.exceptions import SerializationError, DeserializationError, ValidationError
724
725
try:
726
# Serialization
727
serialized = serializer.body(data, 'ComplexType')
728
729
# Deserialization
730
deserialized = deserializer('ComplexType', response_data)
731
732
except SerializationError as e:
733
print(f"Serialization failed: {e}")
734
except DeserializationError as e:
735
print(f"Deserialization failed: {e}")
736
except ValidationError as e:
737
print(f"Validation failed: {e}")
738
```