@@ -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.
@@ -119,6 +119,9 @@ def apply_patch(doc, patch, in_place=False):
119119 By default patch will be applied to document copy.
120120 :type in_place: bool
121121
122+ :param pointer_cls: JSON pointer class to use.
123+ :type pointer_cls: Type[JsonPointer]
124+
122125 :return: Patched document object.
123126 :rtype: dict
124127
@@ -137,13 +140,13 @@ def apply_patch(doc, patch, in_place=False):
137140 """
138141
139142 if isinstance (patch , basestring ):
140- patch = JsonPatch .from_string (patch )
143+ patch = JsonPatch .from_string (patch , pointer_cls = pointer_cls )
141144 else :
142- patch = JsonPatch (patch )
145+ patch = JsonPatch (patch , pointer_cls = pointer_cls )
143146 return patch .apply (doc , in_place )
144147
145148
146- def make_patch (src , dst ):
149+ def make_patch (src , dst , pointer_cls = JsonPointer ):
147150 """Generates patch by comparing two document objects. Actually is
148151 a proxy to :meth:`JsonPatch.from_diff` method.
149152
@@ -153,6 +156,9 @@ def make_patch(src, dst):
153156 :param dst: Data source document object.
154157 :type dst: dict
155158
159+ :param pointer_cls: JSON pointer class to use.
160+ :type pointer_cls: Type[JsonPointer]
161+
156162 >>> src = {'foo': 'bar', 'numbers': [1, 3, 4, 8]}
157163 >>> dst = {'baz': 'qux', 'numbers': [1, 4, 7]}
158164 >>> patch = make_patch(src, dst)
@@ -161,7 +167,7 @@ def make_patch(src, dst):
161167 True
162168 """
163169
164- return JsonPatch .from_diff (src , dst )
170+ return JsonPatch .from_diff (src , dst , pointer_cls = pointer_cls )
165171
166172
167173class JsonPatch (object ):
@@ -213,8 +219,9 @@ class JsonPatch(object):
213219 ... patch.apply(old) #doctest: +ELLIPSIS
214220 {...}
215221 """
216- def __init__ (self , patch ):
222+ def __init__ (self , patch , pointer_cls = JsonPointer ):
217223 self .patch = patch
224+ self .pointer_cls = pointer_cls
218225
219226 self .operations = {
220227 'remove' : RemoveOperation ,
@@ -256,23 +263,30 @@ def __ne__(self, other):
256263 return not (self == other )
257264
258265 @classmethod
259- def from_string (cls , patch_str , loads = None ):
266+ def from_string (cls , patch_str , loads = None , pointer_cls = JsonPointer ):
260267 """Creates JsonPatch instance from string source.
261268
262269 :param patch_str: JSON patch as raw string.
263270 :type patch_str: str
271+
264272 :param loads: A function of one argument that loads a serialized
265273 JSON string.
266274 :type loads: function
267275
276+ :param pointer_cls: JSON pointer class to use.
277+ :type pointer_cls: Type[JsonPointer]
278+
268279 :return: :class:`JsonPatch` instance.
269280 """
270281 json_loader = loads or cls .json_loader
271282 patch = json_loader (patch_str )
272- return cls (patch )
283+ return cls (patch , pointer_cls = pointer_cls )
273284
274285 @classmethod
275- def from_diff (cls , src , dst , optimization = True , dumps = None ):
286+ def from_diff (
287+ cls , src , dst , optimization = True , dumps = None ,
288+ pointer_cls = JsonPointer ,
289+ ):
276290 """Creates JsonPatch instance based on comparison of two document
277291 objects. Json patch would be created for `src` argument against `dst`
278292 one.
@@ -287,6 +301,9 @@ def from_diff(cls, src, dst, optimization=True, dumps=None):
287301 JSON string.
288302 :type dumps: function
289303
304+ :param pointer_cls: JSON pointer class to use.
305+ :type pointer_cls: Type[JsonPointer]
306+
290307 :return: :class:`JsonPatch` instance.
291308
292309 >>> src = {'foo': 'bar', 'numbers': [1, 3, 4, 8]}
@@ -297,10 +314,10 @@ def from_diff(cls, src, dst, optimization=True, dumps=None):
297314 True
298315 """
299316 json_dumper = dumps or cls .json_dumper
300- builder = DiffBuilder (json_dumper )
317+ builder = DiffBuilder (json_dumper , pointer_cls = pointer_cls )
301318 builder ._compare_values ('' , None , src , dst )
302319 ops = list (builder .execute ())
303- return cls (ops )
320+ return cls (ops , pointer_cls = pointer_cls )
304321
305322 def to_string (self , dumps = None ):
306323 """Returns patch set as JSON string."""
@@ -345,24 +362,25 @@ def _get_operation(self, operation):
345362 raise InvalidJsonPatch ("Unknown operation {0!r}" .format (op ))
346363
347364 cls = self .operations [op ]
348- return cls (operation )
365+ return cls (operation , pointer_cls = self . pointer_cls )
349366
350367
351368class PatchOperation (object ):
352369 """A single operation inside a JSON Patch."""
353370
354- def __init__ (self , operation ):
371+ def __init__ (self , operation , pointer_cls = JsonPointer ):
372+ self .pointer_cls = pointer_cls
355373
356374 if not operation .__contains__ ('path' ):
357375 raise InvalidJsonPatch ("Operation must have a 'path' member" )
358376
359- if isinstance (operation ['path' ], JsonPointer ):
377+ if isinstance (operation ['path' ], self . pointer_cls ):
360378 self .location = operation ['path' ].path
361379 self .pointer = operation ['path' ]
362380 else :
363381 self .location = operation ['path' ]
364382 try :
365- self .pointer = JsonPointer (self .location )
383+ self .pointer = self . pointer_cls (self .location )
366384 except TypeError as ex :
367385 raise InvalidJsonPatch ("Invalid 'path'" )
368386
@@ -530,10 +548,10 @@ class MoveOperation(PatchOperation):
530548
531549 def apply (self , obj ):
532550 try :
533- if isinstance (self .operation ['from' ], JsonPointer ):
551+ if isinstance (self .operation ['from' ], self . pointer_cls ):
534552 from_ptr = self .operation ['from' ]
535553 else :
536- from_ptr = JsonPointer (self .operation ['from' ])
554+ from_ptr = self . pointer_cls (self .operation ['from' ])
537555 except KeyError as ex :
538556 raise InvalidJsonPatch (
539557 "The operation does not contain a 'from' member" )
@@ -555,32 +573,32 @@ def apply(self, obj):
555573 obj = RemoveOperation ({
556574 'op' : 'remove' ,
557575 'path' : self .operation ['from' ]
558- }).apply (obj )
576+ }, pointer_cls = self . pointer_cls ).apply (obj )
559577
560578 obj = AddOperation ({
561579 'op' : 'add' ,
562580 'path' : self .location ,
563581 'value' : value
564- }).apply (obj )
582+ }, pointer_cls = self . pointer_cls ).apply (obj )
565583
566584 return obj
567585
568586 @property
569587 def from_path (self ):
570- from_ptr = JsonPointer (self .operation ['from' ])
588+ from_ptr = self . pointer_cls (self .operation ['from' ])
571589 return '/' .join (from_ptr .parts [:- 1 ])
572590
573591 @property
574592 def from_key (self ):
575- from_ptr = JsonPointer (self .operation ['from' ])
593+ from_ptr = self . pointer_cls (self .operation ['from' ])
576594 try :
577595 return int (from_ptr .parts [- 1 ])
578596 except TypeError :
579597 return from_ptr .parts [- 1 ]
580598
581599 @from_key .setter
582600 def from_key (self , value ):
583- from_ptr = JsonPointer (self .operation ['from' ])
601+ from_ptr = self . pointer_cls (self .operation ['from' ])
584602 from_ptr .parts [- 1 ] = str (value )
585603 self .operation ['from' ] = from_ptr .path
586604
@@ -643,7 +661,7 @@ class CopyOperation(PatchOperation):
643661
644662 def apply (self , obj ):
645663 try :
646- from_ptr = JsonPointer (self .operation ['from' ])
664+ from_ptr = self . pointer_cls (self .operation ['from' ])
647665 except KeyError as ex :
648666 raise InvalidJsonPatch (
649667 "The operation does not contain a 'from' member" )
@@ -658,15 +676,16 @@ def apply(self, obj):
658676 'op' : 'add' ,
659677 'path' : self .location ,
660678 'value' : value
661- }).apply (obj )
679+ }, pointer_cls = self . pointer_cls ).apply (obj )
662680
663681 return obj
664682
665683
666684class DiffBuilder (object ):
667685
668- def __init__ (self , dumps = json .dumps ):
686+ def __init__ (self , dumps = json .dumps , pointer_cls = JsonPointer ):
669687 self .dumps = dumps
688+ self .pointer_cls = pointer_cls
670689 self .index_storage = [{}, {}]
671690 self .index_storage2 = [[], []]
672691 self .__root = root = []
@@ -735,7 +754,7 @@ def execute(self):
735754 'op' : 'replace' ,
736755 'path' : op_second .location ,
737756 'value' : op_second .operation ['value' ],
738- }).operation
757+ }, pointer_cls = self . pointer_cls ).operation
739758 curr = curr [1 ][1 ]
740759 continue
741760
@@ -756,22 +775,22 @@ def _item_added(self, path, key, item):
756775 'op' : 'move' ,
757776 'from' : op .location ,
758777 'path' : _path_join (path , key ),
759- })
778+ }, pointer_cls = self . pointer_cls )
760779 self .insert (new_op )
761780 else :
762781 new_op = AddOperation ({
763782 'op' : 'add' ,
764783 'path' : _path_join (path , key ),
765784 'value' : item ,
766- })
785+ }, pointer_cls = self . pointer_cls )
767786 new_index = self .insert (new_op )
768787 self .store_index (item , new_index , _ST_ADD )
769788
770789 def _item_removed (self , path , key , item ):
771790 new_op = RemoveOperation ({
772791 'op' : 'remove' ,
773792 'path' : _path_join (path , key ),
774- })
793+ }, pointer_cls = self . pointer_cls )
775794 index = self .take_index (item , _ST_ADD )
776795 new_index = self .insert (new_op )
777796 if index is not None :
@@ -786,7 +805,7 @@ def _item_removed(self, path, key, item):
786805 'op' : 'move' ,
787806 'from' : new_op .location ,
788807 'path' : op .location ,
789- })
808+ }, pointer_cls = self . pointer_cls )
790809 new_index [2 ] = new_op
791810
792811 else :
@@ -800,7 +819,7 @@ def _item_replaced(self, path, key, item):
800819 'op' : 'replace' ,
801820 'path' : _path_join (path , key ),
802821 'value' : item ,
803- }))
822+ }, pointer_cls = self . pointer_cls ))
804823
805824 def _compare_dicts (self , path , src , dst ):
806825 src_keys = set (src .keys ())
0 commit comments