0
# JSON Integration
1
2
Automatic JSON serialization support and monkeypatch utilities for seamless integration with JSON libraries. Provides custom encoders and system-wide patches for transparent frozendict serialization.
3
4
## Capabilities
5
6
### Automatic JSON Encoder
7
8
Custom JSON encoder that handles frozendict serialization by converting to regular dictionaries.
9
10
```python { .api }
11
class FrozendictJsonEncoder(JSONEncoder):
12
"""
13
JSON encoder that can serialize frozendict instances.
14
15
Automatically converts frozendict objects to regular dicts during
16
JSON serialization while preserving all other JSONEncoder functionality.
17
"""
18
19
def default(self, obj):
20
"""
21
Convert frozendict to dict for JSON serialization.
22
23
Parameters:
24
- obj: Object to serialize
25
26
Returns:
27
dict: Regular dict if obj is frozendict, otherwise delegates to parent
28
"""
29
```
30
31
**Usage Example:**
32
33
```python
34
import json
35
from frozendict import frozendict, FrozendictJsonEncoder
36
37
# Create frozendict with nested data
38
data = frozendict({
39
'name': 'Alice',
40
'settings': frozendict({'theme': 'dark', 'notifications': True}),
41
'tags': ['admin', 'developer']
42
})
43
44
# Serialize using custom encoder
45
json_string = json.dumps(data, cls=FrozendictJsonEncoder, indent=2)
46
print(json_string)
47
# {
48
# "name": "Alice",
49
# "settings": {
50
# "theme": "dark",
51
# "notifications": true
52
# },
53
# "tags": ["admin", "developer"]
54
# }
55
56
# Deserialize back to regular dicts
57
restored = json.loads(json_string)
58
# Note: restored will contain regular dicts, not frozendicts
59
```
60
61
### JSON Module Patching
62
63
Patch the standard json module to automatically handle frozendict serialization.
64
65
```python { .api }
66
def patchOrUnpatchJson(*, patch, warn=True):
67
"""
68
Patch or unpatch JSON module to handle frozendict serialization.
69
70
Parameters:
71
- patch: bool, True to apply patch, False to remove patch
72
- warn: bool, whether to show warnings about patching (default: True)
73
74
Returns:
75
None
76
77
Effects:
78
- When patched: json.dumps() automatically handles frozendict objects
79
- When unpatched: json.dumps() raises TypeError for frozendict objects
80
"""
81
```
82
83
**Usage Example:**
84
85
```python
86
import json
87
from frozendict import frozendict, patchOrUnpatchJson
88
89
# Enable automatic JSON support
90
patchOrUnpatchJson(patch=True, warn=False)
91
92
data = frozendict({'key': 'value', 'number': 42})
93
94
# Now json.dumps works directly with frozendict
95
json_string = json.dumps(data)
96
print(json_string) # {"key": "value", "number": 42}
97
98
# Disable automatic support
99
patchOrUnpatchJson(patch=False)
100
101
# Now json.dumps would raise TypeError
102
try:
103
json.dumps(data)
104
except TypeError as e:
105
print(f"Error: {e}") # Object of type frozendict is not JSON serializable
106
```
107
108
### OrJSON Integration
109
110
Support for the high-performance orjson library with automatic frozendict handling.
111
112
```python { .api }
113
def patchOrUnpatchOrjson(*, patch, warn=True):
114
"""
115
Patch or unpatch orjson module to handle frozendict serialization.
116
117
Parameters:
118
- patch: bool, True to apply patch, False to remove patch
119
- warn: bool, whether to show warnings about patching (default: True)
120
121
Returns:
122
None
123
124
Effects:
125
- When patched: orjson.dumps() automatically handles frozendict objects
126
- When unpatched: orjson.dumps() raises TypeError for frozendict objects
127
"""
128
```
129
130
**Usage Example:**
131
132
```python
133
# Requires: pip install orjson
134
import orjson
135
from frozendict import frozendict, patchOrUnpatchOrjson
136
137
# Enable orjson support
138
patchOrUnpatchOrjson(patch=True)
139
140
data = frozendict({'performance': 'high', 'speed': 'fast'})
141
142
# orjson now handles frozendict automatically
143
json_bytes = orjson.dumps(data)
144
json_string = json_bytes.decode('utf-8')
145
print(json_string) # {"performance": "high", "speed": "fast"}
146
147
# Restore original behavior
148
patchOrUnpatchOrjson(patch=False)
149
```
150
151
### Collections Integration
152
153
Patch collections.abc.MutableMapping to properly exclude frozendict from mutable mapping checks.
154
155
```python { .api }
156
def patchOrUnpatchMutableMappingSubclasshook(*, patch, warn=True):
157
"""
158
Patch or unpatch MutableMapping to exclude frozendict.
159
160
Parameters:
161
- patch: bool, True to apply patch, False to remove patch
162
- warn: bool, whether to show warnings about patching (default: True)
163
164
Returns:
165
None
166
167
Effects:
168
- When patched: isinstance(frozendict(), MutableMapping) returns False
169
- When unpatched: isinstance(frozendict(), MutableMapping) might return True
170
"""
171
```
172
173
**Usage Example:**
174
175
```python
176
from collections.abc import MutableMapping, Mapping
177
from frozendict import frozendict, patchOrUnpatchMutableMappingSubclasshook
178
179
# Apply the patch
180
patchOrUnpatchMutableMappingSubclasshook(patch=True)
181
182
d = frozendict({'a': 1, 'b': 2})
183
184
# frozendict is correctly identified as non-mutable
185
print(isinstance(d, Mapping)) # True (it is a mapping)
186
print(isinstance(d, MutableMapping)) # False (it is not mutable)
187
188
# Remove the patch
189
patchOrUnpatchMutableMappingSubclasshook(patch=False)
190
```
191
192
### Comprehensive Patching
193
194
Apply or remove all monkeypatches at once for complete integration.
195
196
```python { .api }
197
def patchOrUnpatchAll(*, patch, warn=True, raise_orjson=False):
198
"""
199
Apply or remove all monkeypatches at once.
200
201
Parameters:
202
- patch: bool, True to apply all patches, False to remove all patches
203
- warn: bool, whether to show warnings about patching (default: True)
204
- raise_orjson: bool, raise exception if orjson patch fails (default: False)
205
206
Returns:
207
None
208
209
Effects:
210
Applies/removes all of:
211
- JSON module patching
212
- OrJSON module patching (if available)
213
- MutableMapping subclass hook patching
214
"""
215
```
216
217
**Usage Example:**
218
219
```python
220
import json
221
from frozendict import frozendict, patchOrUnpatchAll
222
223
# Enable all integrations
224
patchOrUnpatchAll(patch=True, warn=False)
225
226
# Now everything works seamlessly
227
data = frozendict({'integrated': True, 'seamless': True})
228
json_result = json.dumps(data) # Works automatically
229
230
# Disable all integrations
231
patchOrUnpatchAll(patch=False, warn=False)
232
```
233
234
## Warning Classes
235
236
```python { .api }
237
class MonkeypatchWarning(Warning):
238
"""
239
Warning class for monkeypatch operations.
240
241
Issued when monkeypatch operations encounter potentially
242
problematic situations or when patches are applied/removed.
243
"""
244
```
245
246
**Usage Example:**
247
248
```python
249
import warnings
250
from frozendict import patchOrUnpatchAll, MonkeypatchWarning
251
252
# Monitor monkeypatch warnings
253
with warnings.catch_warnings(record=True) as w:
254
warnings.simplefilter("always")
255
256
# This might issue warnings about patching
257
patchOrUnpatchAll(patch=True, warn=True)
258
259
for warning in w:
260
if issubclass(warning.category, MonkeypatchWarning):
261
print(f"Monkeypatch warning: {warning.message}")
262
```
263
264
## Automatic Initialization
265
266
When importing frozendict, the following occurs automatically:
267
268
```python
269
# Automatically executed on import:
270
patchOrUnpatchAll(patch=True, warn=False)
271
```
272
273
This means that JSON serialization support is enabled by default when you import frozendict, providing seamless integration without explicit setup.
274
275
## Advanced Integration Patterns
276
277
### Custom JSON Encoder Extension
278
279
Extending FrozendictJsonEncoder for additional custom types:
280
281
```python
282
import json
283
from frozendict import FrozendictJsonEncoder
284
from datetime import datetime
285
286
class ExtendedJsonEncoder(FrozendictJsonEncoder):
287
def default(self, obj):
288
if isinstance(obj, datetime):
289
return obj.isoformat()
290
return super().default(obj)
291
292
# Use extended encoder
293
data = frozendict({
294
'timestamp': datetime.now(),
295
'nested': frozendict({'key': 'value'})
296
})
297
298
json_string = json.dumps(data, cls=ExtendedJsonEncoder)
299
```
300
301
### Selective Patching
302
303
Apply only specific patches for controlled integration:
304
305
```python
306
from frozendict import (
307
patchOrUnpatchJson,
308
patchOrUnpatchMutableMappingSubclasshook
309
)
310
311
# Enable only JSON support, not orjson
312
patchOrUnpatchJson(patch=True, warn=False)
313
patchOrUnpatchMutableMappingSubclasshook(patch=True, warn=False)
314
315
# orjson patching is not applied, giving more control
316
```
317
318
### Context-Managed Patching
319
320
Temporarily enable patches for specific operations:
321
322
```python
323
import json
324
from contextlib import contextmanager
325
from frozendict import frozendict, patchOrUnpatchJson
326
327
@contextmanager
328
def json_patched():
329
patchOrUnpatchJson(patch=True, warn=False)
330
try:
331
yield
332
finally:
333
patchOrUnpatchJson(patch=False, warn=False)
334
335
# Use within context
336
data = frozendict({'temp': 'patch'})
337
338
with json_patched():
339
result = json.dumps(data) # Works with patch
340
341
# Outside context, patch is removed
342
```