@@ -106,7 +106,7 @@ def multidict(ordered_pairs):
106106_jsonloads = functools .partial (json .loads , object_pairs_hook = multidict )
107107
108108
109- def apply_patch (doc , patch , in_place = False ):
109+ def apply_patch (doc , patch , in_place = False , pointer_cls = JsonPointer ):
110110 """Apply list of patches to specified json document.
111111
112112 :param doc: Document object.
@@ -137,13 +137,13 @@ def apply_patch(doc, patch, in_place=False):
137137 """
138138
139139 if isinstance (patch , basestring ):
140- patch = JsonPatch .from_string (patch )
140+ patch = JsonPatch .from_string (patch , pointer_cls = pointer_cls )
141141 else :
142- patch = JsonPatch (patch )
142+ patch = JsonPatch (patch , pointer_cls = pointer_cls )
143143 return patch .apply (doc , in_place )
144144
145145
146- def make_patch (src , dst ):
146+ def make_patch (src , dst , pointer_cls = JsonPointer ):
147147 """Generates patch by comparing two document objects. Actually is
148148 a proxy to :meth:`JsonPatch.from_diff` method.
149149
@@ -153,6 +153,9 @@ def make_patch(src, dst):
153153 :param dst: Data source document object.
154154 :type dst: dict
155155
156+ :param pointer_cls: JSON pointer (sub)class.
157+ :type pointer_cls: Type[JsonPointer]
158+
156159 >>> src = {'foo': 'bar', 'numbers': [1, 3, 4, 8]}
157160 >>> dst = {'baz': 'qux', 'numbers': [1, 4, 7]}
158161 >>> patch = make_patch(src, dst)
@@ -161,7 +164,7 @@ def make_patch(src, dst):
161164 True
162165 """
163166
164- return JsonPatch .from_diff (src , dst )
167+ return JsonPatch .from_diff (src , dst , pointer_cls = pointer_cls )
165168
166169
167170class JsonPatch (object ):
@@ -210,8 +213,9 @@ class JsonPatch(object):
210213 ... patch.apply(old) #doctest: +ELLIPSIS
211214 {...}
212215 """
213- def __init__ (self , patch ):
216+ def __init__ (self , patch , pointer_cls = JsonPointer ):
214217 self .patch = patch
218+ self .pointer_cls = pointer_cls
215219
216220 self .operations = {
217221 'remove' : RemoveOperation ,
@@ -246,19 +250,22 @@ def __ne__(self, other):
246250 return not (self == other )
247251
248252 @classmethod
249- def from_string (cls , patch_str ):
253+ def from_string (cls , patch_str , pointer_cls = JsonPointer ):
250254 """Creates JsonPatch instance from string source.
251255
252256 :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]
254261
255262 :return: :class:`JsonPatch` instance.
256263 """
257264 patch = _jsonloads (patch_str )
258- return cls (patch )
265+ return cls (patch , pointer_cls = pointer_cls )
259266
260267 @classmethod
261- def from_diff (cls , src , dst , optimization = True ):
268+ def from_diff (cls , src , dst , optimization = True , pointer_cls = JsonPointer ):
262269 """Creates JsonPatch instance based on comparison of two document
263270 objects. Json patch would be created for `src` argument against `dst`
264271 one.
@@ -269,6 +276,9 @@ def from_diff(cls, src, dst, optimization=True):
269276 :param dst: Data source document object.
270277 :type dst: dict
271278
279+ :param pointer_cls: JSON pointer (sub)class.
280+ :type pointer_cls: Type[JsonPointer]
281+
272282 :return: :class:`JsonPatch` instance.
273283
274284 >>> src = {'foo': 'bar', 'numbers': [1, 3, 4, 8]}
@@ -279,10 +289,10 @@ def from_diff(cls, src, dst, optimization=True):
279289 True
280290 """
281291
282- builder = DiffBuilder ()
292+ builder = DiffBuilder (pointer_cls = pointer_cls )
283293 builder ._compare_values ('' , None , src , dst )
284294 ops = list (builder .execute ())
285- return cls (ops )
295+ return cls (ops , pointer_cls = pointer_cls )
286296
287297 def to_string (self ):
288298 """Returns patch set as JSON string."""
@@ -326,24 +336,25 @@ def _get_operation(self, operation):
326336 raise InvalidJsonPatch ("Unknown operation {0!r}" .format (op ))
327337
328338 cls = self .operations [op ]
329- return cls (operation )
339+ return cls (operation , pointer_cls = self . pointer_cls )
330340
331341
332342class PatchOperation (object ):
333343 """A single operation inside a JSON Patch."""
334344
335- def __init__ (self , operation ):
345+ def __init__ (self , operation , pointer_cls = JsonPointer ):
346+ self .pointer_cls = pointer_cls
336347
337348 if not operation .__contains__ ('path' ):
338349 raise InvalidJsonPatch ("Operation must have a 'path' member" )
339350
340- if isinstance (operation ['path' ], JsonPointer ):
351+ if isinstance (operation ['path' ], self . pointer_cls ):
341352 self .location = operation ['path' ].path
342353 self .pointer = operation ['path' ]
343354 else :
344355 self .location = operation ['path' ]
345356 try :
346- self .pointer = JsonPointer (self .location )
357+ self .pointer = self . pointer_cls (self .location )
347358 except TypeError as ex :
348359 raise InvalidJsonPatch ("Invalid 'path'" )
349360
@@ -511,10 +522,10 @@ class MoveOperation(PatchOperation):
511522
512523 def apply (self , obj ):
513524 try :
514- if isinstance (self .operation ['from' ], JsonPointer ):
525+ if isinstance (self .operation ['from' ], self . pointer_cls ):
515526 from_ptr = self .operation ['from' ]
516527 else :
517- from_ptr = JsonPointer (self .operation ['from' ])
528+ from_ptr = self . pointer_cls (self .operation ['from' ])
518529 except KeyError as ex :
519530 raise InvalidJsonPatch (
520531 "The operation does not contain a 'from' member" )
@@ -536,32 +547,32 @@ def apply(self, obj):
536547 obj = RemoveOperation ({
537548 'op' : 'remove' ,
538549 'path' : self .operation ['from' ]
539- }).apply (obj )
550+ }, pointer_cls = self . pointer_cls ).apply (obj )
540551
541552 obj = AddOperation ({
542553 'op' : 'add' ,
543554 'path' : self .location ,
544555 'value' : value
545- }).apply (obj )
556+ }, pointer_cls = self . pointer_cls ).apply (obj )
546557
547558 return obj
548559
549560 @property
550561 def from_path (self ):
551- from_ptr = JsonPointer (self .operation ['from' ])
562+ from_ptr = self . pointer_cls (self .operation ['from' ])
552563 return '/' .join (from_ptr .parts [:- 1 ])
553564
554565 @property
555566 def from_key (self ):
556- from_ptr = JsonPointer (self .operation ['from' ])
567+ from_ptr = self . pointer_cls (self .operation ['from' ])
557568 try :
558569 return int (from_ptr .parts [- 1 ])
559570 except TypeError :
560571 return from_ptr .parts [- 1 ]
561572
562573 @from_key .setter
563574 def from_key (self , value ):
564- from_ptr = JsonPointer (self .operation ['from' ])
575+ from_ptr = self . pointer_cls (self .operation ['from' ])
565576 from_ptr .parts [- 1 ] = str (value )
566577 self .operation ['from' ] = from_ptr .path
567578
@@ -624,7 +635,7 @@ class CopyOperation(PatchOperation):
624635
625636 def apply (self , obj ):
626637 try :
627- from_ptr = JsonPointer (self .operation ['from' ])
638+ from_ptr = self . pointer_cls (self .operation ['from' ])
628639 except KeyError as ex :
629640 raise InvalidJsonPatch (
630641 "The operation does not contain a 'from' member" )
@@ -639,14 +650,15 @@ def apply(self, obj):
639650 'op' : 'add' ,
640651 'path' : self .location ,
641652 'value' : value
642- }).apply (obj )
653+ }, pointer_cls = self . pointer_cls ).apply (obj )
643654
644655 return obj
645656
646657
647658class DiffBuilder (object ):
648659
649- def __init__ (self ):
660+ def __init__ (self , pointer_cls = JsonPointer ):
661+ self .pointer_cls = pointer_cls
650662 self .index_storage = [{}, {}]
651663 self .index_storage2 = [[], []]
652664 self .__root = root = []
@@ -715,7 +727,7 @@ def execute(self):
715727 'op' : 'replace' ,
716728 'path' : op_second .location ,
717729 'value' : op_second .operation ['value' ],
718- }).operation
730+ }, pointer_cls = self . pointer_cls ).operation
719731 curr = curr [1 ][1 ]
720732 continue
721733
@@ -736,22 +748,22 @@ def _item_added(self, path, key, item):
736748 'op' : 'move' ,
737749 'from' : op .location ,
738750 'path' : _path_join (path , key ),
739- })
751+ }, pointer_cls = self . pointer_cls )
740752 self .insert (new_op )
741753 else :
742754 new_op = AddOperation ({
743755 'op' : 'add' ,
744756 'path' : _path_join (path , key ),
745757 'value' : item ,
746- })
758+ }, pointer_cls = self . pointer_cls )
747759 new_index = self .insert (new_op )
748760 self .store_index (item , new_index , _ST_ADD )
749761
750762 def _item_removed (self , path , key , item ):
751763 new_op = RemoveOperation ({
752764 'op' : 'remove' ,
753765 'path' : _path_join (path , key ),
754- })
766+ }, pointer_cls = self . pointer_cls )
755767 index = self .take_index (item , _ST_ADD )
756768 new_index = self .insert (new_op )
757769 if index is not None :
@@ -766,7 +778,7 @@ def _item_removed(self, path, key, item):
766778 'op' : 'move' ,
767779 'from' : new_op .location ,
768780 'path' : op .location ,
769- })
781+ }, pointer_cls = self . pointer_cls )
770782 new_index [2 ] = new_op
771783
772784 else :
@@ -780,7 +792,7 @@ def _item_replaced(self, path, key, item):
780792 'op' : 'replace' ,
781793 'path' : _path_join (path , key ),
782794 'value' : item ,
783- }))
795+ }, pointer_cls = self . pointer_cls ))
784796
785797 def _compare_dicts (self , path , src , dst ):
786798 src_keys = set (src .keys ())
0 commit comments