0
# JsonDiffer Configuration
1
2
The main class providing configurable diff computation with options for syntax, serialization, marshaling, and path exclusion. JsonDiffer serves as the central orchestrator for all diff operations and provides fine-grained control over the diff process.
3
4
## Capabilities
5
6
### JsonDiffer Class
7
8
Central class managing diff computation with comprehensive configuration options for different use cases and output requirements.
9
10
```python { .api }
11
class JsonDiffer:
12
"""
13
A class for computing differences between two JSON structures and applying patches.
14
"""
15
def __init__(self, syntax='compact', load=False, dump=False, marshal=False,
16
loader=None, dumper=None, escape_str='$'):
17
"""
18
Initialize JsonDiffer with specified options.
19
20
Parameters:
21
- syntax: str or syntax class, diff output format (default: 'compact')
22
- 'compact': Minimal output size
23
- 'explicit': Human-readable with clear operation labels
24
- 'symmetric': Bidirectional with original and modified values
25
- 'rightonly': Focus on final state values
26
- load: bool, automatically load JSON from strings or files (default: False)
27
- dump: bool, automatically dump output to JSON strings or files (default: False)
28
- marshal: bool, marshal diffs to handle special characters (default: False)
29
- loader: callable, custom function for loading JSON data (default: built-in JsonLoader)
30
- dumper: callable, custom function for dumping JSON data (default: built-in JsonDumper)
31
- escape_str: str, string used to escape special characters (default: '$')
32
"""
33
34
def diff(self, a, b, fp=None, exclude_paths=None):
35
"""
36
Compute difference between two JSON structures.
37
38
Parameters:
39
- a: Original JSON structure
40
- b: Modified JSON structure
41
- fp: Optional file pointer to dump diff to
42
- exclude_paths: list of string paths to exclude from diff
43
44
Returns:
45
dict: Computed diff structure
46
"""
47
48
def similarity(self, a, b):
49
"""
50
Calculate similarity score between two JSON structures.
51
52
Parameters:
53
- a: First JSON structure
54
- b: Second JSON structure
55
56
Returns:
57
float: Similarity score between 0.0 and 1.0
58
"""
59
60
def patch(self, a, d, fp=None):
61
"""
62
Apply diff to JSON structure to produce modified structure.
63
64
Parameters:
65
- a: Original JSON structure to patch
66
- d: Diff to apply
67
- fp: Optional file pointer to dump result to
68
69
Returns:
70
JSON structure: Patched structure
71
"""
72
73
def unpatch(self, b, d, fp=None):
74
"""
75
Reverse diff on JSON structure to produce original structure.
76
Available only with symmetric syntax.
77
78
Parameters:
79
- b: Modified JSON structure
80
- d: Diff that was applied
81
- fp: Optional file pointer to dump result to
82
83
Returns:
84
JSON structure: Original structure before diff
85
"""
86
87
def marshal(self, d):
88
"""
89
Convert structure to marshaled form with escaped special characters.
90
91
Parameters:
92
- d: Structure to marshal
93
94
Returns:
95
Marshaled structure with escaped symbols
96
"""
97
98
def unmarshal(self, d):
99
"""
100
Convert marshaled structure back to original form.
101
102
Parameters:
103
- d: Marshaled structure to unmarshal
104
105
Returns:
106
Original structure with unescaped symbols
107
"""
108
```
109
110
### Configuration Options
111
112
The JsonDiffer class provides extensive configuration through its Options inner class and constructor parameters.
113
114
```python { .api }
115
class JsonDiffer:
116
class Options:
117
"""Configuration options container for JsonDiffer."""
118
pass
119
```
120
121
**Usage Examples:**
122
123
```python
124
from jsondiff import JsonDiffer, JsonLoader, JsonDumper
125
126
# Basic configuration with different syntaxes
127
compact_differ = JsonDiffer(syntax='compact')
128
explicit_differ = JsonDiffer(syntax='explicit')
129
symmetric_differ = JsonDiffer(syntax='symmetric')
130
131
# Auto-loading from JSON strings
132
auto_loader = JsonDiffer(load=True)
133
result = auto_loader.diff('{"a": 1}', '{"a": 2, "b": 3}')
134
135
# Auto-dumping to JSON strings
136
auto_dumper = JsonDiffer(dump=True)
137
json_result = auto_dumper.diff({'a': 1}, {'a': 2}) # Returns JSON string
138
139
# Marshaling for safe serialization
140
marshal_differ = JsonDiffer(marshal=True)
141
result = marshal_differ.diff({'$delete': 'value'}, {'$delete': 'new_value'})
142
# Symbols are escaped: {'$$delete': 'new_value'}
143
144
# Custom loaders and dumpers
145
custom_loader = JsonLoader(parse_float=float, parse_int=int)
146
custom_dumper = JsonDumper(indent=2, sort_keys=True)
147
custom_differ = JsonDiffer(loader=custom_loader, dumper=custom_dumper)
148
149
# Custom escape string
150
custom_escape = JsonDiffer(escape_str='#')
151
# Symbols will be escaped with '#' instead of '$'
152
```
153
154
### Path Exclusion
155
156
Exclude specific JSON paths from diff computation, useful for ignoring timestamps, IDs, or other dynamic fields.
157
158
**Usage Examples:**
159
160
```python
161
from jsondiff import JsonDiffer
162
163
differ = JsonDiffer()
164
165
# Single path exclusion
166
data1 = {'user': {'name': 'John', 'last_login': '2023-01-01', 'id': 123}}
167
data2 = {'user': {'name': 'John', 'last_login': '2023-01-02', 'id': 123}}
168
169
result = differ.diff(data1, data2, exclude_paths=['user.last_login'])
170
# Result: {} (no differences after excluding timestamp)
171
172
# Multiple path exclusion
173
data1 = {
174
'users': [
175
{'name': 'Alice', 'id': 1, 'created': '2023-01-01'},
176
{'name': 'Bob', 'id': 2, 'created': '2023-01-02'}
177
],
178
'metadata': {'version': '1.0', 'timestamp': '2023-01-01T10:00:00'}
179
}
180
181
data2 = {
182
'users': [
183
{'name': 'Alice', 'id': 1, 'created': '2023-01-01'},
184
{'name': 'Bob', 'id': 2, 'created': '2023-01-02'},
185
{'name': 'Charlie', 'id': 3, 'created': '2023-01-03'}
186
],
187
'metadata': {'version': '1.1', 'timestamp': '2023-01-03T15:30:00'}
188
}
189
190
result = differ.diff(data1, data2, exclude_paths=[
191
'metadata.timestamp',
192
'users.created' # Note: This excludes the path pattern, not array elements
193
])
194
# Result focuses on structural changes, ignoring timestamps
195
```
196
197
### Advanced Configuration
198
199
Configure JsonDiffer for specialized use cases with custom serialization and processing options.
200
201
**Usage Examples:**
202
203
```python
204
from jsondiff import JsonDiffer, YamlLoader, YamlDumper
205
import json
206
207
# YAML processing configuration
208
yaml_differ = JsonDiffer(
209
load=True,
210
dump=True,
211
loader=YamlLoader(),
212
dumper=YamlDumper(default_flow_style=False)
213
)
214
215
# File-based operations
216
with open('config1.yaml', 'r') as f1, open('config2.yaml', 'r') as f2:
217
with open('diff.yaml', 'w') as output:
218
yaml_differ.diff(f1, f2, fp=output)
219
220
# High-precision numeric handling
221
class HighPrecisionLoader:
222
def __call__(self, src):
223
return json.loads(src, parse_float=lambda x: x) # Keep as string
224
225
precision_differ = JsonDiffer(loader=HighPrecisionLoader())
226
227
# Streaming large diffs
228
class StreamingDumper:
229
def __call__(self, obj, dest=None):
230
if dest:
231
json.dump(obj, dest, separators=(',', ':')) # Compact output
232
else:
233
return json.dumps(obj, separators=(',', ':'))
234
235
streaming_differ = JsonDiffer(dump=True, dumper=StreamingDumper())
236
237
# Combining multiple options
238
production_differ = JsonDiffer(
239
syntax='compact', # Minimal storage
240
marshal=True, # Safe for serialization
241
load=True, # Accept JSON strings
242
dump=True, # Return JSON strings
243
escape_str='@' # Custom escape character
244
)
245
```
246
247
### Marshaling and Unmarshaling
248
249
Handle special characters and symbols safely for serialization and storage.
250
251
**Usage Examples:**
252
253
```python
254
from jsondiff import JsonDiffer, delete, insert
255
256
differ = JsonDiffer(marshal=True)
257
258
# Data with symbol-like keys
259
original = {'$delete': 'some_value', 'normal_key': 'data'}
260
modified = {'$delete': 'updated_value', 'normal_key': 'data', '$insert': 'new'}
261
262
# Marshal handles symbol conflicts
263
result = differ.diff(original, modified)
264
# Symbols are properly escaped to avoid conflicts
265
266
# Manual marshaling/unmarshaling
267
raw_diff = {delete: ['removed_key'], 'updated_key': 'new_value'}
268
marshaled = differ.marshal(raw_diff)
269
print(marshaled) # {'$delete': ['removed_key'], 'updated_key': 'new_value'}
270
271
unmarshaled = differ.unmarshal(marshaled)
272
print(unmarshaled) # {delete: ['removed_key'], 'updated_key': 'new_value'}
273
274
# Safe round-trip serialization
275
import json
276
277
# Create diff with symbols
278
diff_with_symbols = differ.diff({'a': 1}, {'b': 2})
279
marshaled_diff = differ.marshal(diff_with_symbols)
280
281
# Serialize safely
282
json_str = json.dumps(marshaled_diff)
283
loaded_diff = json.loads(json_str)
284
285
# Unmarshal and apply
286
final_diff = differ.unmarshal(loaded_diff)
287
result = differ.patch({'a': 1}, final_diff)
288
```
289
290
## Error Handling
291
292
JsonDiffer handles various error conditions and provides clear error messages:
293
294
```python
295
from jsondiff import JsonDiffer
296
from json import JSONDecodeError
297
298
differ = JsonDiffer()
299
300
# Invalid syntax specification
301
try:
302
invalid_differ = JsonDiffer(syntax='nonexistent')
303
except (KeyError, AttributeError) as e:
304
print(f"Invalid syntax: {e}")
305
306
# Load errors with auto-loading
307
auto_differ = JsonDiffer(load=True)
308
try:
309
result = auto_differ.diff('{"invalid": json}', '{"valid": "json"}')
310
except JSONDecodeError as e:
311
print(f"JSON parsing error: {e}")
312
313
# Unpatch without symmetric syntax
314
compact_differ = JsonDiffer(syntax='compact')
315
try:
316
result = compact_differ.unpatch({'a': 2}, {'a': 1})
317
except AttributeError as e:
318
print(f"Unpatch not supported: {e}")
319
```