Coder Social home page Coder Social logo

objectpath's People

Contributors

adriank avatar cool-rr avatar ela-b avatar hackerhelmut avatar ilyasukhanov avatar movermeyer avatar nastasi avatar peterheja avatar ryanbowen avatar truebit avatar u8sand avatar vvasyaev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

objectpath's Issues

Recursive descent selector cannot select element in arrary by conditions

Use ObjectPathPy/test.json for test:

L:\OtherProjects\json_path_query\ObjectPathPy>python ObjectPath.py -o test.json
ObjectPath interactive shell
        ctrl+c to exit.

{}
JSON file loaded from test.json
>>> $.store.book.*[price is 8.95]
[{u'category': u'reference', u'price': 8.95, u'title': u'Sayings of the Century', u'author': u'Nigel Rees'}]
>>> $..store.book.*[price is 8.95]
[]
>>> $..book.*[price is 8.95]
[]
>>> $..store.book[price is 8.95]
[]
>>> $..book[price is 8.95]
[]
>>>

The first try uses full path "$.store.book.*[price is 8.95]" or "$.store.book[price is 8.95]" and we can get the book of which price is 8.95.
But "$..store.book.*[price is 8.95]" or "$..book[price is 8.95]" (used in situations that the required item is too deep to describe all parent nodes) does not work.
Could you fix that?

Anyway, it's an awesome lib:) Thanks.

Jsonpath with multiple array seectors

How to write jsonpath when multiple array selectors are required?
In the bellow python example the I want to select {"d": 10, "e": 20} first jsonpath looks correct but does not work. The other ones have side effects.

from objectpath import Tree
a={ 
    "a": [
        {
            "b":1,
            "c": [
                {"d": 10, "e": 20},
                {"d": 30, "e": {"d": 10, "e": 11}},
            ],
            "b2": {
                "c":[
                    {"d":10, "e": 12}
                ]
            }
        },
        {"b": 2}
    ]
}
print list(Tree(a).execute("$.a[@.b is 1].c[@.d is 10]"))
print list(Tree(a).execute("$.a[@.b is 1].c..*[@.d is 10]"))
print list(Tree(a).execute("$.a[@.b is 1]..c[@.d is 10]"))
Output:
[]
[{'e': 20, 'd': 10}, {'e': 11, 'd': 10}]
[{'e': 20, 'd': 10}, {'e': 12, 'd': 10}]

Egg for setuptools?

Interesting project. Any chance to make the python library portably available via pip install ?

Jupyter Notebook, py2.7 get errors on tutorial

I wish to use a python notebook, ie jupyter with this library. I could only get the most trivial example to work. Any ideas?
thank you!
Anne

This works, returning '1'
http://objectpath.org/tutorial.html

from objectpath import *
tree1=Tree({"a":1})
tree1.execute("$.a")

None of the complex json example is working;

json3 = '{ "store": { "book": [ { "category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95 } ] }}'
tree3=Tree(json3)
tree3.execute("$")  # ("$.store.book[0].price")

/Users/ME/anaconda/envs/py27/lib/python2.7/site-packages/objectpath/core/interpreter.pyc in execute(self, expr)
    603                 D=self.D
    604                 if type(expr) in STR_TYPES:
--> 605                         tree=self.compile(expr)
    606                 elif type(expr) not in (tuple,list,dict):
    607                         return expr

/Users/ME/anaconda/envs/py27/lib/python2.7/site-packages/objectpath/core/interpreter.pyc in compile(self, expr)
     36                 if expr in EXPR_CACHE:
     37                         return EXPR_CACHE[expr]
---> 38                 ret=EXPR_CACHE[expr]=parse(expr,self.D)
     39                 return ret
     40 

/Users/ME/anaconda/envs/py27/lib/python2.7/site-packages/objectpath/core/parser.pyc in parse(expr, D)
    462                 nextToken=tokenize(expr).next
    463         token=nextToken()
--> 464         r=expression().getTree()
    465         if D:
    466                 print ("PARSE STAGE")

/Users/ME/anaconda/envs/py27/lib/python2.7/site-packages/objectpath/core/parser.pyc in expression(rbp)
    443         t=token
    444         token=nextToken()
--> 445         left=t.nud()
    446         while rbp < token.lbp:
    447                 t=token

