@@ -106,7 +106,7 @@ def multidict(ordered_pairs):
106
106
_jsonloads = functools .partial (json .loads , object_pairs_hook = multidict )
107
107
108
108
109
- def apply_patch (doc , patch , in_place = False ):
109
+ def apply_patch (doc , patch , in_place = False , pointer_cls = JsonPointer ):
110
110
"""Apply list of patches to specified json document.
111
111
112
112
:param doc: Document object.
@@ -137,13 +137,13 @@ def apply_patch(doc, patch, in_place=False):
137
137
"""
138
138
139
139
if isinstance (patch , basestring ):
140
- patch = JsonPatch .from_string (patch )
140
+ patch = JsonPatch .from_string (patch , pointer_cls = pointer_cls )
141
141
else :
142
- patch = JsonPatch (patch )
142
+ patch = JsonPatch (patch , pointer_cls = pointer_cls )
143
143
return patch .apply (doc , in_place )
144
144
145
145
146
- def make_patch (src , dst ):
146
+ def make_patch (src , dst , pointer_cls = JsonPointer ):
147
147
"""Generates patch by comparing two document objects. Actually is
148
148
a proxy to :meth:`JsonPatch.from_diff` method.
149
149
@@ -153,6 +153,9 @@ def make_patch(src, dst):
153
153
:param dst: Data source document object.
154
154
:type dst: dict
155
155
156
+ :param pointer_cls: JSON pointer (sub)class.
157
+ :type pointer_cls: Type[JsonPointer]
158
+
156
159
>>> src = {'foo': 'bar', 'numbers': [1, 3, 4, 8]}
157
160
>>> dst = {'baz': 'qux', 'numbers': [1, 4, 7]}
158
161
>>> patch = make_patch(src, dst)
@@ -161,7 +164,7 @@ def make_patch(src, dst):
161
164
True
162
165
"""
163
166
164
- return JsonPatch .from_diff (src , dst )
167
+ return JsonPatch .from_diff (src , dst , pointer_cls = pointer_cls )
165
168
166
169
167
170
class JsonPatch (object ):
@@ -210,8 +213,9 @@ class JsonPatch(object):
210
213
... patch.apply(old) #doctest: +ELLIPSIS
211
214
{...}
212
215
"""
213
- def __init__ (self , patch ):
216
+ def __init__ (self , patch , pointer_cls = JsonPointer ):
214
217
self .patch = patch
218
+ self .pointer_cls = pointer_cls
215
219
216
220
self .operations = {
217
221
'remove' : RemoveOperation ,
@@ -246,19 +250,22 @@ def __ne__(self, other):
246
250
return not (self == other )
247
251
248
252
@classmethod
249
- def from_string (cls , patch_str ):
253
+ def from_string (cls , patch_str , pointer_cls = JsonPointer ):
250
254
"""Creates JsonPatch instance from string source.
251
255
252
256
:param patch_str: JSON patch as raw string.
253
- :type patch_str: str
257
+ :type pointer_cls: str
258
+
259
+ :param pointer_cls: JSON pointer (sub)class.
260
+ :type pointer_cls: Type[JsonPointer]
254
261
255
262
:return: :class:`JsonPatch` instance.
256
263
"""
257
264
patch = _jsonloads (patch_str )
258
- return cls (patch )
265
+ return cls (patch , pointer_cls = pointer_cls )
259
266
260
267
@classmethod
261
- def from_diff (cls , src , dst , optimization = True ):
268
+ def from_diff (cls , src , dst , optimization = True , pointer_cls = JsonPointer ):
262
269
"""Creates JsonPatch instance based on comparison of two document
263
270
objects. Json patch would be created for `src` argument against `dst`
264
271
one.
@@ -269,6 +276,9 @@ def from_diff(cls, src, dst, optimization=True):
269
276
:param dst: Data source document object.
270
277
:type dst: dict
271
278
279
+ :param pointer_cls: JSON pointer (sub)class.
280
+ :type pointer_cls: Type[JsonPointer]
281
+
272
282
:return: :class:`JsonPatch` instance.
273
283
274
284
>>> src = {'foo': 'bar', 'numbers': [1, 3, 4, 8]}
@@ -279,10 +289,10 @@ def from_diff(cls, src, dst, optimization=True):
279
289
True
280
290
"""
281
291
282
- builder = DiffBuilder ()
292
+ builder = DiffBuilder (pointer_cls = pointer_cls )
283
293
builder ._compare_values ('' , None , src , dst )
284
294
ops = list (builder .execute ())
285
- return cls (ops )
295
+ return cls (ops , pointer_cls = pointer_cls )
286
296
287
297
def to_string (self ):
288
298
"""Returns patch set as JSON string."""
@@ -326,24 +336,25 @@ def _get_operation(self, operation):
326
336
raise InvalidJsonPatch ("Unknown operation {0!r}" .format (op ))
327
337
328
338
cls = self .operations [op ]
329
- return cls (operation )
339
+ return cls (operation , pointer_cls = self . pointer_cls )
330
340
331
341
332
342
class PatchOperation (object ):
333
343
"""A single operation inside a JSON Patch."""
334
344
335
- def __init__ (self , operation ):
345
+ def __init__ (self , operation , pointer_cls = JsonPointer ):
346
+ self .pointer_cls = pointer_cls
336
347
337
348
if not operation .__contains__ ('path' ):
338
349
raise InvalidJsonPatch ("Operation must have a 'path' member" )
339
350
340
- if isinstance (operation ['path' ], JsonPointer ):
351
+ if isinstance (operation ['path' ], self . pointer_cls ):
341
352
self .location = operation ['path' ].path
342
353
self .pointer = operation ['path' ]
343
354
else :
344
355
self .location = operation ['path' ]
345
356
try :
346
- self .pointer = JsonPointer (self .location )
357
+ self .pointer = self . pointer_cls (self .location )
347
358
except TypeError as ex :
348
359
raise InvalidJsonPatch ("Invalid 'path'" )
349
360
@@ -511,10 +522,10 @@ class MoveOperation(PatchOperation):
511
522
512
523
def apply (self , obj ):
513
524
try :
514
- if isinstance (self .operation ['from' ], JsonPointer ):
525
+ if isinstance (self .operation ['from' ], self . pointer_cls ):
515
526
from_ptr = self .operation ['from' ]
516
527
else :
517
- from_ptr = JsonPointer (self .operation ['from' ])
528
+ from_ptr = self . pointer_cls (self .operation ['from' ])
518
529
except KeyError as ex :
519
530
raise InvalidJsonPatch (
520
531
"The operation does not contain a 'from' member" )
@@ -536,32 +547,32 @@ def apply(self, obj):
536
547
obj = RemoveOperation ({
537
548
'op' : 'remove' ,
538
549
'path' : self .operation ['from' ]
539
- }).apply (obj )
550
+ }, pointer_cls = self . pointer_cls ).apply (obj )
540
551
541
552
obj = AddOperation ({
542
553
'op' : 'add' ,
543
554
'path' : self .location ,
544
555
'value' : value
545
- }).apply (obj )
556
+ }, pointer_cls = self . pointer_cls ).apply (obj )
546
557
547
558
return obj
548
559
549
560
@property
550
561
def from_path (self ):
551
- from_ptr = JsonPointer (self .operation ['from' ])
562
+ from_ptr = self . pointer_cls (self .operation ['from' ])
552
563
return '/' .join (from_ptr .parts [:- 1 ])
553
564
554
565
@property
555
566
def from_key (self ):
556
- from_ptr = JsonPointer (self .operation ['from' ])
567
+ from_ptr = self . pointer_cls (self .operation ['from' ])
557
568
try :
558
569
return int (from_ptr .parts [- 1 ])
559
570
except TypeError :
560
571
return from_ptr .parts [- 1 ]
561
572
562
573
@from_key .setter
563
574
def from_key (self , value ):
564
- from_ptr = JsonPointer (self .operation ['from' ])
575
+ from_ptr = self . pointer_cls (self .operation ['from' ])
565
576
from_ptr .parts [- 1 ] = str (value )
566
577
self .operation ['from' ] = from_ptr .path
567
578
@@ -624,7 +635,7 @@ class CopyOperation(PatchOperation):
624
635
625
636
def apply (self , obj ):
626
637
try :
627
- from_ptr = JsonPointer (self .operation ['from' ])
638
+ from_ptr = self . pointer_cls (self .operation ['from' ])
628
639
except KeyError as ex :
629
640
raise InvalidJsonPatch (
630
641
"The operation does not contain a 'from' member" )
@@ -639,14 +650,15 @@ def apply(self, obj):
639
650
'op' : 'add' ,
640
651
'path' : self .location ,
641
652
'value' : value
642
- }).apply (obj )
653
+ }, pointer_cls = self . pointer_cls ).apply (obj )
643
654
644
655
return obj
645
656
646
657
647
658
class DiffBuilder (object ):
648
659
649
- def __init__ (self ):
660
+ def __init__ (self , pointer_cls = JsonPointer ):
661
+ self .pointer_cls = pointer_cls
650
662
self .index_storage = [{}, {}]
651
663
self .index_storage2 = [[], []]
652
664
self .__root = root = []
@@ -715,7 +727,7 @@ def execute(self):
715
727
'op' : 'replace' ,
716
728
'path' : op_second .location ,
717
729
'value' : op_second .operation ['value' ],
718
- }).operation
730
+ }, pointer_cls = self . pointer_cls ).operation
719
731
curr = curr [1 ][1 ]
720
732
continue
721
733
@@ -736,22 +748,22 @@ def _item_added(self, path, key, item):
736
748
'op' : 'move' ,
737
749
'from' : op .location ,
738
750
'path' : _path_join (path , key ),
739
- })
751
+ }, pointer_cls = self . pointer_cls )
740
752
self .insert (new_op )
741
753
else :
742
754
new_op = AddOperation ({
743
755
'op' : 'add' ,
744
756
'path' : _path_join (path , key ),
745
757
'value' : item ,
746
- })
758
+ }, pointer_cls = self . pointer_cls )
747
759
new_index = self .insert (new_op )
748
760
self .store_index (item , new_index , _ST_ADD )
749
761
750
762
def _item_removed (self , path , key , item ):
751
763
new_op = RemoveOperation ({
752
764
'op' : 'remove' ,
753
765
'path' : _path_join (path , key ),
754
- })
766
+ }, pointer_cls = self . pointer_cls )
755
767
index = self .take_index (item , _ST_ADD )
756
768
new_index = self .insert (new_op )
757
769
if index is not None :
@@ -766,7 +778,7 @@ def _item_removed(self, path, key, item):
766
778
'op' : 'move' ,
767
779
'from' : new_op .location ,
768
780
'path' : op .location ,
769
- })
781
+ }, pointer_cls = self . pointer_cls )
770
782
new_index [2 ] = new_op
771
783
772
784
else :
@@ -780,7 +792,7 @@ def _item_replaced(self, path, key, item):
780
792
'op' : 'replace' ,
781
793
'path' : _path_join (path , key ),
782
794
'value' : item ,
783
- }))
795
+ }, pointer_cls = self . pointer_cls ))
784
796
785
797
def _compare_dicts (self , path , src , dst ):
786
798
src_keys = set (src .keys ())
0 commit comments