stefankoegl / python-json-pointer

Resolve JSON Pointers in Python
https://python-json-pointer.readthedocs.org/
Other
141 stars 43 forks source link

resolve_pointer() won't always return the default. #9

Closed thekafkaf closed 7 years ago

thekafkaf commented 10 years ago

I noticed the behavior in to cases:

  1. The path that was given was longer the the dicts depth and the last object resolved was a string.
  2. The 'doc' obj to be resolved against was not a dict nor a list and the path was'nt defined.

Both this cases are the product of the handling of getitem in the function walk(), in case the doc is not a list nor a dict, getitem is called without an except. Is there a reason for that? If not, I'd would be more than happy to open a pull request with new tests and a fix.

stefankoegl commented 10 years ago

I am not sure if I understand your points correctly. Could you provide short code examples to reproduce the cases?

thekafkaf commented 10 years ago

I'm sorry for my unclear report, here is an example:

In [1]: from jsonpointer import resolve_pointer
In [2]: d = {'a': {'b': 'c'}}
In [3]: resolve_pointer(d, '/a/b/d', None)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-5e4f54760a84> in <module>()
----> 1 resolve_pointer(d, '/a/b/d', None)

/home/kafkaf/dev/python-json-pointer/jsonpointer.pyc in resolve_pointer(doc, pointer, default)
    104 
    105     pointer = JsonPointer(pointer)
--> 106     return pointer.resolve(doc, default)
    107 
    108 def set_pointer(doc, pointer, value, inplace=True):

/home/kafkaf/dev/python-json-pointer/jsonpointer.pyc in resolve(self, doc, default)
    161 
    162             try:
--> 163                 doc = self.walk(doc, part)
    164             except JsonPointerException:
    165                 if default is _nothing:

/home/kafkaf/dev/python-json-pointer/jsonpointer.pyc in walk(self, doc, part)
    241         else:
    242             # Object supports __getitem__, assume custom indexing
--> 243             return doc[part]
    244 
    245     def contains(self, ptr):

TypeError: string indices must be integers, not unicode

The source of the error is clear, but I'll add an example for the second case, just in case:

In [16]: class Foo(MutableMapping):
    def __init__(self, d):
        self.d = d
    def __getitem__(self, item):
        return self.d[item]
    def __len__(self):
        return len(self.d)
    def __iter__(self):
        return iter(self.d)
    def __delitem__(self, item):
        del self.d[item]
    def __setitem__(self, key, value):
        self.d[key] = value
In [17]: f = Foo({'a': {'b': 'c'}})
In [19]: resolve_pointer(f, '/x/y', None)
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-19-a0b4cf24d5b0> in <module>()
----> 1 resolve_pointer(f, '/x/y', None)

/home/kafkaf/dev/python-json-pointer/jsonpointer.pyc in resolve_pointer(doc, pointer, default)
    104 
    105     pointer = JsonPointer(pointer)
--> 106     return pointer.resolve(doc, default)
    107 
    108 def set_pointer(doc, pointer, value, inplace=True):

/home/kafkaf/dev/python-json-pointer/jsonpointer.pyc in resolve(self, doc, default)
    161 
    162             try:
--> 163                 doc = self.walk(doc, part)
    164             except JsonPointerException:
    165                 if default is _nothing:

/home/kafkaf/dev/python-json-pointer/jsonpointer.pyc in walk(self, doc, part)
    241         else:
    242             # Object supports __getitem__, assume custom indexing
--> 243             return doc[part]
    244 
    245     def contains(self, ptr):

<ipython-input-16-180c99604678> in __getitem__(self, item)
      3         self.d = d
      4     def __getitem__(self, item):
----> 5         return self.d[item]
      6     def __len__(self):
      7         return len(self.d)

KeyError: u'x'
stefankoegl commented 9 years ago

OK, now it's clear. I'd definitely consider both cases an error. It would be great if you could prepare pull requests for those.

thekafkaf commented 9 years ago

I'm on it.

stefankoegl commented 7 years ago

While reviewing open issues, I noticed that this is already fixed in the latest version.

>>> from jsonpointer import resolve_pointer
>>> from collections.abc import MutableMapping
>>> 
>>> class Foo(MutableMapping):
...     def __init__(self, d):
...         self.d = d
...     def __getitem__(self, item):
...         return self.d[item]
...     def __len__(self):
...         return len(self.d)
...     def __iter__(self):
...         return iter(self.d)
...     def __delitem__(self, item):
...         del self.d[item]
...     def __setitem__(self, key, value):
...         self.d[key] = value
... 
>>> f = Foo({'a': {'b': 'c'}})
>>> resolve_pointer(f, '/x/y', None) is None
True
>>> resolve_pointer(f, '/x/y', 'x') == 'x'
True
>>> 
>>> d = {'a': {'b': 'c'}}
>>> resolve_pointer(d, '/a/b/d', 'y') == 'y'
True