Skip to main content

Handy python classes for manipulating json data, providing syntactic sugar for less verbose, easier to write code.

Project description

traversify

Handy python classes for manipulating json data, providing syntactic sugar for less verbose, easier to write code.

Traverser class allows one to:

  • traverse complex trees of data with dotted syntax rather than the verbose dictionary dereferencing.
  • treat nodes on the tree as lists even if they are singleton dictionaries, eliminating a lot of type-checking code.
  • add or delete branches of the tree with simple dotted syntax.
  • treat missing keys on the tree as None rather than throwing a key exception, much as JavaScript returns undefined.
  • linkage to Filter class (defined next) for powerful tree comparisons or tree pruning.

Filter class allows one to:

  • define a set of criteria for comparing two partially incongruous trees by limiting the sets of fields compared.
  • apply said criteria to prune a tree of any unwanted fields.

Traverser

Pass tree data to Traverser, either as a list, dictionary, json string or any class offering a json method, and the resultant object will provide the syntactic sugar for traversing with dotted syntax, treating singleston nodes as lists:

>>> from traversify import Traverser
>>> obj = Traverser({'id': 1, 'username': 'jdoe'})
>>> obj.id
1
>>> obj.username
'jdoe'
>>> obj.bad_key is None
True
>>> [node.id for node in obj]
[1]
>>> obj[0].id
1
>>> {'id': 1, 'username': 'jdoe'} in obj
True

Not only can singletons be addressed as lists, but append and extend methods are available to turn singletons into lists on the fly:

>>> obj = Traverser({'id': 1})
>>> obj.append({'id': 2})
>>> obj.extend([{'id': 3, 'id': 4}])
>>> [node.id for node in obj]
[1, 2, 3, 4]

At any time, a Traverser instance will return the underlying value when called:

>>> obj = Traverser({'id': 1})
>>> obj()
{'id': 1}

The tree can be updated using dotted syntax. Note that by default, a Traverser instance makes a deepcopy of the json data so that there are no unintended side effects:

>>> data = {'id': 1, 'username': 'jdoe'}
>>> obj = Traverser(data)
>>> obj.id = 2
>>> del obj.username
>>> obj()
{'id': 2}
>>> data
{'id': 1, 'username': 'jdoe'}

However, if the side-effect of updating the data passed is desired (perhaps due to memory constaints), then pass deepcopy=False:

>>> data = {'id': 1}
>>> obj = Traverser(data, deepcopy=False)
>>> obj.id = 2
>>> obj()
{'id': 2}
>>> data
{'id': 2}

In case there are keys that are not identifiers, then dictionary dereferencing can still be used:

>>> obj = Traverser({'@xsi.type': 'textarea'})
>>> obj['@xsi.type']
'textarea'

The get method allows traversing multiple levels in one call, using dots to set off the levels:

>>> obj = Traverser({'root': {'username': 'any'}})
>>> obj.get('root.username')
'any'

Also, the get method supports dot-escaping so that keys containing dots can still be traversed:

>>> obj = Traverser({'@xsi.type': 'textarea'})
>>> obj.get('@xsi..type')
'textarea'

There's a set method that will update a node multiple levels down and even build out branches that aren't already there:

>>> obj = Traverser({'stats': {'id': 1}})
>>> obj.set('stats.id', 2)
>>> obj()
{'stats': {'id': 2}}
>>> obj.set('users.0.username', 'any')
>>> obj()
{'stats': {'id': 2}, 'users': [{'username': 'any'}]}

To save the trouble of importing json and using dumps, there's a handy to_json method:

>>> obj = Traverser({'id': 1})
>>> obj.to_json()
'{"id": 1}'

Filter

Often one needs to compare two trees without taking into account irrelavant fields, like when records in the tree have ids, but a new record doesn't have it yet. Filter provides a way to make this less verbose by providing blacklist and whitelist attributes for controlled comparison:

>>> from traversify import Traverser, Filter
>>> id_exclude_filter = Filter(blacklist='id')
>>> record = Traverser({'id': 1, 'username': 'jdoe'})
>>> id_exclude_filter.are_equal(record, {'username': 'jdoe'})
True

The same filter can be used to prune a tree of its unwanted fields:

>>> id_exclude_filter.prune(record)
>>> record()
{'username': 'jdoe'}

If a filter is passed while creating a Traverser instance, then ==, in and the prune() method will use it to do the comparison or pruning:

>>> record = Traverser({'id': 1, 'username': 'jdoe'}, filter=Filter(blacklist='id'))
>>> record == {'username': 'jdoe'}
True
>>> {'username': 'jdoe'} in record
True
>>> record.prune()
>>> record()
{'username': 'jdoe'}

Traverser's prune method will accept a filter to override the default (or supply one not already supplied):

>>> record = Traverser({'id': 1, 'username': 'jdoe'})
>>> record.prune(filter=Filter(blacklist='id'))
>>> record()
{'username': 'jdoe'}

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

traversify-1.1.2.tar.gz (5.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

traversify-1.1.2-py3-none-any.whl (20.3 kB view details)

Uploaded Python 3

File details

Details for the file traversify-1.1.2.tar.gz.

File metadata

  • Download URL: traversify-1.1.2.tar.gz
  • Upload date:
  • Size: 5.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/40.6.2 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.6.8

File hashes

Hashes for traversify-1.1.2.tar.gz
Algorithm Hash digest
SHA256 d127880c5f8d5a3be0651fcfc655996bede2434b8eedc9a9b7f67710f882e70b
MD5 7f9e17c251719a125781a6768e983f04
BLAKE2b-256 2b1fc554628d82cf58ee97c4b5a22c91d43bafc4477f78ed933e9736b5810ed9

See more details on using hashes here.

File details

Details for the file traversify-1.1.2-py3-none-any.whl.

File metadata

  • Download URL: traversify-1.1.2-py3-none-any.whl
  • Upload date:
  • Size: 20.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/40.6.2 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.6.8

File hashes

Hashes for traversify-1.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 66955ea198270b499dd6b1f7af49b2baf794572c4b74e228b4e563451f8619f2
MD5 8cf2987218ec7e2d9235ea6b5fb45600
BLAKE2b-256 076730c6e6393b8ed82be287a7ad3d99f73c66fc08837faa0309a502ef9afde7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page