36
36
37
37
# Will be parsed by setup.py to determine package metadata
38
38
__author__ = 'Stefan Kögl <[email protected] >'
39
- __version__ = '1.11 '
39
+ __version__ = '1.10 '
40
40
__website__ = 'https://github.com/stefankoegl/python-json-pointer'
41
41
__license__ = 'Modified BSD License'
42
42
43
43
44
44
try :
45
45
from urllib import unquote
46
+ from itertools import izip
46
47
str = unicode
47
48
except ImportError : # Python 3
48
49
from urllib .parse import unquote
50
+ izip = zip
49
51
50
52
try :
51
53
from collections .abc import Mapping , Sequence
52
54
except ImportError : # Python 3
53
55
from collections import Mapping , Sequence
54
56
57
+ from itertools import tee
55
58
import re
56
59
import copy
57
60
@@ -108,6 +111,26 @@ def resolve_pointer(doc, pointer, default=_nothing):
108
111
return pointer .resolve (doc , default )
109
112
110
113
114
+ def pairwise (iterable ):
115
+ """ Transforms a list to a list of tuples of adjacent items
116
+
117
+ s -> (s0,s1), (s1,s2), (s2, s3), ...
118
+
119
+ >>> list(pairwise([]))
120
+ []
121
+
122
+ >>> list(pairwise([1]))
123
+ []
124
+
125
+ >>> list(pairwise([1, 2, 3, 4]))
126
+ [(1, 2), (2, 3), (3, 4)]
127
+ """
128
+ a , b = tee (iterable )
129
+ for _ in b :
130
+ break
131
+ return izip (a , b )
132
+
133
+
111
134
class JsonPointerException (Exception ):
112
135
pass
113
136
@@ -145,62 +168,23 @@ def to_last(self, doc):
145
168
if not self .parts :
146
169
return doc , None
147
170
148
- doc = self .resolve (doc , parts = self .parts [:- 1 ])
149
- last = self .parts [- 1 ]
150
- ptype = type (doc )
151
- if ptype == dict :
152
- pass
153
- elif ptype == list or isinstance (doc , Sequence ):
154
- if not self ._RE_ARRAY_INDEX .match (str (last )):
155
- raise JsonPointerException (
156
- "'%s' is not a valid list index" % (last , )
157
- )
158
- last = int (last )
159
-
160
- return doc , last
161
-
162
- def resolve (self , doc , default = _nothing , parts = None ):
163
- """ Resolves the pointer against doc, returns the referenced object """
164
- if parts is None :
165
- parts = self .parts
171
+ for part in self .parts [:- 1 ]:
172
+ doc = self .walk (doc , part )
166
173
167
- try :
168
- for part in parts :
169
- ptype = type (doc )
170
- if ptype == dict :
171
- doc = doc [part ]
172
- elif ptype == list or isinstance (doc , Sequence ):
173
- if part == '-' :
174
- doc = EndOfList (doc )
175
- else :
176
- if not self ._RE_ARRAY_INDEX .match (str (part )):
177
- raise JsonPointerException (
178
- "'%s' is not a valid list index" % (part , )
179
- )
180
- doc = doc [int (part )]
174
+ return doc , self .get_part (doc , self .parts [- 1 ])
175
+
176
+ def resolve (self , doc , default = _nothing ):
177
+ """Resolves the pointer against doc and returns the referenced object"""
178
+
179
+ for part in self .parts :
180
+
181
+ try :
182
+ doc = self .walk (doc , part )
183
+ except JsonPointerException :
184
+ if default is _nothing :
185
+ raise
181
186
else :
182
- doc = doc [part ]
183
- except KeyError :
184
- if default is not _nothing :
185
- return default
186
- raise JsonPointerException (
187
- "member '%s' not found in %s" % (part , doc )
188
- )
189
-
190
- except IndexError :
191
- if default is not _nothing :
192
- return default
193
- raise JsonPointerException (
194
- "index '%s' is out of bounds" % (part , )
195
- )
196
-
197
- except TypeError :
198
- if default is not _nothing :
199
- return default
200
- raise JsonPointerException (
201
- "Document '%s' does not support indexing, must be dict/list "
202
- "or support __getitem__" % type (doc )
203
- )
187
+ return default
204
188
205
189
return doc
206
190
@@ -225,19 +209,17 @@ def set(self, doc, value, inplace=True):
225
209
def get_part (self , doc , part ):
226
210
"""Returns the next step in the correct type"""
227
211
228
- # Optimize for common cases of doc being a dict or list, but not a
229
- # sub-class (because isinstance() is far slower)
230
- ptype = type (doc )
231
- if ptype == dict :
212
+ if isinstance (doc , Mapping ):
232
213
return part
233
- if ptype == list or isinstance (doc , Sequence ):
214
+
215
+ elif isinstance (doc , Sequence ):
216
+
234
217
if part == '-' :
235
218
return part
236
219
237
220
if not self ._RE_ARRAY_INDEX .match (str (part )):
238
- raise JsonPointerException (
239
- "'%s' is not a valid list index" % (part , )
240
- )
221
+ raise JsonPointerException ("'%s' is not a valid sequence index" % part )
222
+
241
223
return int (part )
242
224
243
225
elif hasattr (doc , '__getitem__' ):
@@ -246,42 +228,34 @@ def get_part(self, doc, part):
246
228
return part
247
229
248
230
else :
249
- raise JsonPointerException (
250
- "Document '%s' does not support indexing, must be "
251
- "mapping/sequence or support __getitem__" % type (doc )
252
- )
231
+ raise JsonPointerException ("Document '%s' does not support indexing, "
232
+ "must be mapping/sequence or support __getitem__" % type (doc ))
233
+
253
234
254
235
def walk (self , doc , part ):
255
236
""" Walks one step in doc and returns the referenced part """
256
237
257
238
part = self .get_part (doc , part )
258
239
259
- if part == '-' and isinstance (doc , Sequence ):
260
- return EndOfList (doc )
240
+ assert hasattr (doc , '__getitem__' ), "invalid document type %s" % (type (doc ),)
261
241
262
- try :
263
- return doc [part ]
242
+ if isinstance (doc , Sequence ):
243
+ if part == '-' :
244
+ return EndOfList (doc )
264
245
265
- except KeyError :
266
- raise JsonPointerException (
267
- "member '%s' not found in %s" % (part , doc )
268
- )
246
+ try :
247
+ return doc [part ]
269
248
270
- except IndexError :
271
- raise JsonPointerException (
272
- "index '%s' is out of bounds" % (part , )
273
- )
249
+ except IndexError :
250
+ raise JsonPointerException ("index '%s' is out of bounds" % (part , ))
274
251
275
- except TypeError :
276
- raise JsonPointerException (
277
- "Document '%s' does not support indexing, must be dict/list "
278
- "or support __getitem__" % type (doc )
279
- )
252
+ # Else the object is a mapping or supports __getitem__(so assume custom indexing)
253
+ try :
254
+ return doc [part ]
280
255
281
256
except KeyError :
282
- raise JsonPointerException (
283
- "member '%s' not found in %s" % (part , doc )
284
- )
257
+ raise JsonPointerException ("member '%s' not found in %s" % (part , doc ))
258
+
285
259
286
260
def contains (self , ptr ):
287
261
""" Returns True if self contains the given ptr """
0 commit comments