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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jsonpatch
3
- Version: 1.35
3
+ Version: 1.37
4
4
  Summary: Apply JSON-Patches (RFC 6902)
5
5
  Home-page: https://github.com/stefankoegl/python-json-patch
6
6
  Author: Stefan Kögl
@@ -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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (84.0.0)
2
+ Generator: setuptools (84.2.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
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.35'
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.pointer_cls(self.operation['from'])
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.pointer_cls(self.operation['from'])
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.pointer_cls(self.operation['from'])
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 self.patch:
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
- json.dump(result, fp, indent=args.indent, ensure_ascii=not(args.preserve_unicode))
112
- fp.write('\n')
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.rename(pathname, args.ORIGINAL.name)
140
+ os.replace(pathname, args.ORIGINAL.name)
130
141
 
131
142
  except OSError:
132
- # In the event we could not actually do the atomic
133
- # replace, unlink the original to move it out of the
134
- # way and finally move the temporary file into place.
135
-
136
- os.unlink(args.ORIGINAL.name)
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
@@ -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,,