jsonpatch 1.35__py3-none-any.whl → 1.37__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {jsonpatch-1.35.dist-info → jsonpatch-1.37.dist-info}/METADATA +1 -1
- jsonpatch-1.37.dist-info/RECORD +9 -0
- {jsonpatch-1.35.dist-info → jsonpatch-1.37.dist-info}/WHEEL +1 -1
- jsonpatch.py +25 -7
- jsonpatch_cli.py +30 -20
- jsonpatch-1.35.dist-info/RECORD +0 -9
- {jsonpatch-1.35.dist-info → jsonpatch-1.37.dist-info}/entry_points.txt +0 -0
- {jsonpatch-1.35.dist-info → jsonpatch-1.37.dist-info}/licenses/AUTHORS +0 -0
- {jsonpatch-1.35.dist-info → jsonpatch-1.37.dist-info}/licenses/LICENSE +0 -0
- {jsonpatch-1.35.dist-info → jsonpatch-1.37.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
jsonpatch.py,sha256=6fX9MEBkMv4cIyw_iVt5b2VkDXMSG73MjDTgp4FMhRg,43496
|
|
2
|
+
jsonpatch_cli.py,sha256=Gi1DOHBOYcny9Fedd7893r1XdLn6Sq-Rycgncn1hObo,5617
|
|
3
|
+
jsonpatch-1.37.dist-info/licenses/AUTHORS,sha256=hOtEnBGbfDegKjzMDEl5vuVJyczbI2PlYE2ho4LjGNQ,140
|
|
4
|
+
jsonpatch-1.37.dist-info/licenses/LICENSE,sha256=Q5PrZzP6HjZ_QXabOC9PG-e_Da6x4kPtkrP12Lr9I28,1481
|
|
5
|
+
jsonpatch-1.37.dist-info/METADATA,sha256=oaKNZAeNG-Z59oQ07lI2ne1vvUJ8uo8iZEj4XDyeT9Q,3672
|
|
6
|
+
jsonpatch-1.37.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
7
|
+
jsonpatch-1.37.dist-info/entry_points.txt,sha256=aY9ormBVRZHHDaAeMcdqTBwZ-ax7GvBTSQ33I75xtZM,98
|
|
8
|
+
jsonpatch-1.37.dist-info/top_level.txt,sha256=efUF341HUk8WcQKnFt8ZLKEKNrm1kFT76Flr38Fjno0,24
|
|
9
|
+
jsonpatch-1.37.dist-info/RECORD,,
|
jsonpatch.py
CHANGED
|
@@ -54,7 +54,7 @@ _EXACT_MATCH_LIMIT = 500 ** 2
|
|
|
54
54
|
|
|
55
55
|
# Will be parsed by setup.py to determine package metadata
|
|
56
56
|
__author__ = 'Stefan Kögl <stefan@skoegl.net>'
|
|
57
|
-
__version__ = '1.
|
|
57
|
+
__version__ = '1.37'
|
|
58
58
|
__website__ = 'https://github.com/stefankoegl/python-json-patch'
|
|
59
59
|
__license__ = 'BSD-3-Clause'
|
|
60
60
|
|
|
@@ -384,7 +384,7 @@ class MoveOperation(PatchOperation):
|
|
|
384
384
|
|
|
385
385
|
@property
|
|
386
386
|
def from_path(self):
|
|
387
|
-
from_ptr = self.
|
|
387
|
+
from_ptr = self._from_pointer()
|
|
388
388
|
return '/'.join(from_ptr.parts[:-1])
|
|
389
389
|
|
|
390
390
|
@property
|
|
@@ -396,14 +396,14 @@ class MoveOperation(PatchOperation):
|
|
|
396
396
|
self.set_from_part(-1, value)
|
|
397
397
|
|
|
398
398
|
def get_from_part(self, index):
|
|
399
|
-
from_ptr = self.
|
|
399
|
+
from_ptr = self._from_pointer()
|
|
400
400
|
try:
|
|
401
401
|
return int(from_ptr.parts[index])
|
|
402
402
|
except ValueError:
|
|
403
403
|
return from_ptr.parts[index]
|
|
404
404
|
|
|
405
405
|
def set_from_part(self, index, value):
|
|
406
|
-
from_ptr = self.
|
|
406
|
+
from_ptr = self._from_pointer()
|
|
407
407
|
from_ptr.parts[index] = str(value)
|
|
408
408
|
self.operation['from'] = from_ptr.path
|
|
409
409
|
|
|
@@ -518,11 +518,18 @@ class JsonPatch(object):
|
|
|
518
518
|
self.patch = patch
|
|
519
519
|
self.pointer_cls = pointer_cls
|
|
520
520
|
|
|
521
|
+
if isinstance(patch, (str, bytes, Mapping)):
|
|
522
|
+
raise InvalidJsonPatch("Document is expected to be sequence of operations")
|
|
523
|
+
try:
|
|
524
|
+
patch_iter = iter(patch)
|
|
525
|
+
except TypeError:
|
|
526
|
+
raise InvalidJsonPatch("Document is expected to be sequence of operations")
|
|
527
|
+
|
|
521
528
|
# Verify that the structure of the patch document
|
|
522
529
|
# is correct by retrieving each patch element.
|
|
523
530
|
# Much of the validation is done in the initializer
|
|
524
531
|
# though some is delayed until the patch is applied.
|
|
525
|
-
for op in
|
|
532
|
+
for op in patch_iter:
|
|
526
533
|
# We're only checking for strings in the following check
|
|
527
534
|
# for two reasons:
|
|
528
535
|
#
|
|
@@ -597,6 +604,10 @@ class JsonPatch(object):
|
|
|
597
604
|
:param dst: Data target document object.
|
|
598
605
|
:type dst: dict
|
|
599
606
|
|
|
607
|
+
:param optimization: Generate move operations for matching values.
|
|
608
|
+
Set to False to use only add, remove and replace.
|
|
609
|
+
:type optimization: bool
|
|
610
|
+
|
|
600
611
|
:param dumps: A function of one argument that produces a serialized
|
|
601
612
|
JSON string.
|
|
602
613
|
:type dumps: Callable
|
|
@@ -614,7 +625,8 @@ class JsonPatch(object):
|
|
|
614
625
|
True
|
|
615
626
|
"""
|
|
616
627
|
json_dumper = dumps or cls.json_dumper
|
|
617
|
-
builder = DiffBuilder(src, dst, json_dumper, pointer_cls=pointer_cls
|
|
628
|
+
builder = DiffBuilder(src, dst, json_dumper, pointer_cls=pointer_cls,
|
|
629
|
+
optimization=optimization)
|
|
618
630
|
builder._compare_values((), None, src, dst)
|
|
619
631
|
ops = list(builder.execute())
|
|
620
632
|
return cls(ops, pointer_cls=pointer_cls)
|
|
@@ -670,9 +682,11 @@ class JsonPatch(object):
|
|
|
670
682
|
|
|
671
683
|
class DiffBuilder(object):
|
|
672
684
|
|
|
673
|
-
def __init__(self, src_doc, dst_doc, dumps=json.dumps, pointer_cls=JsonPointer
|
|
685
|
+
def __init__(self, src_doc, dst_doc, dumps=json.dumps, pointer_cls=JsonPointer,
|
|
686
|
+
optimization=True):
|
|
674
687
|
self.dumps = dumps
|
|
675
688
|
self.pointer_cls = pointer_cls
|
|
689
|
+
self.optimization = optimization
|
|
676
690
|
self.index_storage = [{}, {}]
|
|
677
691
|
self.__root = root = []
|
|
678
692
|
self.src_doc = src_doc
|
|
@@ -693,10 +707,14 @@ class DiffBuilder(object):
|
|
|
693
707
|
return id(value)
|
|
694
708
|
|
|
695
709
|
def store_index(self, value, index, st):
|
|
710
|
+
if not self.optimization:
|
|
711
|
+
return
|
|
696
712
|
storage = self.index_storage[st]
|
|
697
713
|
storage.setdefault(self._move_key(value), []).append(index)
|
|
698
714
|
|
|
699
715
|
def take_index(self, value, st):
|
|
716
|
+
if not self.optimization:
|
|
717
|
+
return None
|
|
700
718
|
stored = self.index_storage[st].get(self._move_key(value))
|
|
701
719
|
if stored:
|
|
702
720
|
return stored.pop()
|
jsonpatch_cli.py
CHANGED
|
@@ -12,8 +12,8 @@ import argparse
|
|
|
12
12
|
|
|
13
13
|
jsondiff_parser = argparse.ArgumentParser(
|
|
14
14
|
prog='jsondiff', description='Diff two JSON files')
|
|
15
|
-
jsondiff_parser.add_argument('FILE1', type=argparse.FileType('r'))
|
|
16
|
-
jsondiff_parser.add_argument('FILE2', type=argparse.FileType('r'))
|
|
15
|
+
jsondiff_parser.add_argument('FILE1', type=argparse.FileType('r', encoding='utf-8'))
|
|
16
|
+
jsondiff_parser.add_argument('FILE2', type=argparse.FileType('r', encoding='utf-8'))
|
|
17
17
|
jsondiff_parser.add_argument('--indent', type=int, default=None,
|
|
18
18
|
help='Indent output by n spaces')
|
|
19
19
|
jsondiff_parser.add_argument('-u', '--preserve-unicode', action='store_true',
|
|
@@ -43,9 +43,9 @@ def diff_files():
|
|
|
43
43
|
jsonpatch_parser = argparse.ArgumentParser(
|
|
44
44
|
prog='jsonpatch',
|
|
45
45
|
description='Apply a JSON patch on a JSON file')
|
|
46
|
-
jsonpatch_parser.add_argument('ORIGINAL', type=argparse.FileType('r'),
|
|
46
|
+
jsonpatch_parser.add_argument('ORIGINAL', type=argparse.FileType('r', encoding='utf-8'),
|
|
47
47
|
help='Original file')
|
|
48
|
-
jsonpatch_parser.add_argument('PATCH', type=argparse.FileType('r'),
|
|
48
|
+
jsonpatch_parser.add_argument('PATCH', type=argparse.FileType('r', encoding='utf-8'),
|
|
49
49
|
nargs='?', default=sys.stdin,
|
|
50
50
|
help='Patch file (read from stdin if omitted)')
|
|
51
51
|
jsonpatch_parser.add_argument('--indent', type=int, default=None,
|
|
@@ -86,7 +86,7 @@ def patch_files():
|
|
|
86
86
|
# because atomic renames do not work across mount points.)
|
|
87
87
|
|
|
88
88
|
fd, pathname = tempfile.mkstemp(dir=dirname)
|
|
89
|
-
fp = os.fdopen(fd, 'w')
|
|
89
|
+
fp = os.fdopen(fd, 'w', encoding='utf-8')
|
|
90
90
|
atomic = True
|
|
91
91
|
|
|
92
92
|
except OSError:
|
|
@@ -96,7 +96,7 @@ def patch_files():
|
|
|
96
96
|
|
|
97
97
|
if args.backup:
|
|
98
98
|
os.rename(args.ORIGINAL.name, args.ORIGINAL.name + '.orig')
|
|
99
|
-
fp = open(args.ORIGINAL.name, 'w')
|
|
99
|
+
fp = open(args.ORIGINAL.name, 'w', encoding='utf-8')
|
|
100
100
|
atomic = False
|
|
101
101
|
|
|
102
102
|
else:
|
|
@@ -108,15 +108,26 @@ def patch_files():
|
|
|
108
108
|
# By this point we have some sort of file object we can write the
|
|
109
109
|
# modified JSON to.
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
try:
|
|
112
|
+
json.dump(result, fp, indent=args.indent, ensure_ascii=not(args.preserve_unicode))
|
|
113
|
+
fp.write('\n')
|
|
114
|
+
if args.in_place:
|
|
115
|
+
fp.close()
|
|
116
|
+
except BaseException:
|
|
117
|
+
if args.in_place:
|
|
118
|
+
# Cleanup must not replace the original output error.
|
|
119
|
+
try:
|
|
120
|
+
fp.close()
|
|
121
|
+
except OSError:
|
|
122
|
+
pass
|
|
123
|
+
if atomic:
|
|
124
|
+
try:
|
|
125
|
+
os.unlink(pathname)
|
|
126
|
+
except OSError:
|
|
127
|
+
pass
|
|
128
|
+
raise
|
|
113
129
|
|
|
114
130
|
if args.in_place:
|
|
115
|
-
# Close the new file. If we aren't replacing atomically, this
|
|
116
|
-
# is our last step, since everything else is already in place.
|
|
117
|
-
|
|
118
|
-
fp.close()
|
|
119
|
-
|
|
120
131
|
if atomic:
|
|
121
132
|
try:
|
|
122
133
|
# Complete the atomic replace by linking the original
|
|
@@ -126,12 +137,11 @@ def patch_files():
|
|
|
126
137
|
if args.backup:
|
|
127
138
|
os.link(args.ORIGINAL.name, args.ORIGINAL.name + '.orig')
|
|
128
139
|
os.chmod(pathname, os.stat(args.ORIGINAL.name).st_mode)
|
|
129
|
-
os.
|
|
140
|
+
os.replace(pathname, args.ORIGINAL.name)
|
|
130
141
|
|
|
131
142
|
except OSError:
|
|
132
|
-
#
|
|
133
|
-
# replace
|
|
134
|
-
#
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
os.rename(pathname, args.ORIGINAL.name)
|
|
143
|
+
# Preserve the original if backup, permissions, or replacement
|
|
144
|
+
# fails. replace() can overwrite an existing file on Windows
|
|
145
|
+
# without unlinking it first.
|
|
146
|
+
os.unlink(pathname)
|
|
147
|
+
raise
|
jsonpatch-1.35.dist-info/RECORD
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
jsonpatch.py,sha256=fO9Isq-oqu2Ua64PLMzuV3wCVIrx0SW7v9xB84W44rA,42817
|
|
2
|
-
jsonpatch_cli.py,sha256=HD5iqPJP__uTPKm50eg7xbTaTuQHL4Bt7MpgO-vlzaM,5304
|
|
3
|
-
jsonpatch-1.35.dist-info/licenses/AUTHORS,sha256=hOtEnBGbfDegKjzMDEl5vuVJyczbI2PlYE2ho4LjGNQ,140
|
|
4
|
-
jsonpatch-1.35.dist-info/licenses/LICENSE,sha256=Q5PrZzP6HjZ_QXabOC9PG-e_Da6x4kPtkrP12Lr9I28,1481
|
|
5
|
-
jsonpatch-1.35.dist-info/METADATA,sha256=v3G9IpDxUG83tcXWWPX4CQlfs4lMll0QGIw2i9qfDMM,3672
|
|
6
|
-
jsonpatch-1.35.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
7
|
-
jsonpatch-1.35.dist-info/entry_points.txt,sha256=aY9ormBVRZHHDaAeMcdqTBwZ-ax7GvBTSQ33I75xtZM,98
|
|
8
|
-
jsonpatch-1.35.dist-info/top_level.txt,sha256=efUF341HUk8WcQKnFt8ZLKEKNrm1kFT76Flr38Fjno0,24
|
|
9
|
-
jsonpatch-1.35.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|