74
74
class JsonPatchException (Exception ):
75
75
"""Base Json Patch exception"""
76
76
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
+
77
86
78
87
class InvalidJsonPatch (JsonPatchException ):
79
88
""" Raised if an invalid JSON Patch is created """
@@ -238,7 +247,7 @@ def apply(self, obj):
238
247
del subobj [part ]
239
248
except (KeyError , IndexError ) as ex :
240
249
msg = "can't remove a non-existent object '{0}'" .format (part )
241
- raise JsonPatchConflict (msg )
250
+ raise JsonPatchConflict (msg , op = self )
242
251
243
252
return obj
244
253
@@ -267,7 +276,7 @@ def apply(self, obj):
267
276
value = self .operation ["value" ]
268
277
except KeyError as ex :
269
278
raise InvalidJsonPatch (
270
- "The operation does not contain a 'value' member" )
279
+ "The operation does not contain a 'value' member" , op = self )
271
280
272
281
subobj , part = self .pointer .to_last (obj )
273
282
@@ -276,7 +285,7 @@ def apply(self, obj):
276
285
subobj .append (value ) # pylint: disable=E1103
277
286
278
287
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 )
280
289
281
290
else :
282
291
subobj .insert (part , value ) # pylint: disable=E1103
@@ -291,7 +300,7 @@ def apply(self, obj):
291
300
if part is None :
292
301
raise TypeError ("invalid document type {0}" .format (type (subobj )))
293
302
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 )
295
304
return obj
296
305
297
306
def _on_undo_remove (self , path , key ):
@@ -319,29 +328,29 @@ def apply(self, obj):
319
328
value = self .operation ["value" ]
320
329
except KeyError as ex :
321
330
raise InvalidJsonPatch (
322
- "The operation does not contain a 'value' member" )
331
+ "The operation does not contain a 'value' member" , op = self )
323
332
324
333
subobj , part = self .pointer .to_last (obj )
325
334
326
335
if part is None :
327
336
return value
328
337
329
338
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 )
331
340
332
341
if isinstance (subobj , MutableSequence ):
333
342
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 )
335
344
336
345
elif isinstance (subobj , MutableMapping ):
337
346
if part not in subobj :
338
347
msg = "can't replace a non-existent object '{0}'" .format (part )
339
- raise JsonPatchConflict (msg )
348
+ raise JsonPatchConflict (msg , op = self )
340
349
else :
341
350
if part is None :
342
351
raise TypeError ("invalid document type {0}" .format (type (subobj )))
343
352
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 )
345
354
346
355
subobj [part ] = value
347
356
return obj
@@ -364,21 +373,21 @@ def apply(self, obj):
364
373
from_ptr = self .pointer_cls (self .operation ['from' ])
365
374
except KeyError as ex :
366
375
raise InvalidJsonPatch (
367
- "The operation does not contain a 'from' member" )
376
+ "The operation does not contain a 'from' member" , op = self )
368
377
369
378
subobj , part = from_ptr .to_last (obj )
370
379
try :
371
380
value = subobj [part ]
372
381
except (KeyError , IndexError ) as ex :
373
- raise JsonPatchConflict (str (ex ))
382
+ raise JsonPatchConflict (str (ex ), op = self )
374
383
375
384
# If source and target are equal, this is a no-op
376
385
if self .pointer == from_ptr :
377
386
return obj
378
387
379
388
if isinstance (subobj , MutableMapping ) and \
380
389
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 )
382
391
383
392
obj = RemoveOperation ({
384
393
'op' : 'remove' ,
@@ -450,18 +459,18 @@ def apply(self, obj):
450
459
else :
451
460
val = self .pointer .walk (subobj , part )
452
461
except JsonPointerException as ex :
453
- raise JsonPatchTestFailed (str (ex ))
462
+ raise JsonPatchTestFailed (str (ex ), op = self )
454
463
455
464
try :
456
465
value = self .operation ['value' ]
457
466
except KeyError as ex :
458
467
raise InvalidJsonPatch (
459
- "The operation does not contain a 'value' member" )
468
+ "The operation does not contain a 'value' member" , op = self )
460
469
461
470
if val != value :
462
471
msg = '{0} ({1}) is not equal to tested value {2} ({3})'
463
472
raise JsonPatchTestFailed (msg .format (val , type (val ),
464
- value , type (value )))
473
+ value , type (value )), op = self )
465
474
466
475
return obj
467
476
@@ -474,13 +483,13 @@ def apply(self, obj):
474
483
from_ptr = self .pointer_cls (self .operation ['from' ])
475
484
except KeyError as ex :
476
485
raise InvalidJsonPatch (
477
- "The operation does not contain a 'from' member" )
486
+ "The operation does not contain a 'from' member" , op = self )
478
487
479
488
subobj , part = from_ptr .to_last (obj )
480
489
try :
481
490
value = copy .deepcopy (subobj [part ])
482
491
except (KeyError , IndexError ) as ex :
483
- raise JsonPatchConflict (str (ex ))
492
+ raise JsonPatchConflict (str (ex ), op = self )
484
493
485
494
obj = AddOperation ({
486
495
'op' : 'add' ,
@@ -672,15 +681,15 @@ def apply(self, obj, in_place=False):
672
681
673
682
def _get_operation (self , operation ):
674
683
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 )
676
685
677
686
op = operation ['op' ]
678
687
679
688
if not isinstance (op , basestring ):
680
- raise InvalidJsonPatch ("Operation must be a string" )
689
+ raise InvalidJsonPatch ("Operation must be a string" , op = operation )
681
690
682
691
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 )
684
693
685
694
cls = self .operations [op ]
686
695
return cls (operation , pointer_cls = self .pointer_cls )
0 commit comments