/Users/ME/anaconda/envs/py27/lib/python2.7/site-packages/objectpath/core/parser.pyc in nud(self)
    276         else:
    277                 self.fst=token.value
--> 278                 advance()
    279         return self
    280 

/Users/ME/anaconda/envs/py27/lib/python2.7/site-packages/objectpath/core/parser.pyc in advance(ID)
    159         if ID and token.id != ID:
    160                 raise SyntaxError("Expected %r, got %s"%(ID,token.id))
--> 161         token=nextToken()
    162 
    163 def method(s):

StopIteration: 

I am using;

$ source activate py27; 
discarding /Users/ME/anaconda/bin from PATH
prepending /Users/ME/anaconda/envs/py27/bin to PATH
$ python --version ; pip --version 
Python 2.7.11 :: Continuum Analytics, Inc.
pip 8.1.2 from /Users/ME/anaconda/envs/py27/lib/python2.7/site-packages (python 2.7)
$ ipython --version ; jupyter --version 
4.2.0
4.1.0

Return more than one elements in the final list

I am using the books (json) that you are using in the tutorial and I would like to retrieve the result of the following query:

$..[@.author is 'Evelyn Waugh' and @.title is 'Sword of Honour'] and $..[@.author is 'Nigel Rees' and @.title is 'Sayings of the Century']

this returns only 1 object:
[{
"category": "reference",
"price": 8.95,
"title": "Sayings of the Century",
"author": "Nigel Rees"
}]

I would expect to get two entities back, one for Sword of Honour and one for Sayings of the Century. Is this feasible?

Wierd result for queries on non-object elements

Invalid queries return valid results on non-object elements of the tree (e.g. numbers, strings, sequence of strings)

Using the dataset from main page:

$ objectpath -u "http://api.openweathermap.org/data/2.5/box/city?bbox=12,32,15,37,10&cluster=yes"
>>> $.cnt
15
>>> $.cnt.11
15
>>> $.cnt.wtf?
15
>>> $.cod.foo
"200"
>>> $.cod.foo.asd
"200"
>>> $.cod.foo.asd[asd]
"200"
>>> $.cod.foo.bar['???']
"200"

Same applies to sequences of strings:

$ cat > test.json
{"list": [1,2,3,4]}
$ objectpath test.json
>>> $.list
[
  1,
  2,
  3,
  4
]
>>> $.list.123
[
  1,
  2,
  3,
  4
]
>>> $.list.abc
[]

in Python last line yields an empty generator.

Recursion?

Hey there, I was wondering if it was possible to do recursion of expressions?

Like so:

{
  attachments: $.items[ { title: @.name } ]
}

Which would result in:

[
  { title: somename },
  { title: somename2 }
]

Problem with unicode string in comparison

I have a use use case where I must filter data on some values which contain a leading slash (ie. "/tmp"). This data is loaded from a JSON file so it ends up in unicode and I cannot find a way to filter this. Here is an example:

    data = {
        "store": {
            "book": [
                {
                    "category": "/fiction",
                    "title": "str /fiction"
                },
                {
                    "category": u"/fiction",
                    "title": "unicode /fiction"
                },
                {
                    "category": "fiction/",
                    "title": "str fiction/"
                },
                {
                    "category": u"fiction/",
                    "title": "unicode fiction/"
                },
            ]
        }
    }
    tree = Tree(data)
    tree.execute("$.store.book[@.category is '/fiction']")    # ==> 1 match ("str /fiction")
    tree.execute("$.store.book[@.category is 'fiction/']")    # ==> 2 matches

Thanks

Cannot return the whole document

If I want to get back the whole document, I get an error.
Here the code:

ee = objectpath.Tree({'aa':'bb', 'cc': {'ee':'11', 'rr': '33'}})
ee.execute("$.cc") --> works
ee.execute("$")  --> throws exception "StopIteration"

Support querying python objects

Any plans to support?
I would like to

>>> import datetime
>>> import objectpath
>>> objectpath.Tree(datetime).execute("$.*.now")

Intersection and difference

Currently we have + for union operation to combine two or more collections together. This is very helpful in the way you can split your desired results into sub-sections and write different query paths for each. In addition to +, in certain use cases, more collection operators will prove their usefulness (borrowing from set theory).

