0
# Utilities and Helpers
1
2
Utility classes and functions supporting Schematics functionality. These components provide role-based field filtering, validation helpers, and other supporting functionality for advanced model usage.
3
4
## Capabilities
5
6
### Role System
7
8
Role-based field filtering system for controlling data access and export.
9
10
```python { .api }
11
class Role(Set):
12
"""
13
Field filtering system using set-based operations.
14
15
A Role defines which fields should be included or excluded from
16
operations like export, serialization, or validation based on
17
user permissions or context.
18
"""
19
20
def __init__(self, function, fields):
21
"""
22
Initialize role with filtering function and field set.
23
24
Args:
25
function (callable): Filter function taking field name, returns bool
26
fields (iterable): Collection of field names this role affects
27
"""
28
29
def __contains__(self, field_name):
30
"""
31
Check if field is included in this role.
32
33
Args:
34
field_name (str): Field name to check
35
36
Returns:
37
bool: True if field should be included
38
"""
39
```
40
41
### Import String Utilities
42
43
Utilities for dynamic import of classes and functions from string paths.
44
45
```python { .api }
46
def import_string(import_name):
47
"""
48
Import a class or function from a string path.
49
50
Args:
51
import_name (str): Dotted import path (e.g., 'mymodule.MyClass')
52
53
Returns:
54
object: Imported class or function
55
56
Raises:
57
ImportStringError: If import fails
58
"""
59
60
class ImportStringError(Exception):
61
"""
62
Exception raised when import_string fails to import from string path.
63
"""
64
```
65
66
### Collection Utilities
67
68
Helper functions for working with collections and data structures.
69
70
```python { .api }
71
def listify(value):
72
"""
73
Convert value to list format for consistent processing.
74
75
Args:
76
value: Value to convert (single item, list, tuple, etc.)
77
78
Returns:
79
list: Value as list
80
"""
81
82
def get_all_subclasses(cls):
83
"""
84
Get all subclasses of a class recursively.
85
86
Args:
87
cls (type): Class to find subclasses of
88
89
Returns:
90
set: All subclasses including nested subclasses
91
"""
92
```
93
94
### Threading Utilities
95
96
Thread-safe utilities for concurrent model usage.
97
98
```python { .api }
99
def get_ident():
100
"""
101
Get current thread identifier for thread-safe operations.
102
103
Returns:
104
int: Thread identifier
105
"""
106
107
def setdefault(obj, attr, value, search_mro=False, overwrite_none=False):
108
"""
109
Enhanced setdefault with MRO search and None overwrite options.
110
111
Args:
112
obj: Object to set attribute on
113
attr (str): Attribute name
114
value: Default value to set
115
search_mro (bool): Whether to search method resolution order
116
overwrite_none (bool): Whether to overwrite None values
117
118
Returns:
119
Current or newly set attribute value
120
"""
121
```
122
123
### Constants and Enums
124
125
Special constant classes used throughout Schematics.
126
127
```python { .api }
128
class Constant(int):
129
"""
130
Special integer constant with string representation.
131
132
Used for export levels and other enumerated constants that need
133
both numeric and readable string representations.
134
"""
135
136
def __new__(cls, value, name=None):
137
"""
138
Create constant with value and optional name.
139
140
Args:
141
value (int): Numeric value
142
name (str, optional): String representation
143
"""
144
```
145
146
## Usage Examples
147
148
### Role-Based Field Filtering
149
150
```python
151
from schematics.models import Model
152
from schematics.types import StringType, IntType, BooleanType
153
from schematics.role import Role
154
155
class User(Model):
156
name = StringType(required=True)
157
email = StringType(required=True)
158
age = IntType()
159
is_admin = BooleanType(default=False)
160
salary = IntType()
161
162
# Define roles
163
public_role = Role(lambda field: field in ['name', 'age'], ['name', 'age'])
164
admin_role = Role(lambda field: field != 'salary', ['name', 'email', 'age', 'is_admin'])
165
166
user = User({
167
'name': 'John Doe',
168
'email': 'john@example.com',
169
'age': 30,
170
'is_admin': False,
171
'salary': 75000
172
})
173
174
# Export with role filtering
175
public_data = user.export(role=public_role)
176
# {'name': 'John Doe', 'age': 30}
177
178
admin_data = user.export(role=admin_role)
179
# {'name': 'John Doe', 'email': 'john@example.com', 'age': 30, 'is_admin': False}
180
```
181
182
### Dynamic Field Types
183
184
```python
185
from schematics.util import import_string, listify
186
187
# Dynamic import of field types
188
field_class = import_string('schematics.types.StringType')
189
field = field_class(required=True, max_length=100)
190
191
# Convert various inputs to lists
192
single_value = listify('item') # ['item']
193
multiple_values = listify(['a', 'b']) # ['a', 'b']
194
tuple_values = listify(('x', 'y')) # ['x', 'y']
195
```
196
197
### Thread-Safe Model Usage
198
199
```python
200
import threading
201
from schematics.util import get_ident
202
203
class ThreadSafeModel(Model):
204
def __init__(self, *args, **kwargs):
205
super().__init__(*args, **kwargs)
206
self._thread_id = get_ident()
207
208
def validate(self, *args, **kwargs):
209
current_thread = get_ident()
210
if current_thread != self._thread_id:
211
# Handle cross-thread validation
212
pass
213
return super().validate(*args, **kwargs)
214
```
215
216
### Custom Constants
217
218
```python
219
from schematics.util import Constant
220
221
# Define custom export levels
222
BASIC_EXPORT = Constant(5, 'BASIC_EXPORT')
223
DETAILED_EXPORT = Constant(15, 'DETAILED_EXPORT')
224
FULL_EXPORT = Constant(25, 'FULL_EXPORT')
225
226
class Product(Model):
227
name = StringType(export_level=BASIC_EXPORT)
228
description = StringType(export_level=DETAILED_EXPORT)
229
internal_notes = StringType(export_level=FULL_EXPORT)
230
231
# Export at different levels
232
product = Product({
233
'name': 'Widget',
234
'description': 'A useful widget',
235
'internal_notes': 'Manufactured in facility B'
236
})
237
238
# Only exports fields with export_level <= specified level
239
basic = product.export(export_level=BASIC_EXPORT)
240
# {'name': 'Widget'}
241
242
detailed = product.export(export_level=DETAILED_EXPORT)
243
# {'name': 'Widget', 'description': 'A useful widget'}
244
245
full = product.export(export_level=FULL_EXPORT)
246
# {'name': 'Widget', 'description': 'A useful widget', 'internal_notes': 'Manufactured in facility B'}
247
```