jon-betts / python-datapath

Get and set values in deeply nested structures using JSONPath like syntax

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

python-datapath

Use JSONPath like strings to get and set values in a deeply nested data structure with graceful retrieval if the structure does not exist and autovivification when setting values.

Inspired by, but not completely compliant with the [JSONPath specification] (http://goessner.net/articles/JsonPath/)

Why should I use this library?

YOU REALLY SHOULDN'T - This is nowhere near ready to be used yet!

datapath lets you:

  • Get values from deeply nested structures without caring if any of the intermediate keys exist
  • Set values into data structures and have all intermediate values created for you
  • Turn deeply nested structures into flat dicts and back

Enough talking!

from datapath import ddict

a = ddict({
    'store': {
        'book': [
            {
                'title': 'Sayings of the Century',
                'price': 8.95
            }
        ]
    },
    'bicycle': {
        'color': 'red',
        'price': 19.95
    }
})

# Retrieve a value deeply nested value

# ...by using it as a normal dict
print a['store']['book'][0]['price']  # Not very safe
print a.get('store', {}).get('book', [{}])[0].get('price')  # Much safer

# ... or using datapath
print a[['store.book:0.price']]

# Retrieve a value that doesn't exist yet without an issue (with a default)
print a[['store.book:10.price', 0]]

# Set values on objects that don't yet exist
a[['store.book:2.price']] = 8.99
a[['new.here:3.escaped\\.dot']] = 'All intermediate structures created'

# Set all book categories at once
a[['store.book:*.category']] = 'fiction'

# The price of everything
print a[["..price"]]

# The price of everything in the store
print a[["store..price"]]

Compact paths

The datapath library supports compact paths which cut a small amount of the verboseness of the full JSONPath spec. A number of simplifying assumptions are made:

  • All paths are local
  • 'Naked' paths without a prefix are assumed to be dict keys
  • Bracketed paths are assumed to be on the local object

You can mix and match compact paths or JSON Paths in the same path.

Action Compact path JSON Path
Dict key .a, a $["a"]
Dict key wild .*, * $[*]
Dict key slice ["a", "b"] $["a", "b"]
Recurse to dict key ..a $..a
Recurse to any dict key ..* $..*
List key :3, [3] $[3]
List key wild :* n/a
List slice [0:10:2] $[0:10:2]
List slice (range) [0,2,-1] $[0,2,-1]
Recurse to list key ..:0 n/a

Anchoring

The JSONPath spec suggest '@.' for local anchoring and '$.' for root anchoring. Where anchoring is not specified or relevant datapath allows the omission of the leading identifiers.

NOTE! - Currently datapath parses anchors, but does nothing with them.

Escaping

You can set a key with a dot, or any other reserved character by escaping it:

from datapath.crud import get_path
 
print get_path('a\\.b', {'a.b' : 5})  # 5!

Compliance levels

The datapath library does not support the following parts of JSONPath at the moment:

  • Selectors beyond '*' or slices
  • No ability to do things like book[author='lily']

Known issues

  • This library doesn't work, and using it is a fools errand
  • Setting recursive paths is a bit wonky ** Sometimes it's accurate but counter intuitive

About

Get and set values in deeply nested structures using JSONPath like syntax


Languages

Language:Python 100.0%