7474class JsonPatchException (Exception ):
7575 """Base Json Patch exception"""
7676
77+ def __init__ (self , op = None ):
78+ """
79+ Initialize a new instance of a JsonPatchException
80+ :param op: The operation that failed. Attach to exception if you
81+ desire to catch and modify the original patch operations.
82+ :type op: Type[PatchOperation]
83+ """
84+ self .op = op
85+
7786
7887class InvalidJsonPatch (JsonPatchException ):
7988 """ Raised if an invalid JSON Patch is created """
@@ -238,7 +247,7 @@ def apply(self, obj):
238247 del subobj [part ]
239248 except (KeyError , IndexError ) as ex :
240249 msg = "can't remove a non-existent object '{0}'" .format (part )
241- raise JsonPatchConflict (msg )
250+ raise JsonPatchConflict (msg , op = self )
242251
243252 return obj
244253
@@ -267,7 +276,7 @@ def apply(self, obj):
267276 value = self .operation ["value" ]
268277 except KeyError as ex :
269278 raise InvalidJsonPatch (
270- "The operation does not contain a 'value' member" )
279+ "The operation does not contain a 'value' member" , op = self )
271280
272281 subobj , part = self .pointer .to_last (obj )
273282
@@ -276,7 +285,7 @@ def apply(self, obj):
276285 subobj .append (value ) # pylint: disable=E1103
277286
278287 elif part > len (subobj ) or part < 0 :
279- raise JsonPatchConflict ("can't insert outside of list" )
288+ raise JsonPatchConflict ("can't insert outside of list" , op = self )
280289
281290 else :
282291 subobj .insert (part , value ) # pylint: disable=E1103
@@ -291,7 +300,7 @@ def apply(self, obj):
291300 if part is None :
292301 raise TypeError ("invalid document type {0}" .format (type (subobj )))
293302 else :
294- raise JsonPatchConflict ("unable to fully resolve json pointer {0}, part {1}" .format (self .location , part ))
303+ raise JsonPatchConflict ("unable to fully resolve json pointer {0}, part {1}" .format (self .location , part ), op = self )
295304 return obj
296305
297306 def _on_undo_remove (self , path , key ):
@@ -319,29 +328,29 @@ def apply(self, obj):
319328 value = self .operation ["value" ]
320329 except KeyError as ex :
321330 raise InvalidJsonPatch (
322- "The operation does not contain a 'value' member" )
331+ "The operation does not contain a 'value' member" , op = self )
323332
324333 subobj , part = self .pointer .to_last (obj )
325334
326335 if part is None :
327336 return value
328337
329338 if part == "-" :
330- raise InvalidJsonPatch ("'path' with '-' can't be applied to 'replace' operation" )
339+ raise InvalidJsonPatch ("'path' with '-' can't be applied to 'replace' operation" , op = self )
331340
332341 if isinstance (subobj , MutableSequence ):
333342 if part >= len (subobj ) or part < 0 :
334- raise JsonPatchConflict ("can't replace outside of list" )
343+ raise JsonPatchConflict ("can't replace outside of list" , op = self )
335344
336345 elif isinstance (subobj , MutableMapping ):
337346 if part not in subobj :
338347 msg = "can't replace a non-existent object '{0}'" .format (part )
339- raise JsonPatchConflict (msg )
348+ raise JsonPatchConflict (msg , op = self )
340349 else :
341350 if part is None :
342351 raise TypeError ("invalid document type {0}" .format (type (subobj )))
343352 else :
344- raise JsonPatchConflict ("unable to fully resolve json pointer {0}, part {1}" .format (self .location , part ))
353+ raise JsonPatchConflict ("unable to fully resolve json pointer {0}, part {1}" .format (self .location , part ), op = self )
345354
346355 subobj [part ] = value
347356 return obj
@@ -364,21 +373,21 @@ def apply(self, obj):
364373 from_ptr = self .pointer_cls (self .operation ['from' ])
365374 except KeyError as ex :
366375 raise InvalidJsonPatch (
367- "The operation does not contain a 'from' member" )
376+ "The operation does not contain a 'from' member" , op = self )
368377
369378 subobj , part = from_ptr .to_last (obj )
370379 try :
371380 value = subobj [part ]
372381 except (KeyError , IndexError ) as ex :
373- raise JsonPatchConflict (str (ex ))
382+ raise JsonPatchConflict (str (ex ), op = self )
374383
375384 # If source and target are equal, this is a no-op
376385 if self .pointer == from_ptr :
377386 return obj
378387
379388 if isinstance (subobj , MutableMapping ) and \
380389 self .pointer .contains (from_ptr ):
381- raise JsonPatchConflict ('Cannot move values into their own children' )
390+ raise JsonPatchConflict ('Cannot move values into their own children' , op = self )
382391
383392 obj = RemoveOperation ({
384393 'op' : 'remove' ,
@@ -450,18 +459,18 @@ def apply(self, obj):
450459 else :
451460 val = self .pointer .walk (subobj , part )
452461 except JsonPointerException as ex :
453- raise JsonPatchTestFailed (str (ex ))
462+ raise JsonPatchTestFailed (str (ex ), op = self )
454463
455464 try :
456465 value = self .operation ['value' ]
457466 except KeyError as ex :
458467 raise InvalidJsonPatch (
459- "The operation does not contain a 'value' member" )
468+ "The operation does not contain a 'value' member" , op = self )
460469
461470 if val != value :
462471 msg = '{0} ({1}) is not equal to tested value {2} ({3})'
463472 raise JsonPatchTestFailed (msg .format (val , type (val ),
464- value , type (value )))
473+ value , type (value )), op = self )
465474
466475 return obj
467476
@@ -474,13 +483,13 @@ def apply(self, obj):
474483 from_ptr = self .pointer_cls (self .operation ['from' ])
475484 except KeyError as ex :
476485 raise InvalidJsonPatch (
477- "The operation does not contain a 'from' member" )
486+ "The operation does not contain a 'from' member" , op = self )
478487
479488 subobj , part = from_ptr .to_last (obj )
480489 try :
481490 value = copy .deepcopy (subobj [part ])
482491 except (KeyError , IndexError ) as ex :
483- raise JsonPatchConflict (str (ex ))
492+ raise JsonPatchConflict (str (ex ), op = self )
484493
485494 obj = AddOperation ({
486495 'op' : 'add' ,
@@ -672,15 +681,15 @@ def apply(self, obj, in_place=False):
672681
673682 def _get_operation (self , operation ):
674683 if 'op' not in operation :
675- raise InvalidJsonPatch ("Operation does not contain 'op' member" )
684+ raise InvalidJsonPatch ("Operation does not contain 'op' member" , op = operation )
676685
677686 op = operation ['op' ]
678687
679688 if not isinstance (op , basestring ):
680- raise InvalidJsonPatch ("Operation must be a string" )
689+ raise InvalidJsonPatch ("Operation must be a string" , op = operation )
681690
682691 if op not in self .operations :
683- raise InvalidJsonPatch ("Unknown operation {0!r}" .format (op ))
692+ raise InvalidJsonPatch ("Unknown operation {0!r}" .format (op ), op = operation )
684693
685694 cls = self .operations [op ]
686695 return cls (operation , pointer_cls = self .pointer_cls )
0 commit comments