0
# Exceptions and Utilities
1
2
Marshmallow provides structured exception types for error handling and utility functions for data manipulation, type checking, and advanced use cases.
3
4
## Capabilities
5
6
### Exception Classes
7
8
Comprehensive exception hierarchy for handling validation and processing errors.
9
10
```python { .api }
11
class MarshmallowError(Exception):
12
"""
13
Base exception class for all marshmallow-related errors.
14
"""
15
16
class ValidationError(MarshmallowError):
17
"""
18
Main exception raised when validation fails during deserialization.
19
20
Attributes:
21
- messages: dict/list/str, validation error messages
22
- field_name: str, name of the field where error occurred (if applicable)
23
- data: dict, raw input data that caused the error
24
- valid_data: dict, successfully validated data (if any)
25
"""
26
27
def __init__(self, message, field_name="_schema", data=None, valid_data=None, **kwargs):
28
"""
29
Initialize ValidationError.
30
31
Parameters:
32
- message: str/list/dict, error message(s)
33
- field_name: str, field name where error occurred (default: "_schema")
34
- data: dict, input data that failed validation
35
- valid_data: dict, any data that passed validation
36
"""
37
38
@property
39
def messages_dict(self):
40
"""
41
Get error messages as a dictionary.
42
43
Returns:
44
dict: error messages organized by field name
45
"""
46
47
class RegistryError(MarshmallowError):
48
"""
49
Raised for invalid schema registry operations.
50
"""
51
52
class StringNotCollectionError(ValidationError):
53
"""
54
Raised when a string is passed where a collection is expected.
55
"""
56
```
57
58
### Error Constants
59
60
```python { .api }
61
SCHEMA = "_schema" # Key used for schema-level validation errors
62
```
63
64
### Utility Functions
65
66
Helper functions for data manipulation and object introspection.
67
68
```python { .api }
69
def get_value(obj, key, default=missing):
70
"""
71
Get a value from an object by key with fallback support.
72
73
Parameters:
74
- obj: object to get value from (dict-like or object with attributes)
75
- key: str, key or attribute name (supports dot notation for nested access)
76
- default: default value if key is not found
77
78
Returns:
79
The value at the specified key, or default if not found
80
"""
81
82
def set_value(dct, key, value):
83
"""
84
Set a value in a dictionary using dot notation for nested keys.
85
86
Parameters:
87
- dct: dict, dictionary to modify
88
- key: str, key name (supports dot notation like 'user.profile.name')
89
- value: value to set
90
"""
91
92
def pluck(dictlist, key):
93
"""
94
Extract a list of values by key from a list of dictionaries.
95
96
Parameters:
97
- dictlist: list of dict, list of dictionaries
98
- key: str, key to extract from each dictionary
99
100
Returns:
101
list: values extracted from each dictionary
102
"""
103
```
104
105
### Type Checking Utilities
106
107
Functions for runtime type checking and validation.
108
109
```python { .api }
110
def is_collection(obj):
111
"""
112
Check if an object is a collection type (but not string/bytes).
113
114
Parameters:
115
- obj: object to check
116
117
Returns:
118
bool: True if object is a collection, False otherwise
119
"""
120
121
def is_iterable_but_not_string(obj):
122
"""
123
Check if an object is iterable but not a string or bytes.
124
125
Parameters:
126
- obj: object to check
127
128
Returns:
129
bool: True if iterable and not string/bytes
130
"""
131
132
def is_sequence_but_not_string(obj):
133
"""
134
Check if an object is a sequence but not a string or bytes.
135
136
Parameters:
137
- obj: object to check
138
139
Returns:
140
bool: True if sequence and not string/bytes
141
"""
142
143
def is_generator(obj):
144
"""
145
Check if an object is a generator.
146
147
Parameters:
148
- obj: object to check
149
150
Returns:
151
bool: True if object is a generator
152
"""
153
154
def callable_or_raise(obj):
155
"""
156
Check if an object is callable, raise TypeError if not.
157
158
Parameters:
159
- obj: object to check
160
161
Raises:
162
TypeError: if object is not callable
163
"""
164
```
165
166
### Date and Time Utilities
167
168
Functions for datetime conversion and manipulation.
169
170
```python { .api }
171
def is_aware(dt):
172
"""
173
Check if a datetime object is timezone-aware.
174
175
Parameters:
176
- dt: datetime object to check
177
178
Returns:
179
bool: True if datetime is timezone-aware
180
"""
181
182
def from_timestamp(value):
183
"""
184
Convert a POSIX timestamp to a datetime object.
185
186
Parameters:
187
- value: numeric timestamp (seconds since epoch)
188
189
Returns:
190
datetime: datetime object in UTC
191
"""
192
193
def from_timestamp_ms(value):
194
"""
195
Convert a millisecond timestamp to a datetime object.
196
197
Parameters:
198
- value: numeric timestamp (milliseconds since epoch)
199
200
Returns:
201
datetime: datetime object in UTC
202
"""
203
204
def timestamp(value):
205
"""
206
Convert a datetime object to a POSIX timestamp.
207
208
Parameters:
209
- value: datetime object
210
211
Returns:
212
float: timestamp in seconds since epoch
213
"""
214
215
def timestamp_ms(value):
216
"""
217
Convert a datetime object to a millisecond timestamp.
218
219
Parameters:
220
- value: datetime object
221
222
Returns:
223
int: timestamp in milliseconds since epoch
224
"""
225
226
def timedelta_to_microseconds(value):
227
"""
228
Convert a timedelta to total microseconds.
229
230
Parameters:
231
- value: timedelta object
232
233
Returns:
234
int: total microseconds
235
"""
236
```
237
238
### String Utilities
239
240
Functions for text processing and encoding.
241
242
```python { .api }
243
def ensure_text_type(val):
244
"""
245
Ensure a value is a text/string type.
246
247
Parameters:
248
- val: value to convert
249
250
Returns:
251
str: string representation of the value
252
"""
253
```
254
255
### Advanced Utilities
256
257
#### OrderedSet Class
258
259
```python { .api }
260
class OrderedSet:
261
"""
262
Set that maintains insertion order (similar to dict keys in Python 3.7+).
263
264
Provides standard set operations while preserving the order elements were added.
265
"""
266
267
def add(self, item):
268
"""Add an item to the set."""
269
270
def discard(self, item):
271
"""Remove an item from the set if present."""
272
273
def pop(self):
274
"""Remove and return the last item."""
275
276
def clear(self):
277
"""Remove all items from the set."""
278
279
def __contains__(self, item):
280
"""Check if item is in the set."""
281
282
def __iter__(self):
283
"""Iterate over items in insertion order."""
284
285
def __len__(self):
286
"""Return the number of items."""
287
```
288
289
290
## Usage Examples
291
292
### Error Handling
293
294
```python
295
from marshmallow import Schema, fields, ValidationError
296
297
class UserSchema(Schema):
298
username = fields.Str(required=True)
299
email = fields.Email(required=True)
300
age = fields.Int(validate=lambda x: x >= 18)
301
302
schema = UserSchema()
303
304
try:
305
result = schema.load({
306
'username': '',
307
'email': 'invalid-email',
308
'age': 15
309
})
310
except ValidationError as err:
311
print("Validation failed:")
312
print(f"Messages: {err.messages}")
313
print(f"Field errors: {err.messages_dict}")
314
print(f"Valid data: {err.valid_data}")
315
316
# Handle specific field errors
317
if 'email' in err.messages:
318
print("Email validation failed")
319
320
# Access nested error structure
321
for field, errors in err.messages.items():
322
print(f"{field}: {errors}")
323
```
324
325
### Data Manipulation Utilities
326
327
```python
328
from marshmallow.utils import get_value, set_value, pluck
329
330
# Working with nested data
331
user_data = {
332
'profile': {
333
'personal': {
334
'name': 'John Doe'
335
}
336
}
337
}
338
339
# Get nested values with dot notation
340
name = get_value(user_data, 'profile.personal.name') # 'John Doe'
341
missing_value = get_value(user_data, 'profile.work.title', 'N/A') # 'N/A'
342
343
# Set nested values
344
set_value(user_data, 'profile.personal.age', 30)
345
# user_data now has: {'profile': {'personal': {'name': 'John Doe', 'age': 30}}}
346
347
# Extract values from list of dictionaries
348
users = [
349
{'name': 'Alice', 'age': 25},
350
{'name': 'Bob', 'age': 30},
351
{'name': 'Charlie', 'age': 35}
352
]
353
names = pluck(users, 'name') # ['Alice', 'Bob', 'Charlie']
354
```
355
356
### Type Checking
357
358
```python
359
from marshmallow.utils import is_collection, is_sequence_but_not_string
360
361
# Type checking examples
362
print(is_collection([1, 2, 3])) # True
363
print(is_collection({'a': 1})) # True
364
print(is_collection('string')) # False
365
print(is_collection({1, 2, 3})) # True
366
367
print(is_sequence_but_not_string([1, 2, 3])) # True
368
print(is_sequence_but_not_string('string')) # False
369
print(is_sequence_but_not_string((1, 2, 3))) # True
370
print(is_sequence_but_not_string({1, 2, 3})) # False (set is not sequence)
371
```
372
373
### DateTime Utilities
374
375
```python
376
from datetime import datetime, timezone
377
from marshmallow.utils import timestamp, from_timestamp, is_aware
378
379
# Convert datetime to timestamp
380
dt = datetime(2023, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
381
ts = timestamp(dt) # Unix timestamp
382
383
# Convert timestamp back to datetime
384
dt_from_ts = from_timestamp(ts)
385
386
# Check timezone awareness
387
naive_dt = datetime(2023, 1, 1, 12, 0, 0)
388
aware_dt = datetime(2023, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
389
390
print(is_aware(naive_dt)) # False
391
print(is_aware(aware_dt)) # True
392
```
393
394
### Custom Exception Handling
395
396
```python
397
from marshmallow import Schema, fields, ValidationError, validates_schema
398
399
class CustomValidationSchema(Schema):
400
data = fields.Dict()
401
402
@validates_schema
403
def custom_validation(self, data, **kwargs):
404
"""Custom validation with detailed error reporting."""
405
errors = {}
406
407
# Complex validation logic
408
if 'required_field' not in data.get('data', {}):
409
errors['data'] = ['Missing required_field in data object']
410
411
# Multiple error conditions
412
value = data.get('data', {}).get('value')
413
if value is not None:
414
if not isinstance(value, (int, float)):
415
errors.setdefault('data', []).append('Value must be numeric')
416
elif value < 0:
417
errors.setdefault('data', []).append('Value must be positive')
418
419
if errors:
420
raise ValidationError(errors)
421
422
# Usage
423
schema = CustomValidationSchema()
424
try:
425
result = schema.load({'data': {'value': -5}})
426
except ValidationError as err:
427
# Handle multiple validation errors
428
for field, field_errors in err.messages.items():
429
for error in field_errors:
430
print(f"Error in {field}: {error}")
431
```
432
433
### OrderedSet Usage
434
435
```python
436
from marshmallow.orderedset import OrderedSet
437
438
# Create ordered set
439
tags = OrderedSet()
440
tags.add('python')
441
tags.add('marshmallow')
442
tags.add('validation')
443
tags.add('python') # Duplicate ignored
444
445
# Maintains insertion order
446
print(list(tags)) # ['python', 'marshmallow', 'validation']
447
448
# Standard set operations
449
tags.discard('python')
450
print('python' in tags) # False
451
print(len(tags)) # 2
452
```