1
2 """Provides classes for the JSONPointer definition in
3 accordance to RFC6901 and relative pointers draft-1/2018.
4 """
5 from __future__ import absolute_import
6 from __future__ import print_function
7
8 import re
9 import copy
10
11 from jsondata import V3K, ISSTR, JSONPointerError, JSONPointerTypeError, \
12 C_SHALLOW, C_DEEP, \
13 M_FIRST, M_LAST, \
14 rtypes2num, RT_LST, RT_JSONPOINTER, \
15 verify2num, V_FINAL, V_STEPS
16
17
18 __author__ = 'Arno-Can Uestuensoez'
19 __maintainer__ = 'Arno-Can Uestuensoez'
20 __license__ = "Artistic-License-2.0 + Forced-Fairplay-Constraints"
21 __copyright__ = "Copyright (C) 2015-2016 Arno-Can Uestuensoez" \
22 " @Ingenieurbuero Arno-Can Uestuensoez"
23 __version__ = '0.2.21'
24 __uuid__ = '63b597d6-4ada-4880-9f99-f5e0961351fb'
25
26 if V3K:
27 unicode = str
28 from urllib.parse import unquote as url_unquote
29 else:
30 from urllib import unquote as url_unquote
31
32
33 _interactive = False
34
35 from jsondata import NOTATION_JSON, NOTATION_JSON_REL, NOTATION_HTTP_FRAGMENT
36
37 VALID_NODE_TYPE = (
38 dict,
39 list,
40 str,
41 unicode,
42 int,
43 float,
44 bool,
45 None,
46 )
47
48 CHARSET_UTF = 0
49 CHARSET_STR = 1
50
51
52
53
54
55
56
57
58
59
60
61 if V3K:
62 _RELPOINTER = re.compile(r"(0|[1-9][0-9]*)(([#]$)|(/.*$)|($))")
63 else:
64 _RELPOINTER = re.compile(unicode(r"(0|[1-9][0-9]*)(([#]$)|(/.*$)|($))"))
65
66
67 _unescaped = re.compile(r'/|~[^01]')
68
69
70 _privattr = {
71 'isfragment': '__isfragment',
72 'isrel': '__isrel',
73 'raw': '__raw',
74 'relupidx': '__relupidx',
75 'start': '__start',
76 'startrel': '__startrel',
77 }
78
79
81 """Converts the address of *node* within the data structure
82 *base* into a corresponding pointer path.
83 The current implementation is search based, thus
84 may cause performance issues when frequently applied,
85 or processing very large structures.
86
87 For example: ::
88
89 nodex = {'a': 'pattern'}
90 data = {0: nodex, 1: [{'x':[nodex}]]}
91
92 res = fetch_pointerpath(nodex, data)
93
94 res = [
95 [0],
96 [1, 0, 'x', 0]
97 ]
98
99 Args:
100
101 **node**:
102 Address of Node to be searched for.
103
104 **base**:
105 A tree top node to search the subtree for node.
106
107 **restype**:
108 Type of search. ::
109
110 M_FIRST: The first match only.
111 M_LAST: The first match only.
112 M_ALL: All matches.
113
114 Returns:
115
116 Returns a list of lists, where the contained
117 lists are pointer pathlists for matched elements.
118
119 * restype:=M_FIRST: '[[<first-match>]]',
120
121 * restype:=M_LAST: '[[<last-match>]]',
122
123 * restype:=M_ALL: '[[<first-match>],[<second-match>],...]'
124
125 Raises:
126
127 JSONDataError
128
129 """
130 if not node or not base:
131 return []
132
133 if isinstance(base, JSONData):
134 base = base.data
135
136 spath = []
137 res = []
138
139 kl = 0
140
141 if type(base) is list:
142 kl = 0
143 if id(node) == id(base):
144 res.append([kl])
145 else:
146 for sx in base:
147 if id(node) == id(sx):
148 s = spath[:]
149 s.append(kl)
150 res.append(s)
151
152 elif type(sx) in (dict, list):
153 sublst = fetch_pointerpath(node, sx, restype)
154 if sublst:
155 for slx in sublst:
156
157 _l = [kl]
158 _l.extend(slx)
159 res.append(_l)
160 elif type(sx) in (tuple, set,):
161 raise JSONPointerError(sx)
162 kl += 1
163
164 elif type(base) is dict:
165 if id(node) == id(base):
166 res.append([''])
167 else:
168 for k, v in base.items():
169 if id(node) == id(v):
170 spath.append(k)
171 res.append(spath)
172 continue
173 elif type(v) in (list, dict):
174 sublst = fetch_pointerpath(node, v, restype)
175 if sublst:
176 for slx in sublst:
177 if slx:
178
179 _l = [k]
180 _l.extend(slx)
181 res.append(_l)
182 elif type(v) in (tuple, set,):
183 raise JSONPointerError(v)
184
185 elif type(base) in (tuple, set,):
186 raise JSONPointerError(base)
187
188 if res and restype == M_FIRST:
189 return [res[0]]
190 elif res and restype == M_LAST:
191 return [res[-1]]
192 return res
193
194
196 """Represents exactly one JSONPointer in compliance with
197 IETF RFC6901 and relative-pointer/draft-1/2018
198 """
199 VALID_INDEX = re.compile('0|[1-9][0-9]*$')
200 """Regular expression for valid numerical index."""
201
203 """Normalizes and stores a JSONPointer. The internal
204 representation depends on the type.
205
206 * absolute path:
207
208 A list of ordered items representing
209 the path items.
210
211 * relative path:
212
213 Relative paths in addition provide
214 a positive numeric offset of outer
215 containers [RELPOINTER]_.
216
217 Processes the ABNF of a JSON Pointer from RFC6901
218 and/or a relative JSON Pointer(draft 2018).
219
220 Attributes:
221 For details see manuals.
222
223 * *isfragment*
224 * *isrel*
225 * *raw*
226 * *start*
227 * *startrel*
228
229 Args:
230 **ptr**:
231 A JSONPointer to be represented by this object. The
232 supported formats are:
233
234 .. parsed-literal::
235
236 ptr := (
237 JSONPointer # [RFC6901]_ or [RELPOINTER]_
238 | <rfc6901-string> # [RFC6901]_
239 | <relative-pointer-string> # [RELPOINTER]_
240 | <pointer-items-list> # non-URI-fragment pointer path items of [RFC6901]_
241 )
242
243 JSONPointer:
244 A valid object, is copied into this object,
245 see 'deep'. Supports *rfc6901* [RFC6901]_
246 and *relative* pointers [RELPOINTER]_.
247
248 *rfc6901-string*:
249 A string i accordance to RFC6901 [RFC6901]_.
250
251 *relative-pointer-string*:
252 Draft standard, currently
253 experimental [RELPOINTER]_.
254
255 *pointer-items-list*:
256 Expects a path list, where each item
257 is processed for escape and unquote.
258 Supports *rfc6901* pointers [RFC6901]_.
259
260 Containing:
261
262 * absolute JSON Pointer
263 * relative JSON Pointer, requires the
264 keyword argument *startrel*
265
266 kargs:
267
268 **debug**:
269 Enable debugging.
270
271 **deep**:
272 Applies for copy operations on structured data
273 'deep' when 'True', else 'shallow' only.
274 Flat data types are copied by value in any case.
275
276 **node**:
277 Force to set the pointed node in the internal cache.
278
279 **replace**:
280 Replace masked characters, is applied onto the *ptr*
281 parameter only. For the replacement of *startrel*
282 create and pass an object *JSONPointer*. ::
283
284 replace := (
285 True # replaces rfc6901 escape sequences: ~0 and ~1
286 | False # omit unescaping
287 )
288
289 .. note::
290
291 Match operations on address strings are proceeded literally,
292 thus the escaped characters should be consistent,
293 see rfc6901, Section 3.
294
295 default := False
296
297 **startrel**:
298 Start node for relative JSON Pointers. Is evaluated
299 only in combination with a relative path, else
300 ignored. ::
301
302 startrel := (
303 JSONPointer # supports [RFC6901]_ and [RELPOINTER]_
304 | <rfc6901-string> # supports [RFC6901]_
305 | <rel-pointer-string> # supports only relative to whole-document '0/...'
306 )
307
308 default := "" # whole document
309
310 Returns:
311 When successful returns *True*, else returns either *False*, or
312 raises an exception.
313 Success is the complete addition only, thus one failure returns
314 *False*.
315
316 Raises:
317 JSONPointerError:
318
319 """
320
321 self.debug = kargs.get('debug', False)
322 self.deep = deep = kargs.get('deep', False)
323 self.node = kargs.get('node', None)
324 self.__startrel = kargs.get('startrel', '')
325 replace = kargs.get('replace', False)
326
327 super(JSONPointer, self).__init__()
328
329 if type(ptr) in (int, float):
330 ptr = unicode(ptr)
331 self.__raw = ptr
332
333 elif deep:
334 if type(ptr) in ISSTR:
335 self.__raw = ptr[:]
336 else:
337 self.__raw = copy.deepcopy(ptr)
338 else:
339 if type(ptr) in ISSTR:
340 self.__raw = ptr
341 elif isinstance(ptr, JSONPointer):
342 self.__raw = JSONPointer(ptr.get_raw(), startrel=ptr.get_startrel())
343 else:
344 self.__raw = copy.copy(ptr)
345
346 self.__isrel = False
347 self.__start = None
348 self.__isfragment = False
349
350 if type(ptr) in (list, tuple):
351 self.extend(ptr)
352 return
353
354 if ptr in('', '#'):
355
356 return None
357
358 elif ptr == '/':
359 self.append('')
360 return None
361
362 elif isinstance(ptr, ISSTR):
363 if ptr == '#/':
364 self.__isfragment = True
365 self.append('')
366 return None
367
368 elif ptr.startswith('#'):
369 self.__isfragment = True
370 ptr = url_unquote(ptr[1:])
371
372 elif ptr[0].isdigit():
373
374
375
376
377
378
379
380 _m = _RELPOINTER.match(ptr)
381 if _m is None:
382 raise JSONPointerError("Syntax:" + str(ptr))
383 self.__isrel = True
384
385 if type(self.__startrel) not in (JSONPointer, list, str, unicode):
386 _sr = str(type(self.__startrel)) + " / " + str(self.__startrel)
387 if len(_sr) >200:
388 _sr = _sr[:200]
389 raise JSONPointerError("type not supported startrel=" + _sr)
390
391
392
393
394 self.__relupidx = int(_m.group(1))
395 if self.__relupidx == None:
396 raise JSONPointerError("Cannot scan:" + str(ptr))
397
398 if _m.group(4):
399 ptr = _m.group(4)
400 self.__isrelpathrequest = True
401
402 elif _m.group(3):
403 ptr = None
404 self.__isrelpathrequest = False
405
406 elif _m.group(5) != None:
407 ptr = None
408 self.__isrelpathrequest = True
409 else:
410 raise JSONPointerError("Cannot scan:" + str(ptr))
411
412 if type(self.__startrel) in ISSTR or type(self.__startrel) is list:
413 self.__startrel = JSONPointer(self.__startrel)
414
415 if len(self.__startrel) < self.__relupidx:
416 raise JSONPointerError(
417 "\ninteger prefix overflow:"
418 + "\n prefix = " + str(self.__relupidx)
419 + "\n len(startrel) = " + str(len(self.__startrel))
420 + "\n startrel = " + str(self.__startrel)
421 )
422
423 elif len(self.__startrel) == self.__relupidx:
424 if self.__isrelpathrequest:
425 self.__start = JSONPointer(self.__startrel[:(len(self.__startrel)-self.__relupidx)])
426 else:
427 raise JSONPointerError(
428 "\nkey/index request for <whole-document> prohibited by specification [RELPOINTER], see manuals:"
429 + "\n prefix = " + str(self.__relupidx)
430 + "\n len(startrel) = " + str(len(self.__startrel))
431 + "\n startrel = " + str(self.__startrel)
432 )
433
434
435 elif len(self.__startrel) > self.__relupidx:
436 self.__start = JSONPointer(self.__startrel[:(len(self.__startrel)-self.__relupidx)])
437
438 else:
439 self.__start = JSONPointer('')
440
441 if ptr is not None:
442 self.extend(ptr.split('/'))
443
444 if len(self) == 1 or self[0] != '':
445 raise JSONPointerTypeError("requires a valid JSON pointer: " + str(ptr))
446
447 self.pop(0)
448
449 elif isinstance(ptr, JSONPointer):
450 if ptr.isrel():
451 self.__isrel = ptr.isrel()
452 self.__relupidx = ptr.get_relupidx()
453 self.__isrelpathrequest = ptr.isrelpathrequest()
454
455 if deep:
456 self.__raw = ptr.get_raw()[:]
457 if ptr.isrel():
458 self.__start = ptr.get_start().copy()
459 self.__startrel = ptr.get_startrel().copy()
460 self.extend(ptr.copy_path())
461 else:
462 self.__raw = ptr.get_raw()
463 if ptr.isrel():
464 self.__start = ptr.get_start().copy()
465 self.__startrel = ptr.get_startrel().copy()
466 self.extend(ptr)
467
468 elif type(ptr) is list:
469
470
471 def presolv(p0):
472 if isinstance(p0, JSONPointer):
473 return p0.ptr
474 elif p0 in ('', '/'):
475 return p0
476 elif type(p0) in (str, unicode):
477 return p0
478 elif type(p0) in (int, float):
479 return str(p0)
480 else:
481 raise JSONPointerError("Invalid nodepart:" + str(p0))
482 return p0
483
484 if deep:
485 self.extend(map(lambda s: s[:], ptr))
486 else:
487 self.extend(map(presolv, ptr))
488 self.__raw = '/' + '/'.join(self)
489
490 else:
491 if not ptr:
492 self.__raw = None
493 return None
494 raise JSONPointerError("Pointer type not supported:",
495 type(ptr))
496
497 def _rep0(x):
498 if type(x) in (str, unicode):
499 if x.isdigit():
500 return int(x)
501 return url_unquote(x).replace('~1', '/').replace('~0', '~')
502 return x
503
504 def _rep1(x):
505 if type(x) in (str, unicode):
506 if x.isdigit():
507 return int(x)
508 return x
509
510 if replace:
511 sx = [_rep0(x) for x in self]
512 else:
513 sx = [_rep1(x) for x in self]
514
515 del self[:]
516 self.extend(sx)
517
519 """Appends a Pointer to self.
520
521 Args:
522 **x**:
523 A valid JSONPointer of type: ::
524
525 x := (
526 JSONPointer - fragment
527 | JSONPointer - relative-pointer
528 | relative pointer
529 )
530
531 Returns:
532 A new object of JSONPointer
533
534 Raises:
535 JSONPointerError:
536
537 """
538 ret = JSONPointer(self)
539
540 try:
541 if type(x) in (str, unicode) and x[0] is '#':
542 x = x[1:]
543 except IndexError:
544 pass
545
546 if x == '':
547 pass
548 elif x == u'/':
549 ret.__raw += x
550 ret.append('')
551 elif isinstance(x, JSONPointer):
552 ret.__raw += x.raw
553 ret.extend(x)
554 elif type(x) in (list, tuple,):
555 ret.__raw += u'/' + u'/'.join(x)
556 ret.extend(x)
557 elif type(x) in (str, unicode):
558 if x[0] == u'/':
559 ret.extend(x[1:].split('/'))
560 ret.__raw += x
561 else:
562 ret.extend(x.split('/'))
563 ret.__raw += u'/' + x
564 elif type(x) is int:
565 ret.append(x)
566 ret.__raw += u'/' + unicode(x)
567 elif x is None:
568 return ret
569
570 else:
571 raise JSONPointerError()
572 return ret
573
575 """Evaluates the pointer value on the document.
576
577 Args:
578 **x**:
579 A valid JSON document.
580
581 Returns:
582 The resulting pointer value.
583
584 Raises:
585 JSONPointerError
586 """
587 return self.evaluate(x, *args, **kargs)
588
590 raise NotImplementedError("delete: " + name)
591
620
622 """Checks containment(>=) of another pointer within this.
623
624 The weight of contained entries is the criteria, though
625 the shorter is the bigger. This is true only in case of
626 a containment relation.
627
628 The number of equal path pointer items is compared.
629
630 Args:
631 **x**:
632 A valid Pointer.
633
634 Returns:
635 True or False
636
637 Raises:
638 JSONPointerError:
639
640 """
641 if isinstance(x, JSONPointer):
642 return super(JSONPointer, self).__le__(x)
643 elif type(x) in ISSTR:
644 return super(JSONPointer, self).__le__(JSONPointer(x))
645 else:
646 raise JSONPointerError()
647
649 """Checks containment(>) of another pointer or object within this.
650
651 The number of equal items is compared.
652
653 Args:
654 **x**:
655 A valid Pointer.
656
657 Returns:
658 True or False
659
660 Raises:
661 JSONPointerError:
662 """
663 if isinstance(x, JSONPointer):
664 return super(JSONPointer, self).__gt__(x)
665 elif type(x) in ISSTR:
666 return super(JSONPointer, self).__lt__(JSONPointer(x))
667 else:
668 raise JSONPointerError()
669
671 """Add in place x to self, appends a path.
672
673 Args:
674 **x**:
675 A valid Pointer.
676
677 Returns:
678 'self' with updated pointer attributes
679
680 Raises:
681 JSONPointerError:
682 """
683 if type(x) == list:
684 self.__raw += unicode('/' + '/'.join(x))
685 self.extend(x)
686 elif isinstance(x, JSONPointer):
687 if x.raw[0] != u'/':
688 self.__raw += u'/' + x.raw
689 else:
690 self.__raw = x.raw
691 self.extend(x)
692 elif type(x) is int:
693 self.append(unicode(x))
694 self.__raw += u'/' + unicode(x)
695 elif x == '':
696 raise JSONPointerError("Cannot add the whole document")
697 elif x == u'/':
698 self.__raw += x
699 self.append('')
700 elif type(x) in (str, unicode):
701 if x[0] == u'/':
702 self.extend(x[1:].split('/'))
703 self.__raw += x
704 else:
705 self.extend(x.split('/'))
706 self.__raw += u'/' + x
707 elif x is None:
708 return self
709
710 else:
711 raise JSONPointerError()
712 return self
713
715 """Checks containment(<=) of this pointer within another.
716
717 The number of equal items is compared.
718
719 Args:
720 **x**:
721 A valid Pointer.
722
723 Returns:
724 True or False
725
726 Raises:
727 JSONPointerError:
728 """
729 if isinstance(x, JSONPointer):
730 return super(JSONPointer, self).__ge__(x)
731 elif type(x) in ISSTR:
732 return super(JSONPointer, self).__ge__(JSONPointer(x))
733 else:
734 raise JSONPointerError()
735
737 """Checks containment(<) of this pointer within another.
738
739 The number of equal items is compared.
740
741 Args:
742 **x**:
743 A valid Pointer.
744
745 Returns:
746 True or False
747
748 Raises:
749 JSONPointerError:
750 """
751 if isinstance(x, JSONPointer):
752 return super(JSONPointer, self).__gt__(x)
753 elif type(x) in ISSTR:
754 return super(JSONPointer, self).__gt__(JSONPointer(x))
755 else:
756 raise JSONPointerError()
757
759 """Compares this pointer with x.
760
761 Args:
762 **x**:
763 A valid Pointer.
764
765 Returns:
766 True or False
767
768 Raises:
769 JSONPointerError
770 """
771 return not self.__eq__(x)
772
774 """Adds itself as the right-side-argument to the left.
775
776 This method appends 'self' to a path fragment on the left.
777 Therefore it adds the path separator on it's left side only.
778 The left side path fragment has to maintain to be in
779 accordance to RFC6901 by itself.
780
781 Once 'self' is added to the left side, it terminates it's
782 life cycle. Thus another simultaneous add operation is
783 handled by the resulting other element.
784
785 Args:
786 **x**:
787 A valid Pointer.
788
789 Returns:
790 The updated input of type 'x' as 'x+S(x)'
791
792 Raises:
793 JSONPointerError:
794 """
795 if x == '':
796 return u'/' + u'/'.join(map(unicode, self))
797 elif x == u'/':
798 return x + u'/' + u'/'.join(map(unicode, self))
799 elif type(x) is int:
800 return u'/' + unicode(x) + u'/' + u'/'.join(map(unicode, self))
801 elif type(x) in (str, unicode):
802 return x + u'/' + u'/'.join(map(unicode, self))
803 elif type(x) == list:
804 return x.extend(self)
805 else:
806 raise JSONPointerError()
807 return x
808
810 """Returns the attribute self.__raw, which is the raw input JSONPointer.
811
812 Args:
813 None
814
815 Attributes:
816 Evaluates *self.__isrel*
817
818 Returns:
819 For relative paths: ::
820 (<start-offset>, <pointer>)
821
822 start-offset := [<self.startrel>]
823 pointer := [<self>]
824
825 For RFC6901 paths: ::
826
827 <pointer>
828
829 pointer := [<self>]
830
831 Raises:
832 pass-through
833
834 """
835 if self.__isrel:
836 ret = '(%s, %s)' % (
837 repr(self.__start),
838 unicode(super(JSONPointer, self).__repr__()),
839 )
840
841 else:
842 ret = super(JSONPointer, self).__repr__()
843
844 if ret == '':
845 return "''"
846 return ret
847
849 try:
850 self.__dict__[_privattr[name]] = value
851 except KeyError:
852 self.__dict__[name] = value
853
855 """Returns the string for the processed path.
856
857 Args:
858 None
859
860 Attributes:
861 Evaluates *self.__isrel*
862
863 Returns:
864 For relative paths: ::
865 (<start-offset>, <pointer>)
866
867 start-offset := [<self.startrel>]
868 pointer := [<self>]
869
870 For RFC6901 paths: ::
871
872 <pointer>
873
874 pointer := [<self>]
875
876 Raises:
877 pass-through
878
879 """
880
881 if self.__isrel:
882 if self.__start:
883 ret = "%s" % (
884 '/' + '/'.join((str(x) for x in self.__start)) + '/' + '/'.join((str(x) for x in self))
885 )
886 elif self:
887 ret = "%s" % ('/' + '/'.join((str(x) for x in self)))
888 else:
889 ret = '""'
890
891 else:
892 if self:
893 ret = "%s" % ('/' + '/'.join((str(x) for x in self)))
894 else:
895 ret = '""'
896
897 if ret == '':
898 return "''"
899 return ret
900
902 """Checks the existence of the corresponding node
903 within the JSON document.
904
905 Args:
906 **jsondata**:
907 A valid JSON data node.
908
909 **parent**:
910 If *True* returns the parent node of the pointed value.
911
912 Returns:
913 True or False
914
915 Raises:
916 JSONPointerError:
917
918 pass-through
919 """
920 if self == []:
921 return not (not jsondata)
922 elif self == ['']:
923 try:
924 return not ( not jsondata[''])
925 except KeyError:
926 return False
927
928 if not self.isvalid_nodetype(jsondata):
929
930 raise JSONPointerError("Invalid nodetype parameter:" +
931 str(type(jsondata)))
932
933 if parent:
934 _s = self[:-1]
935 else:
936 _s = self
937 for x in _s:
938 if isinstance(jsondata, dict):
939 jsondata = jsondata.get(x, False)
940 if not jsondata:
941 return False
942 elif isinstance(jsondata, list):
943 jsondata = jsondata[x]
944 if not jsondata:
945 return False
946
947 if not self.isvalid_nodetype(jsondata):
948
949 raise JSONPointerError("Invalid path nodetype:" +
950 str(type(jsondata)))
951 self.node = jsondata
952 return True
953
954 - def copy(self, **kargs):
955 """Creates a copy of self.
956
957 Args:
958 None
959
960 kargs:
961 **deep**:
962 When *True* creates a deep copy,
963 else shallow.
964
965 Returns:
966 A copy of self.
967
968 Raises:
969 pass-through
970 """
971 return JSONPointer(self, copydata=kargs.get('deep', C_DEEP))
972
974 """Returns a deep copy of the objects pointer path list.
975
976 Args:
977 **parent**:
978 The parent node of the pointer path.
979
980 Returns:
981 A copy of the path list.
982
983 Raises:
984 none
985 """
986 if self == []:
987 return []
988 if self == ['']:
989 return ['']
990
991 if parent:
992 return [ s[:] for s in self[:-1]]
993 else:
994 return [ s[:] for s in self[:]]
995
996
997
998
999
1000
1004
1006 try:
1007 return self.__dict__[name]
1008 except KeyError as e:
1009 if V3K:
1010 raise JSONPointerError(
1011 "Unknown attribute: " + repr(e)
1012 )
1013 else:
1014 raise JSONPointerError(
1015 "Unknown attribute: " + repr(e)
1016 )
1017
1019 """Get the resulting key for the pointer. In case
1020 of a relative pointer as resulting from the processing
1021 of the relative pointer and the starting node.
1022 """
1023 if not self.__isrel:
1024 if self == None:
1025
1026 return None
1027
1028 elif not self:
1029
1030 return ''
1031
1032 return self[-1]
1033
1034
1035
1036
1037 if self.__isrelpathrequest:
1038 if not self:
1039 if not self.__start:
1040 return None
1041 return str(self.__start[-1])
1042 return self[-1]
1043
1044 else:
1045
1046 if not self.__start:
1047 return None
1048
1049 elif len(self.__start) - 1 - self.__relupidx <= 0:
1050 return None
1051
1052 return str(self.__start[len(self.__start) - 1 - self.__relupidx])
1053
1055 """Returns a tuple containing the parent node and self as the child.
1056
1057 Args:
1058 **jsondata**:
1059 A valid JSON data node.
1060
1061 Returns:
1062 The the tuple: ::
1063
1064 (p, c):
1065 p: Node reference to parent container.
1066 c: Node reference to self as the child.
1067
1068 Raises:
1069 JSONPointerError:
1070
1071 pass=through
1072 """
1073 n = self(jsondata, True)
1074 if len(self) == 1:
1075 return n, None
1076 try:
1077 return n, self(jsondata, False)
1078 except (IndexError, KeyError):
1079 return n, None
1080 raise JSONPointerError(self.__raw)
1081
1083 """Returns a tuple containing the parent node and the key of current.
1084
1085 Args:
1086 **jsondata**:
1087 A valid JSON data node.
1088
1089 Returns:
1090 The the tuple: ::
1091
1092 (n, k):
1093 n: Node reference to parent container.
1094 k: Key for self as the child entry:
1095
1096 k := (
1097 <list-index>
1098 | <dict-key>
1099 | None
1100 )
1101
1102 list-index: 'int'
1103 dict-key: 'UTF-8'
1104 None: "for root-node"
1105
1106 Raises:
1107 JSONPointerError:
1108
1109 pass-through
1110 """
1111 n = self(jsondata, True)
1112 if len(self) == 1 and self[0] == '':
1113 return n, None
1114
1115 try:
1116 return n, self[-1],
1117 except (IndexError, KeyError):
1118 return n, None
1119 raise JSONPointerError(self.__raw)
1120
1122 """Gets the copy of the corresponding node.
1123 Relies on the standard package 'json'.
1124
1125 Args:
1126 **jsondata**:
1127 A valid JSON data node.
1128
1129 **cp**:
1130 Type of returned copy. ::
1131
1132 cp := (
1133 C_DEEP
1134 | C_REF
1135 | C_SHALLOW
1136 )
1137
1138 kargs:
1139 **valtype**:
1140 Type of requested value.
1141
1142 Returns:
1143 The copy of the node, see option *copy*.
1144
1145 Raises:
1146 JSONPointerError
1147
1148 pass-through
1149 """
1150 valtype = kargs.get('valtype', None)
1151
1152 _resroot = self.get_pointer(jsondata, superpose=True)
1153 if _resroot == None:
1154 return None
1155 if not _resroot:
1156 return jsondata
1157 elif len(_resroot) == 0:
1158 return jsondata
1159 elif len(_resroot) == 1:
1160 if _resroot[0] == '':
1161 return jsondata
1162 try:
1163 return jsondata[_resroot[0]]
1164 except (KeyError, IndexError) as e:
1165 if V3K:
1166 raise JSONPointerError(
1167 "Node(" + str(self.index(0)) + "):" + str(self[0]) + " of " + str(self) + ":" + str(e)
1168
1169
1170
1171 )
1172 else:
1173 raise JSONPointerError(
1174 "Node(" + str(self.index(0)) + "):" + str(self[0]) + " of " + str(self) + ":" + str(e)
1175 )
1176
1177 if not self.isvalid_nodetype(jsondata):
1178 raise JSONPointerError("Invalid nodetype parameter:" +
1179 str(type(jsondata)))
1180
1181 try:
1182 for x in _resroot:
1183 if not isinstance(jsondata, (list, dict, JSONData)):
1184 break
1185 try:
1186 jsondata = jsondata[x]
1187 except TypeError:
1188 jsondata = jsondata[int(x)]
1189
1190 except Exception as e:
1191 if V3K:
1192 raise JSONPointerError(
1193 "Node(" + str(self.index(x)) + "):" + str(x) + " of " + str(self) + ":" + str(e)
1194
1195
1196
1197 )
1198 else:
1199 raise JSONPointerError(
1200 "Node(" + str(self.index(x)) + "):" + str(x) + " of " + str(self) + ":" + str(e)
1201 )
1202
1203 if valtype:
1204
1205 if valtype in (int, float):
1206 if jsondata.isdigit():
1207 jsondata = int(jsondata)
1208 elif valtype in (int, float):
1209 if jsondata.isdigit():
1210 jsondata = float(jsondata)
1211
1212 if not type(jsondata) is valtype:
1213 raise JSONPointerError("Invalid path value type:" + str(
1214 type(valtype)) + " != " + str(type(jsondata)))
1215
1216 else:
1217 if not self.isvalid_nodetype(jsondata):
1218 raise JSONPointerError(
1219 "Invalid path nodetype:"
1220 + str(type(jsondata)))
1221
1222
1223
1224 if type(jsondata) in (dict, list,):
1225 if cp == C_SHALLOW:
1226 return copy.copy(jsondata)
1227 elif cp == C_DEEP:
1228 return copy.deepcopy(jsondata)
1229
1230
1231 return jsondata
1232
1234 """Returns the existing node for the pointer,
1235 calls transparently *JSONPointer.__call__*.
1236
1237 Args:
1238 **jsondata**:
1239 A valid JSON data node.
1240
1241 Returns:
1242 The node reference.
1243
1244 Raises:
1245 JSONPointerError:
1246
1247 pass-through
1248
1249 """
1250 return self.__call__(jsondata)
1251
1253 """Returns two parts, the exisitng node for valid part of
1254 the pointer, and the remaining part of the pointer for
1255 the non-existing sub-path.
1256
1257 This method works similar to the 'evaluate' method, whereas it
1258 handles partial valid path pointers, which may also include
1259 a '-' in accordance to RFC6902.
1260
1261 Therefore the non-ambiguous part of the pointer is resolved,
1262 and returned with the remaining part for a newly create.
1263 Thus this method is in particular foreseen to support the
1264 creation of new sub data structures.
1265
1266 The 'evaluate' method therefore returns a list of two elements,
1267 the first is the node reference, the second the list of the
1268 remaining path pointer components. The latter may be empty in
1269 case of a fully valid pointer.
1270
1271
1272 Args:
1273 **jsondata**:
1274 A valid JSON data node.
1275
1276 **parent**:
1277 Return the parent node of the pointed value.
1278
1279 Returns:
1280 The node reference, and the remaining part.
1281 ret:=(node, [<remaining-path-components-list>])
1282
1283 Raises:
1284 JSONPointerError:
1285 forwarded from json
1286 """
1287 if super(JSONPointer, self).__eq__([]):
1288 return (jsondata, None)
1289 if super(JSONPointer, self).__eq__(['']):
1290 return (jsondata[''], None)
1291
1292 if type(jsondata) not in (dict, list, JSONData):
1293
1294 raise JSONPointerError("Invalid nodetype parameter:" +
1295 str(type(jsondata)))
1296 remaining = None
1297 try:
1298 if parent:
1299 for x in self[:-1]:
1300 remaining = x
1301
1302 jsondata = jsondata[x]
1303 else:
1304 for x in self:
1305 remaining = x
1306
1307 jsondata = jsondata[x]
1308 except Exception:
1309 if parent:
1310 remaining = self[self.index(remaining):-1]
1311 else:
1312 remaining = self[self.index(remaining):]
1313 else:
1314 remaining = None
1315
1316 if type(jsondata) not in (dict, list):
1317
1318 raise JSONPointerError("Invalid path nodetype:" +
1319 str(type(jsondata)))
1320 self.node = jsondata
1321 return (jsondata, remaining,)
1322
1324 """Gets for the corresponding path list of the object pointer for
1325 in-memory access on the data of the 'json' package.
1326
1327 Args:
1328 none
1329
1330 Returns:
1331 The path list.
1332
1333 Raises:
1334 none
1335 """
1336 if __debug__:
1337 if self.debug:
1338 print(repr(self))
1339 return list(self)
1340
1342 """Gets for the corresponding path list of the object pointer for in-memory access on the data of the 'json' package.
1343
1344 Args:
1345 none
1346
1347 Returns:
1348 The path list.
1349
1350 Raises:
1351 none
1352 """
1353 if len(self) > 2:
1354 return self[:-1], self[-1]
1355 elif len(self) == 1:
1356 return [], self[-1]
1357 elif len(self) == 0:
1358 return [], None
1359
1361 """Gets the object pointer in compliance to RFC6901
1362 or relative pointer/draft-01/2018.
1363
1364 The result is by default the assigned pointer itself without
1365 verification. Similar in case of a relative pointer the start
1366 offset is ignored by default and no verification is performed.
1367
1368 The following options modify this behaviour:
1369
1370 * superpose - superposes the *startrel* offset with the pointer
1371 * verify - verifies the actual existence of the nodes and/or
1372 intermediate nodes
1373
1374 The options could be applied combined.
1375
1376 Args:
1377 kargs:
1378 **returntype**:
1379 Defines the return type. ::
1380
1381 returntype := (
1382 RT_DEFAULT | 'default'
1383 | RT_LST | 'list' | list
1384 | RT_JSONPOINTER | 'jpointer'
1385 )
1386
1387 **superpose**:
1388 Is only relevant for relative paths. Superposes the offset
1389 *startrel* with the pointer into the resulting final pointer.
1390 By default nodes are not verified, see *verify* parameter.
1391
1392 default := True
1393
1394 **verify**:
1395 Verifies the "road" of the superposed pointers. ::
1396
1397 verify := (
1398 V_DEFAULT | 'default'
1399 | V_NONE | 'none' | None # no checks at all
1400 | V_FINAL | 'final' # checks final result only
1401 | V_STEPS | 'steps' # checks each intermediate directory
1402 )
1403
1404 default := None
1405 Returns:
1406 The new pointer in a choosen format, see *returntype*.
1407
1408 Raises:
1409 none
1410 """
1411 returntype = rtypes2num[kargs.get('returntype')]
1412 verify = verify2num[kargs.get('verify')]
1413
1414 superpose = kargs.get('superpose', True)
1415
1416
1417 _ptr = JSONPointer(self)
1418
1419 if self.__isrel:
1420 if superpose:
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431 ix = len(self.__startrel) - self.__relupidx
1432 if ix < 0:
1433 raise JSONPointerError(
1434 "offset is shorter than integer-index startrel:%s - int-idx=%s" % (
1435 len(self.__startrel), self.__relupidx)
1436 )
1437
1438 if ix == 0:
1439 _ptr = self
1440
1441 else:
1442 _ptr = self.__startrel[:ix]
1443 _ptr.extend(self)
1444
1445
1446
1447
1448
1449 if verify & V_FINAL:
1450
1451 _chk = JSONPointer(_ptr)(jsondata)
1452
1453 elif verify & V_STEPS:
1454
1455
1456
1457
1458
1459 _chk = JSONPointer(self.__startrel)(jsondata)
1460
1461
1462 _chk = JSONPointer(self.__relupidx + '#')(_chk)
1463
1464
1465 _chk = JSONPointer(self)(_chk)
1466
1467
1468
1469
1470 if returntype & RT_JSONPOINTER:
1471 return _ptr
1472 elif returntype & RT_LST:
1473 return list(_ptr)
1474 else:
1475 raise JSONPointerError("Unknown return type: " + str(returntype))
1476
1478 """Get the resulting pointer and key from the processing of
1479 the pointer and the optional starting node *stratrel*.
1480 """
1481 ret = self.get_pointer(jsondata, **kargs)
1482 k = ret.pop()
1483 return (ret, k,)
1484
1486 """Gets the objects pointer string in compliance to RFC6901
1487 or relative pointer/draft-01/2018.
1488
1489 The result is by default the assigned pointer itself without
1490 verification. Similar in case of a relative pointer the start
1491 offset is ignored by default and no verification is performed.
1492
1493 The following options modify this behaviour:
1494
1495 * superpose - superposes the *startrel* offset with the pointer
1496 * verify - verifies the actual existence of the nodes and/or
1497 intermediate nodes
1498
1499 The options could be applied combined.
1500
1501 Args:
1502 kargs:
1503 **forcenotation**:
1504 Force the output notation for string representation to: ::
1505
1506 forcenotation := (
1507 NOTATION_NATIVE # original format with unescape
1508 | NOTATION_JSON # transform to resulting pointer
1509 | NOTATION_HTTP_FRAGMENT # return a fragment with encoding
1510 | NOTATION_JSON_REL # resulting relative pointer
1511 | NOTATION_RAW # raw input
1512 )
1513
1514 default := NOTATION_NATIVE
1515
1516 **REMINDER**: Applicable for return type string only.
1517
1518 **superpose**:
1519 Is only relevant for relative paths. Superposes the offset
1520 *startrel* with the pointer into the resulting final pointer.
1521 By default nodes are not verified, see *verify* parameter.
1522
1523 Returns:
1524 The new pointer in a choosen format, see *returntype*.
1525
1526 Raises:
1527 none
1528 """
1529 forcenotation = kargs.get('forcenotation')
1530 superpose = kargs.get('superpose', False)
1531
1532
1533
1534
1535
1536 if forcenotation == NOTATION_JSON:
1537 if self.__isrel:
1538 if self.__isrelpathrequest:
1539 ret = self.__start.copy()
1540 else:
1541 return self.__start + '#'
1542 else:
1543 if super(JSONPointer,self).__eq__([]):
1544 return '""'
1545 ret = '/'
1546
1547 elif forcenotation == NOTATION_HTTP_FRAGMENT:
1548 if self.__isrel:
1549 if self.__isrelpathrequest:
1550 ret = self.__start
1551 else:
1552 return self.__start
1553 else:
1554 return '/'
1555
1556 elif forcenotation == NOTATION_JSON_REL:
1557 if self.__isrel:
1558 if self.__isrelpathrequest:
1559 ret = self.__start
1560 else:
1561 return self.__start
1562 else:
1563 return '/'
1564
1565 else:
1566
1567
1568
1569
1570
1571 if self.__isfragment:
1572 if not self:
1573 ret = '#'
1574 else:
1575 ret = '#/'
1576
1577 elif self.__isrel:
1578 if self.__isrelpathrequest:
1579 if superpose:
1580 ix = len(self.__startrel) - self.__relupidx
1581 if ix < 0:
1582 raise JSONPointerError(
1583 "offset is shorter than integer-index startrel:%s - int-idx=%s" % (
1584 len(self.__startrel), self.__relupidx)
1585 )
1586
1587 if ix == 0:
1588 _ptr = self
1589
1590 else:
1591 _ptr = self.__startrel[:ix]
1592 _ptr.extend(self)
1593 else:
1594 _ptr = self
1595
1596 if super(JSONPointer, self).__eq__([]):
1597 if _ptr:
1598 return unicode('/' + '/'.join(map(unicode, _ptr)) + '/')
1599 else:
1600 return unicode('""')
1601 else:
1602 return unicode('/' + '/'.join(map(unicode, _ptr)))
1603
1604 else:
1605 return str(self.__relupidx) + '#'
1606
1607 else:
1608 if not self:
1609 return ''
1610 ret = '/'
1611
1612 if len(self) == 1 and self[0] == '':
1613 return '/'
1614
1615
1616 return unicode(ret + '/'.join(map(unicode, self)))
1617
1619 """Gets the objects raw 6901-pointer.
1620
1621 Args:
1622 none
1623
1624 Returns:
1625 The raw path.
1626
1627 Raises:
1628 none
1629 """
1630 try:
1631 return self.__raw
1632 except KeyError:
1633 return None
1634
1636 """Returns the resulting integer prefix.
1637 """
1638 try:
1639 return self.__relupidx
1640 except KeyError:
1641 return None
1642
1644 """Returns the resulting start pointer after the
1645 application of the integer prefix.
1646 """
1647 try:
1648 return self.__start
1649 except KeyError:
1650 return None
1651
1653 """Returns the raw start pointer.
1654 """
1655 try:
1656 return self.__startrel
1657 except KeyError:
1658 return None
1659
1660 - def evaluate(self, jsondata, parent=False):
1661 """Gets the value resulting from the current pointer.
1662
1663 Args:
1664 **jsondata**:
1665 A JSON data node. ::
1666
1667 jsondata := (
1668 JSONData
1669 | list
1670 | dict
1671 )
1672
1673 **parent**:
1674 Return the parent node of the pointed value.
1675 When parent is selected, the pointed child node
1676 is not verified.
1677
1678 Returns:
1679 The referenced value.
1680
1681 Raises:
1682 JSONPointerError:
1683
1684 pass-through
1685 """
1686
1687
1688
1689 if self.__isrel:
1690
1691
1692
1693 if not self.__startrel.check_node_or_value(jsondata):
1694 raise JSONPointerError('node does not exist:"' + str(self.__startrel) + '"')
1695
1696
1697 if self.__isrelpathrequest:
1698 if self.__start:
1699 _startnode = self.__start.evaluate(jsondata)
1700 else:
1701 _startnode = jsondata
1702
1703 if not self:
1704 return _startnode
1705
1706
1707 else:
1708 return self.__start.get_key()
1709
1710 elif self == []:
1711
1712 return jsondata
1713
1714
1715
1716
1717
1718 elif len(self) == 1 and self[0] == '':
1719 try:
1720 return jsondata['']
1721 except KeyError as e:
1722 raise JSONPointerError("""Non-existent node(see RFC6901 - chap 5): '/""'""")
1723
1724 else:
1725
1726 _startnode = jsondata
1727
1728 if type(_startnode) not in (dict, list, JSONData):
1729
1730 if self.__isrel:
1731
1732 raise JSONPointerError(
1733 "Invalid nodetype parameter: %s"
1734 "\n pointer = %s"
1735 "\n startrel = %s"
1736 "\n start = %s"
1737 "\n jsondata = %s"
1738 "\n startnode = %s"
1739 % (
1740 str(type(_startnode)),
1741 str(self),
1742 str(self.__startrel),
1743 str(self.__start),
1744 str(jsondata),
1745 str(_startnode),
1746 ))
1747
1748 else:
1749 raise JSONPointerError(
1750 "Invalid nodetype parameter:" +
1751 str(type(_startnode)))
1752
1753 try:
1754 if parent:
1755 for x in self[:-1]:
1756
1757 try:
1758 _startnode = _startnode[x]
1759 except TypeError as e:
1760 if x == '-':
1761 _startnode = _startnode[-1]
1762 else:
1763 try:
1764
1765 _startnode = _startnode[int(x)]
1766 except ValueError:
1767
1768
1769 raise JSONPointerError(repr(e))
1770 else:
1771 for x in self:
1772 try:
1773
1774 _startnode = _startnode[x]
1775
1776 except TypeError as e:
1777 if x == '-':
1778
1779 _startnode = _startnode[-1]
1780 else:
1781 try:
1782
1783 _startnode = _startnode[int(x)]
1784 except ValueError:
1785
1786
1787 raise JSONPointerError(repr(e))
1788
1789 except Exception as e:
1790 if V3K:
1791 if isinstance(_startnode, JSONData):
1792 _startnode = _startnode.data
1793
1794 if type(_startnode) is dict:
1795 _jdat = _startnode.keys()
1796 elif type(_startnode) is list:
1797 _jdat = '[0...' + str(len(_startnode) - 1) + ']'
1798 else:
1799 _jdat = _startnode
1800
1801 raise JSONPointerError(
1802 "Requires existing Node(jsondata[" + str(self.index(x)) + "]):"
1803 + '"' + str(self) + '":' + repr(e) + ':jsondata(keys/indexes)=' + str(_jdat)
1804
1805
1806
1807 )
1808
1809 else:
1810 raise JSONPointerError(
1811 "Requires existing Node(jsondata[" + str(self.index(x)) + "]):"
1812 + '"' + str(self) + '":' + repr(e) + ':jsondata=' + str(_startnode)
1813 )
1814
1815 self.node = _startnode
1816 return _startnode
1817
1819 """Checks whether a http fragment."""
1820 return self.__isfragment
1821
1823 """Checks whether a path request."""
1824 try:
1825 return self.__isrelpathrequest and self.__isrel
1826 except KeyError:
1827 return False
1828
1830 """Checks whether a relative pointer."""
1831 return self.__isrel
1832
1834 """Checks valid node types of in-memory JSON data."""
1835 return type(x) in VALID_NODE_TYPE_X or x == None
1836
1838 """Checks whether a value request."""
1839 return not self.__isvalrequest and self.__isrel
1840
1841 - def iter_path(self, jsondata=None, **kargs):
1842 """Iterator for the elements of the path pointer itself.
1843
1844 Args:
1845 **jsondata**:
1846 If provided a valid JSON data node, the
1847 path components are successively verified on
1848 the provided document.
1849
1850 kargs:
1851 **parent**:
1852 Uses the path pointer to parent node.
1853
1854 **rev**:
1855 Reverse the order, start with last.
1856
1857 **superpose**:
1858 Is only relevant for relative paths, for *rfc6901* defined
1859 paths the parameter is ignored. When *True* superposes
1860 the offset *startrel* with the pointer into the resulting
1861 final pointer. By default nodes are not verified,
1862 see *verify* parameter. ::
1863
1864 superpose := (
1865 True # iterates resulting paths from *startrel*
1866 | False # iterates the path only
1867 )
1868
1869
1870 default := True
1871
1872 Returns:
1873 Yields the iterator for the current path pointer
1874 components.
1875
1876 Raises:
1877 JSONPointerError:
1878 forwarded from json
1879 """
1880 parent=kargs.get('parent', False)
1881 rev=kargs.get('rev', False)
1882 superpose=kargs.get('superpose', True)
1883
1884 _ptr = self.get_pointer(jsondata, superpose=superpose)
1885
1886 if self == []:
1887 yield ''
1888 elif self == ['']:
1889 yield '/'
1890 else:
1891 if rev:
1892 if parent:
1893 ptrpath = _ptr[:-1:-1]
1894 else:
1895 ptrpath = _ptr[::-1]
1896 else:
1897 if parent:
1898 ptrpath = _ptr[:-1]
1899 else:
1900 ptrpath = _ptr
1901
1902 try:
1903 x = ptrpath[0]
1904 for x in ptrpath:
1905 if jsondata:
1906
1907 jsondata = jsondata[x]
1908 yield x
1909
1910 except Exception as e:
1911 if V3K:
1912 raise JSONPointerError(
1913 "Node(" + str(ptrpath.index(x)) +"):" + str(x) + " of " +
1914 str(self) + ":" + repr(e)
1915
1916
1917
1918 )
1919 else:
1920 raise JSONPointerError(
1921 "Node(" + str(ptrpath.index(x)) +"):" + str(x) + " of " +
1922 str(self) + ":" + repr(e)
1923 )
1924
1925 self.node = jsondata
1926
1928 """Iterator for the elements the path pointer points to.
1929
1930 Args:
1931 **jsondata**:
1932 A valid JSON data node.
1933
1934 **parent**:
1935 Uses the path pointer to parent node.
1936
1937 **rev**:
1938 Reverse the order, start with last.
1939
1940 Returns:
1941 Yields the iterator of the current node reference.
1942
1943 Raises:
1944 JSONPointerError:
1945 forwarded from json
1946 """
1947 if self == []:
1948 yield jsondata
1949 elif self == ['']:
1950 yield jsondata['']
1951 else:
1952 if rev:
1953 if parent:
1954 ptrpath = self[:-1:-1]
1955 else:
1956 ptrpath = self[::-1]
1957 else:
1958 if parent:
1959 ptrpath = self[:-1]
1960 else:
1961 ptrpath = self
1962
1963 try:
1964 x = ptrpath[0]
1965 for x in ptrpath:
1966
1967 jsondata = jsondata[x]
1968 yield jsondata
1969 except Exception as e:
1970 if V3K:
1971 raise JSONPointerError(
1972 "Node(" + str(ptrpath.index(x)) +"):" + str(x) + " of " +
1973 str(self) + ":" + repr(e)
1974
1975
1976
1977 )
1978 else:
1979 raise JSONPointerError(
1980 "Node(" + str(ptrpath.index(x)) +"):" + str(x) + " of " +
1981 str(self) + ":" + repr(e)
1982 )
1983
1984 self.node = jsondata
1985
1987 """Successive iterator for the resulting sub-paths the
1988 path pointer itself.
1989
1990 Args:
1991 **jsondata**:
1992 If provided a valid JSON data node, the
1993 path components are successively verified on
1994 the provided document.
1995
1996 **parent**:
1997 Uses the path pointer to parent node.
1998
1999 **rev**:
2000 Reverse the order, start with last.
2001
2002 Returns:
2003 Yields the iterator for the copy of the current
2004 slice of the path pointer.
2005
2006 Raises:
2007 JSONPointerError:
2008 forwarded from json
2009 """
2010 if self == []:
2011 yield ''
2012 elif self == ['']:
2013 yield '/'
2014 else:
2015 curpath = []
2016 if rev:
2017 if parent:
2018 ptrpath = self[:-1:-1]
2019 else:
2020 ptrpath = self[::-1]
2021 else:
2022 if parent:
2023 ptrpath = self[:-1]
2024 else:
2025 ptrpath = self
2026
2027 try:
2028 x = ptrpath[0]
2029 for x in ptrpath:
2030 if jsondata:
2031
2032 jsondata = jsondata[x]
2033 curpath.append(x)
2034 yield curpath[:]
2035 except Exception as e:
2036 if V3K:
2037 raise JSONPointerError(
2038 "Node(" + str(ptrpath.index(x)) +"):" + str(x) + " of " +
2039 str(self) + ":" + repr(e)
2040
2041
2042
2043 )
2044 else:
2045 raise JSONPointerError(
2046 "Node(" + str(ptrpath.index(x)) +"):" + str(x) + " of " +
2047 str(self) + ":" + repr(e)
2048 )
2049
2051 """Successive iterator for the resulting sub-paths and the
2052 corresponding nodes.
2053
2054 Args:
2055 **jsondata**:
2056 If provided a valid JSON data node, the
2057 path components are successively verified on
2058 the provided document.
2059
2060 **parent**:
2061 Uses the path pointer to parent node.
2062
2063 **rev**:
2064 Reverse the order, start with last.
2065
2066 Returns:
2067 Yields the iterator for the tuple of the current
2068 slice of the path pointer and the reference of the
2069 corresponding node. ::
2070
2071 (<path-item>, <sub-path>, <node>)
2072
2073 path-item: copy of the item
2074 sub-path: copy of the current subpath
2075 node: reference to the corresponding node
2076
2077 Raises:
2078 JSONPointerError:
2079 forwarded from json
2080 """
2081 if self == []:
2082 yield ''
2083 elif self == ['']:
2084 yield '/'
2085 else:
2086 curpath = []
2087 if rev:
2088 if parent:
2089 ptrpath = self[:-1:-1]
2090 else:
2091 ptrpath = self[::-1]
2092 else:
2093 if parent:
2094 ptrpath = self[:-1]
2095 else:
2096 ptrpath = self
2097
2098 try:
2099 x = ptrpath[0]
2100 for x in ptrpath:
2101 if jsondata:
2102
2103 jsondata = jsondata[x]
2104 curpath.append(x)
2105 yield (x, curpath[:], jsondata)
2106 except Exception as e:
2107 if V3K:
2108 raise JSONPointerError(
2109 "Node(" + str(ptrpath.index(x)) +"):" + str(x) + " of " +
2110 str(self) + ":" + repr(e)
2111
2112
2113
2114 )
2115 else:
2116 raise JSONPointerError(
2117 "Node(" + str(ptrpath.index(x)) +"):" + str(x) + " of " +
2118 str(self) + ":" + repr(e)
2119 )
2120
2121 self.node = jsondata
2122
2123 from jsondata.jsondata import JSONData
2124 VALID_NODE_TYPE_X = (
2125 dict,
2126 list,
2127 str,
2128 unicode,
2129 int,
2130 float,
2131 bool,
2132 None,
2133 JSONData,)
2134 """Valid types of in-memory JSON node types for processing."""
2135