I am proposing 2 new collection operators: intersection and difference. These operations require operands to have non duplicate elements. So for these operations, there will be two modes: by-ref and by-value. A and B are by-ref equal if they have the excact same path. A and B are by-value equal if they have the same primitive value or all fields of them are by-value equal.

An array can be a set as long as there are no two elements equal to each other. If otherwise, duplicates are removed before performing any of the set operations.

Intersection ^ (by-ref) and .^ (by-value)

A ^ B is an intersection of A and A iff every element in A ^ B is contained by both A and B.

poems:
    - name: The Bronze Horseman
      author: Pushkin
    - name: Devils
      author: Pushkin
    - name: Oh, Laziness, Come...
      author: Pushkin
    - name: Gitanjali
      author: Tagore
    - name: Manasi
      author: Tagore
    - name: Sonar Tori
      author: Tagore
novels:
    - name: Gitanjali
      author: Tagore
    - name: Noukadubi
      author: Tagore
    - name: Les Misérables
      author: Victor Hugo
  • By-value intersection $.poems.author .^ $.novels.author
    • $.poems.author => Pushkin, Pushkin, Pushkin, Tagore, Tagore, Tagore
    • $.novels.author => Tagore, Tagore, Victor Hugo
    • Remove dups in $.poems.author => Pushkin, Tagore
    • $.poems.author .^ $.novels.author => Tagore
  • By-ref intersection $.poems.author ^ $.novels.author
    • $.poems.author => <poems[0].author>, ..., <poems[5].author>
    • $.novels.author => <novels[0].author>, ..., <novels[2].author>
    • $.poems.author ^ $.novels.author => <None>
  • By-ref intersection $..*[@.author is 'Tagore'] ^ $.novels
    • ($..*[@.author is 'Tagore'] => <poems[3]>, <poem[4]>, <poem[5]>, <novels[0]>, <novels[1]>
    • $.novels => <novels[0]>, ..., <novels[5]>
    • $..*[@.author is 'Tagore'] ^ $.novels => <novels[0]>, <novels[1]>
  • By-value intersection $.poems .^ $.novels => {name: Gitanjali, author: Tagore}

Difference/complement - and .-

A - B is a complement of B in A (or difference of A and B) iff every element in A - B is contained by A but not by B.

  • $.poems.author - $.novels.author => Pushkin, Pushkin, Pushkin, Tagore, Tagore, Tagore
  • $.poems.author .- $.novels.author => Pushkin
  • ($..*[@.author is 'Tagore'] - $.novels).name => Gitanjali, Manasi, Sonar Tori

For performance concerns, A - B should only evaluate B within results of A.

query on temperature data failed

Hi,

I have this sample json file as shown below

{"coord":{"lon":139,"lat":35},
"sys":{"country":"JP","sunrise":1369769524,"sunset":1369821049},
"weather":[{"id":804,"main":"clouds","description":"overcast clouds","icon":"04n"}],
"main":{"temp":289.5,"humidity":89,"pressure":1013,"temp_min":287.04,"temp_max":292.04},
"wind":{"speed":7.31,"deg":187.002},
"rain":{"3h":0},
"clouds":{"all":92},
"dt":1369824698,
"id":1851632,
"name":"Shuzenji",
"cod":200}

The query $..*[@..temp > 10].name works

but the query $..*[@.icon is "04n"].name doesn't work.

any insights?

[Feature request] Named selector and removal operator

For a family like this (the actually data can go very deep):

name: Adam
gender: male
children:
  - name: Bran
    gender: male
  - name: Cindy
    gender: female
    children:
      - name: David
        gender: male
        children:
          - name: Helen
            gender: female
      - name: Eva
        gender: female
  - name: Frank
    gender: male
    children:
      - name: George
        gender: male

I'd like to find Cindy and all female offsprings of Cindy. There will be three steps to take:

  1. Find Cindy: $..*[@.name is 'Cindy'].name => Cindy
  2. Find all female offsprings of Cindy: $..*[@.name is 'Cindy'].children..*[@.gender is female].name => Helen, Eva
  3. Add them together: $..*[@.name is 'Cindy'].name + $..*[@.name is 'Cindy'].children..*[@.gender is female].name => Cindy, Helen, Eva

And now you can see the pattern is already unbearable long due to repetition of finding Cindy pattern. In more complex cases, repetition will make the pattern practically unmaintainable. Currently in my application, I am using a following pattern (with a self-written preprocessor):

$cindy := $..*[@.name is 'Cindy']
$cindy.name + $cindy.children..*[@.gender is female].name

This expands to $..*[@.name is 'Cindy'].name + $..*[@.name is 'Cindy'].children..*[@.gender is female].name.

Another thing I am looking for is the ability to delete certain objects from collection. Suppose I need to find Cindy and all female offsprings of Cindy except David's children. I don't know if it is even possible at the current stage. Since we have '+' for union, I propose use '-' for subtraction.

(The assign operators are aligned only for aesthetics reasons)

$cindy           := $..*[@.name is 'Cindy']
$cindy_bloodline := $cindy.name + $cindy.children..*[@.gender is female].name
$david_bloodline := $..*[@.name is 'David'].children..*.name
$cindy_bloodline - $david_bloodline

int values must be converted to float for comparison

A query looking for a specific float number will match the exact float and for some reason also the integer. E.g. looking for the number 9.891 will find 9.891 but also 9, however 9.8 will not be found.

Somehow the query does work if the value is converted into a float.

from objectpath import Tree

input = {
    "item_1": {
        "value": "foo",
        "x": 5.6,
        "y": 9
    },
    "item_2": {
        "value": "bar",
        "x": 5.6,
        "y": 9.891
    },
    "item_3": {
        "value": "foobar",
        "x": 5.6,
        "y": 9.8
    }
}

op = Tree(input)

query = "$..*[@.x is 5.6 and @.y is 9.891].value"
result = list(op.execute(query))
>>> ['foo', 'bar']

query = "$..*[float(@.x) is 5.6 and float(@.y) is 9.891].value"
result = list(op.execute(query))
>>> ['bar']

extract (print) parent attribute when filtering on child node attribute

I have a json data structure that looks like this:


{    "version": "14",
    "data": {
"applications": [
{

"id": 1,
                "enabled": true,
                "policy": [
                ]
            },            
{
                "id": 2,
                "enabled": true,
                "policy": [
                    {
                        "type": "Rule",
                        "id": 5
                    }
                ]
            }
]

}

I am trying to return the ID of the application when policy id = 5 (or some other int value).

I thought that: $.data.applications[@.policy.*.id is 5].id would work, but i get an empty set []
I also tried: $.data.applications[@.policy..id is 5].id

using "jq" i can do the following:


#cat jsonData.json  | jq ‘.data.applications[] | select(.policy[].id == 5) | .id’

13
14
15
16
17
18
19
21
22
23
24
39

Is this query functionality not possible using objectPath?

timedelta problems

Microsecond handling seems to not be working properly

$ python -c 'import objectpath; print(objectpath.Tree({}).execute("""time([0,0,0,1])"""))'
00:00:00.000001
$ python -c 'import objectpath; print(objectpath.Tree({}).execute("""time([0,0]) - time([0,0,0,1])"""))'
23:59:59.009999

but

>>> datetime.datetime(1970,1,1,0,0) - datetime.datetime(1970,1,1,0,0,0,1)
datetime.timedelta(-1, 86399, 999999)

Notice the number of 9:s

Another sign of the strange microsecond handling is that subtraction of certain values fail:

$ python -c 'import objectpath; print(objectpath.Tree({}).execute("""time([0,0,0,999999])"""))'
00:00:00.999999
$ python -c 'import objectpath; print(objectpath.Tree({}).execute("""time([0,0]) - time([0,0,0,999999])"""))'
Traceback (most recent call last):
  File "/home/ubuntu/env/lib/python3.6/site-packages/objectpath/core/interpreter.py", line 158, in exe
    return fst-snd
TypeError: unsupported operand type(s) for -: 'datetime.time' and 'datetime.time'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/ubuntu/env/lib/python3.6/site-packages/objectpath/core/interpreter.py", line 646, in execute
    ret=exe(tree)
  File "/home/ubuntu/env/lib/python3.6/site-packages/objectpath/core/interpreter.py", line 164, in exe
    return timeutils.subTimes(fst,snd)
  File "/home/ubuntu/env/lib/python3.6/site-packages/objectpath/utils/timeutils.py", line 169, in subTimes
    return datetime.time(*reversed(t2))
ValueError: microsecond must be in 0..999999

Attribute name with leading digit is not parsed

Thanks for ObjectPath, it is great! I started to play with it recently and found that number-leading atributes are not recognized by parser. This is a part of openweathermap json response:

>>> from objectpath import Tree
>>> tree=Tree({'3h':1})
>>> tree.execute("$.3h")
{'3h': 1}

I also found workaround, which gives me expected result:

>>>> tree.execute("$.*['3h'][0]")
1

But in some complex cases workaround does not work either.

Query string for nested array

I want to find the element of the array where firstName is John and has a phoneNumber of type iPhone.

[{
  "firstName": "John",
  "age"      : 26,
  "phoneNumbers": [
    {
      "type"  : "iPhone",
      "number": "0123-4567-8888"
    },
    {
      "type"  : "home",
      "number": "0123-4567-8910"
    }
  ]
},
{
  "firstName": "Johny",
  "lastName" : "doe",
  "age"      : 26,
  "address"  : {
    "streetAddress": "naist street",
    "city"         : "Nara",
    "postalCode"   : "630-0192"
  },
  "phoneNumbers": [
    {
      "type"  : "iPhone",
      "number": "0123-4567-8888"
    },
    {
      "type"  : "home",
      "number": "0123-4567-8910"
    }
  ]
}] 

However I received a syntax error. Here is the session:

Loading JSON document from simple.json... done.
$..[@.firstName is 'John']
[{
"age": 26,
"phoneNumbers": [
{
"type": "iPhone",
"number": "0123-4567-8888"
},
{
"type": "home",
"number": "0123-4567-8910"
}
],
"firstName": "John"
}]
$..
[@.firstName is 'John' and @.phoneNumbers[].type is 'iPhone']
Syntax error ('
').

What I am doing wrong?

Thanks in advance.

UnboundLocalError: local variable 'ret' referenced before assignment

Hi!

It's my first time using ObjectPath, and I'm getting this error:

Traceback (most recent call last):
  File "script.py", line 19, in <module>
    res = tree.execute('$.issues[@.changelog.histories[@.items[0].toString is "Done"]]')
  File "C:\Users\cmmartins\AppData\Local\Programs\Python\Python37-32\lib\site-packages\objectpath\core\interpreter.py", line 608, in execute
    ret=exe(tree)
  File "C:\Users\cmmartins\AppData\Local\Programs\Python\Python37-32\lib\site-packages\objectpath\core\interpreter.py", line 328, in exe
    nodeList_append(exe((selector[0],exe(selector[1]),exe(selector[2]))))
  File "C:\Users\cmmartins\AppData\Local\Programs\Python\Python37-32\lib\site-packages\objectpath\core\interpreter.py", line 234, in exe
    return ret
UnboundLocalError: local variable 'ret' referenced before assignment

I don't know if my query is wrong (toString is a property, maybe this is the problem?) but the error is not being treated. I saw this issue in another repo (miguelgrinberg/python-socketio#85), maybe this guy solution helps you.

Thank you!

wrong types

keys(sum($.))
Argument is not object but int in keys()
keys($.
)
Argument is not object but list in keys()

Can't interpret object keys which contain ":"

I have a JSON-LD style document that contains ":" as a namespace separator in the object's keys, so something like:

{
    "dc:identifier" : [{"type" : "identifier type", "id" : "identifier"}]
}

When I do

t = Tree(doc)
t.execute("$.dc:identifier")

I get nothing back.

If I add a key which does not have a ":" it works fine, so I guess that's the reason.

I couldn't see if ":" is a special character in objectpath, and I couldn't find an escape character to use from the documentation, so a bit stuck. A shame, as it does everything else I need!

python: is and in comparison operators in selector behavior

Hi, cool library!

I have a scenario where I want to get all of the "animals" below where the id attribute contains the word test.

How can I do this? Nothing below seems to work. I can get them explicitly as below, but not from a match this prefix kind of way. The in and is comparison operators seems like they should work, but it doesn't appear to.

Python 3.6.4 (default, Mar 15 2018, 16:45:14)
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from objectpath import *
>>> x = {
...   "a": "test",
...   "b": [{
...     "animals": [{
...       "id": "test AA1",
...       "value": "something"
...     }, {
...       "id": "test AA2",
...       "value": "whatever"
...     }]
...   }]
... }
>>> tree = Tree(x)
>>> result = tree.execute("$.b[0].animals[@.id in 'test AA1']")
>>> next(result)
{'id': 'test AA1', 'value': 'something'}
>>> result = tree.execute("$.b[0].animals[@.id in 'test AA2']")
>>> next(result)
{'id': 'test AA2', 'value': 'whatever'}
>>> result = tree.execute("$.b[0].animals['test' in @.id]")
>>> next(result)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> result = tree.execute("$.b[0].animals[split(@.id,'')[0] is 'test']")
>>> next(result)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

There seems to be no way to utilize the in or is syntax in this way? Perhaps I am doing it wrong?

** in object name

Is there a way to find object with name of structure "**name" / "****name"?
I've tried this by executing $.."**name" and many other combinations on Tree Object but it didn't succeed..

There's such adnotation on documentation page:

Names can be written without quotes, but in that case they cannot start with an operator. ObjectPath raises an exception if name is not valid.

so as far as I understood it shall work with **name (if between quotes)...
If any character is applied before "*" (like " **name" or " %***name") it works.

Thanks and hope there's a quick solution for this problem. ;)

Can't filter selections on root node

Consider the correctly working code below. It simply selects the elements where x<2.

>>> a = {"data": [{'x': 1}, {'x':2}]}
>>> tree = objectpath.Tree(a)
>>> list(tree.execute('$.data[@.x < 2]'))
[{'x': 1}]

Now if we remove data and make the list the root node, it doesn't work:

>>> a = [{'x': 1}, {'x':2}]
>>> tree = objectpath.Tree(a)
>>> list(tree.execute('$[@.x < 2]'))
[{'x': 1}, {'x': 2}]

Is there a reason why this is so? Should it be so? Wouldn't it make conceptual sense to be able to do the same filters on the root node as on child nodes?

sys.version should not be used for version checks

In various places you're using sys.version to determine the Python version. This should use sys.version_info instead as there is no guarantee that the Python version is always at the beginning of sys.version.

typo in example

I think tree=Tree({a:1}) should be tree=Tree({'a':1}) :)

Also I was having troubles with printing tree, getting error like:

>>> tree
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/site-packages/objectpath/core/interpreter.py", line 523, in __repr__
    return self.__str__()
  File "/usr/local/lib/python2.7/site-packages/objectpath/core/interpreter.py", line 520, in __str__
    return "TreeObject(%s)"%str(self.tree)
AttributeError: 'Tree' object has no attribute 'tree'

Add support for custom dictionaries (including OrderedDict)

By default Python's json.load and json.loads creates standard Python dictionaries,
which don't preserve order of keys, so for example the following snippet:

import json, collections
import objectpath

data = """ 
{   
    "g1" : { "a" : 1 },
    "g2" : { "a" : 2 },
    "g3" : { "a" : 3 } 
}   
""" 

tree = objectpath.Tree(json.loads(data))
print "Values of a: ", ",".join(str(x) for x in tree.execute("$..a"))

will print:

Values of a:  3,2,1

This is a problem for me, because for my application that order is important,
I would like to see "1,2,3" printed, as this is the order of values of "a" in my JSON.

So I tried loading data with flag object_pairs_hook = collections.OrderedDict,
which causes json.loads to produce order preserving OrderedDicts:

tree = objectpath.Tree(json.loads(data, object_pairs_hook = collections.OrderedDict))

Unfortunately, if I change the example program like this I get:

Values of a:  
Traceback (most recent call last):
  File "object_path_bug.py", line 16, in <module>
    print "Values of a: ", ",".join(str(x) for x in tree.execute("$..a"))
  File "/var/tmp/SKL/lib/python2.7/site-packages/objectpath/core/interpreter.py", line 608, in execute
    ret=exe(tree)
  File "/var/tmp/SKL/lib/python2.7/site-packages/objectpath/core/interpreter.py", line 288, in exe 
    fst=flatten(exe(node[1]))
  File "/var/tmp/SKL/lib/python2.7/site-packages/objectpath/core/interpreter.py", line 246, in exe 
    return self.data
AttributeError: 'Tree' object has no attribute 'data'

Would it be possible to fix objetpath so it can work with json data decoded with
object_pairs_hook = collections.OrderedDict, please?

in operator confusing behavior

May be it is just me not understanding something obvious, but why this cannot find a substring in string:

>>> import objectpath
>>> tree = objectpath.Tree({'doc': {'title': 'Purple is Best Color'}})
>>> list(tree.execute('$..*["Purple" in @.title]'))
[]

But, explicitly converting the substring to string with str() works:

>>> list(tree.execute('$..*[str("Purple") in @.title]'))
[{'title': 'Purple is Best Color'}]

Is this a bug or an intended behavior? Thanks!

SO post for the reference: http://stackoverflow.com/questions/34820888/objectpath-trouble-with-in-operator

updating fields through object path

Hi,
I've been starting to use ObjectPath earlier today, mostly because I'm dissatisfied with existing JsonPath implementations in Python.

I've been looking through the documentation, but could not find anything related to updating fields from their given path. Is there any functionality like this?

Best regards.

Min() doesn't work on dates

Loading JSON document from http://hackathon.services-autoscout24.de/id.php?asset=357322040163096... done.

$.*
[
{
"latitude": null,
"longitude": null,
"recorded_at": null
},
{
"latitude": 48.14695,
"longitude": 11.5347,
"recorded_at": "2014-10-31T18:25:22Z"
},
{
"latitude": 48.14695,
"GPS_SPEED": {"1": 0},
"longitude": 11.5347,
"recorded_at": "2014-10-31T18:25:21Z"
},
{
"latitude": 48.14775,
"longitude": 11.53441,
"recorded_at": "2014-10-31T18:22:47Z"
},
{
"latitude": 48.14695,
"GPS_DIR": 143.2,
"GPS_SPEED": {"1": 4001},
"longitude": 11.53467,
"recorded_at": "2014-10-31T18:23:03Z"
},
... (11166 more items)
]
$.recorded_at
[
null,
"2014-10-31T18:25:22Z",
"2014-10-31T18:25:21Z",
"2014-10-31T18:22:47Z",
"2014-10-31T18:23:03Z",
... (11166 more items)
]
min($.recorded_at)
min() arg is an empty sequence

Potential hyphen issue?

Hi,

I'm trying to parse the following dictionary:

>>> d
{'rpc-reply': {'data': {'groups': {'group': [{'bgp': {'instance': {'instance-as': {'four-byte-as': {'as': '13335', 'bgp-running': '', 'default-vrf': {'global': {'global-afs': {'global-af': {'af-name': 'ipv4-unicast', 'enable': '', 'aggregate-addresses': {'aggregate-address': {'aggregate-prefix': '20', 'route-policy-name': 'anycast-attributes', 'aggregate-addr': '172.17.17.0'}}}}}}}, 'as': '0'}, 'instance-name': 'default'}}, 'group-name': 'GROUP1'}, {'bgp': {'instance': {'instance-as': {'four-byte-as': {'as': '13335', 'bgp-running': '', 'default-vrf': {'global': {'global-afs': {'global-af': {'af-name': 'ipv4-unicast', 'enable': '', 'aggregate-addresses': {'aggregate-address': {'aggregate-prefix': '20', 'route-policy-name': 'anycast-attributes', 'aggregate-addr': '192.168.0.0'}}}}}}}, 'as': '0'}, 'instance-name': 'default'}}, 'group-name': 'GROUP2'}]}}}}

I am able to instantiate the Tree:

>>> from objectpath import Tree
>>> t = Tree(d)
>>> t
TreeObject()

But I notice that is unable to select:

>>> t.execute("$.rpc-reply")
>>> t.execute("$.data")

When selecting using the square brackets seems that no matter what is requested, returns the whole structure:

>>> t.execute("$['rpc-reply']")
{'rpc-reply': {'data': {'groups': {'group': [{'bgp': {'instance': {'instance-as': {'four-byte-as': {'as': '13335', 'bgp-running': '', 'default-vrf': {'global': {'global-afs': {'global-af': {'af-name': 'ipv4-unicast', 'enable': '', 'aggregate-addresses': {'aggregate-address': {'aggregate-prefix': '20', 'route-policy-name': 'anycast-attributes', 'aggregate-addr': '172.17.17.0'}}}}}}}, 'as': '0'}, 'instance-name': 'default'}}, 'group-name': 'GROUP1'}, {'bgp': {'instance': {'instance-as': {'four-byte-as': {'as': '13335', 'bgp-running': '', 'default-vrf': {'global': {'global-afs': {'global-af': {'af-name': 'ipv4-unicast', 'enable': '', 'aggregate-addresses': {'aggregate-address': {'aggregate-prefix': '20', 'route-policy-name': 'anycast-attributes', 'aggregate-addr': '192.168.0.0'}}}}}}}, 'as': '0'}, 'instance-name': 'default'}}, 'group-name': 'GROUP2'}]}}}}
>>> t.execute("$['anything']")
{'rpc-reply': {'data': {'groups': {'group': [{'bgp': {'instance': {'instance-as': {'four-byte-as': {'as': '13335', 'bgp-running': '', 'default-vrf': {'global': {'global-afs': {'global-af': {'af-name': 'ipv4-unicast', 'enable': '', 'aggregate-addresses': {'aggregate-address': {'aggregate-prefix': '20', 'route-policy-name': 'anycast-attributes', 'aggregate-addr': '172.17.17.0'}}}}}}}, 'as': '0'}, 'instance-name': 'default'}}, 'group-name': 'GROUP1'}, {'bgp': {'instance': {'instance-as': {'four-byte-as': {'as': '13335', 'bgp-running': '', 'default-vrf': {'global': {'global-afs': {'global-af': {'af-name': 'ipv4-unicast', 'enable': '', 'aggregate-addresses': {'aggregate-address': {'aggregate-prefix': '20', 'route-policy-name': 'anycast-attributes', 'aggregate-addr': '192.168.0.0'}}}}}}}, 'as': '0'}, 'instance-name': 'default'}}, 'group-name': 'GROUP2'}]}}}}

Loading the dict into a JSON file and executing form the console:

› objectpath -d groups.json
ObjectPath interactive shell
ctrl+c to exit, documentation at http://adriank.github.io/ObjectPath.

Loading JSON document from groups.json...INFO@35 All strings will be cut to 100 chatacters.
 done.
>>> $
START@43 Tree.execute

>>> $.rpc-reply
START@43 Tree.execute
PARSE STAGE
('-', ('.', ('(root)', 'rs'), ('name', 'rpc')), ('name', 'reply'))
START@56 executing node '('-', ('.', ('(root)', 'rs'), ('name', 'rpc')), ('name', 'reply'))'
START@56 executing node '('.', ('(root)', 'rs'), ('name', 'rpc'))'
START@56 executing node '('(root)', 'rs')'
DEBUG@260 . left is '{
    'rpc-reply': {u'data': {u'groups': {u'group': [{u'bgp': {u'instance': {u'instance-as': {u'four-byte-as': {u'as': ,
    ...
}'
START@56 executing node '('name', 'rpc')'
DEBUG@268 . right is 'rpc'
END@277 . returning 'None'
START@56 executing node '('name', 'reply')'
END@609 Tree.execute with: 'None'
null
>>> $['rpc-reply']
START@43 Tree.execute
PARSE STAGE
('(root)',)
START@56 executing node '('(root)',)'
END@609 Tree.execute with: '{
    'rpc-reply': {u'data': {u'groups': {u'group': [{u'bgp': {u'instance': {u'instance-as': {u'four-byte-as': {u'as': ,
    ...
}'
{"rpc-reply": {"data": {"groups": {"group": [
  {
    "bgp": {...},
    "group-name": "GROUP1"
  },
  {
    "bgp": {...},
    "group-name": "GROUP2"
  }
]}}}}
>>> $['anything']
START@43 Tree.execute
PARSE STAGE
('(root)',)
START@56 executing node '('(root)',)'
END@609 Tree.execute with: '{
    'rpc-reply': {u'data': {u'groups': {u'group': [{u'bgp': {u'instance': {u'instance-as': {u'four-byte-as': {u'as': ,
    ...
}'
{"rpc-reply": {"data": {"groups": {"group": [
  {
    "bgp": {...},
    "group-name": "GROUP2"
  },
  {
    "bgp": {...},
    "group-name": "GROUP2"
  }
]}}}}

Looks like $.rpc-reply returns None, while $['rpc-reply'] returns everything as above.

Is there anything I miss?

Thanks,
Mircea

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.