Skip to content

Commit 8a42d62

Browse files
committed
Merge branch 'alexsdutton-more-efficient-resolving'
2 parents c237196 + 8c64674 commit 8a42d62

File tree

1 file changed

+86
-37
lines changed

1 file changed

+86
-37
lines changed

jsonpointer.py

Lines changed: 86 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -168,23 +168,62 @@ def to_last(self, doc):
168168
if not self.parts:
169169
return doc, None
170170

171-
for part in self.parts[:-1]:
172-
doc = self.walk(doc, part)
171+
doc = self.resolve(doc, parts=self.parts[:-1])
172+
last = self.parts[-1]
173+
ptype = type(doc)
174+
if ptype == dict:
175+
pass
176+
elif ptype == list or isinstance(doc, Sequence):
177+
if not self._RE_ARRAY_INDEX.match(str(last)):
178+
raise JsonPointerException(
179+
"'%s' is not a valid list index" % (last, )
180+
)
181+
last = int(last)
182+
183+
return doc, last
184+
185+
def resolve(self, doc, default=_nothing, parts=None):
186+
""" Resolves the pointer against doc, returns the referenced object """
187+
if parts is None:
188+
parts = self.parts
173189

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
190+
try:
191+
for part in parts:
192+
ptype = type(doc)
193+
if ptype == dict:
194+
doc = doc[part]
195+
elif ptype == list or isinstance(doc, Sequence):
196+
if part == '-':
197+
doc = EndOfList(doc)
198+
else:
199+
if not self._RE_ARRAY_INDEX.match(str(part)):
200+
raise JsonPointerException(
201+
"'%s' is not a valid list index" % (part, )
202+
)
203+
doc = doc[int(part)]
186204
else:
187-
return default
205+
doc = doc[part]
206+
except KeyError:
207+
if default is not _nothing:
208+
return default
209+
raise JsonPointerException(
210+
"member '%s' not found in %s" % (part, doc)
211+
)
212+
213+
except IndexError:
214+
if default is not _nothing:
215+
return default
216+
raise JsonPointerException(
217+
"index '%s' is out of bounds" % (part, )
218+
)
219+
220+
except TypeError:
221+
if default is not _nothing:
222+
return default
223+
raise JsonPointerException(
224+
"Document '%s' does not support indexing, must be dict/list "
225+
"or support __getitem__" % type(doc)
226+
)
188227

189228
return doc
190229

@@ -209,17 +248,19 @@ def set(self, doc, value, inplace=True):
209248
def get_part(self, doc, part):
210249
"""Returns the next step in the correct type"""
211250

212-
if isinstance(doc, Mapping):
251+
# Optimize for common cases of doc being a dict or list, but not a
252+
# sub-class (because isinstance() is far slower)
253+
ptype = type(doc)
254+
if ptype == dict:
213255
return part
214-
215-
elif isinstance(doc, Sequence):
216-
256+
if ptype == list or isinstance(doc, Sequence):
217257
if part == '-':
218258
return part
219259

220260
if not self._RE_ARRAY_INDEX.match(str(part)):
221-
raise JsonPointerException("'%s' is not a valid sequence index" % part)
222-
261+
raise JsonPointerException(
262+
"'%s' is not a valid list index" % (part, )
263+
)
223264
return int(part)
224265

225266
elif hasattr(doc, '__getitem__'):
@@ -228,34 +269,42 @@ def get_part(self, doc, part):
228269
return part
229270

230271
else:
231-
raise JsonPointerException("Document '%s' does not support indexing, "
232-
"must be mapping/sequence or support __getitem__" % type(doc))
233-
272+
raise JsonPointerException(
273+
"Document '%s' does not support indexing, must be "
274+
"mapping/sequence or support __getitem__" % type(doc)
275+
)
234276

235277
def walk(self, doc, part):
236278
""" Walks one step in doc and returns the referenced part """
237279

238280
part = self.get_part(doc, part)
239281

240-
assert hasattr(doc, '__getitem__'), "invalid document type %s" % (type(doc),)
241-
242-
if isinstance(doc, Sequence):
243-
if part == '-':
244-
return EndOfList(doc)
245-
246-
try:
247-
return doc[part]
282+
if part == '-' and isinstance(doc, Sequence):
283+
return EndOfList(doc)
248284

249-
except IndexError:
250-
raise JsonPointerException("index '%s' is out of bounds" % (part, ))
251-
252-
# Else the object is a mapping or supports __getitem__(so assume custom indexing)
253285
try:
254286
return doc[part]
255287

256288
except KeyError:
257-
raise JsonPointerException("member '%s' not found in %s" % (part, doc))
289+
raise JsonPointerException(
290+
"member '%s' not found in %s" % (part, doc)
291+
)
292+
293+
except IndexError:
294+
raise JsonPointerException(
295+
"index '%s' is out of bounds" % (part, )
296+
)
258297

298+
except TypeError:
299+
raise JsonPointerException(
300+
"Document '%s' does not support indexing, must be dict/list "
301+
"or support __getitem__" % type(doc)
302+
)
303+
304+
except KeyError:
305+
raise JsonPointerException(
306+
"member '%s' not found in %s" % (part, doc)
307+
)
259308

260309
def contains(self, ptr):
261310
""" Returns True if self contains the given ptr """

0 commit comments

Comments
 (0)