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'}
Metadata
Release files for traversify 1.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| traversify-1.1.2.tar.gz | 5.5 kB | Without provenance | Details for traversify-1.1.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| traversify-1.1.2-py3-none-any.whl | Python 3 | none | any | Details for traversify-1.1.2-py3-none-any.whl |
Total release size: 25.8 kB
Release files / traversify-1.1.2.tar.gz
| Download URL | traversify-1.1.2.tar.gz |
|---|---|
| Size | 5.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d127880c5f8d5a3be0651fcfc655996bede2434b8eedc9a9b7f67710f882e70b
|
|
BLAKE2b-256 checksum How to use checksums |
2b1fc554628d82cf58ee97c4b5a22c91d43bafc4477f78ed933e9736b5810ed9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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
|
Release files / traversify-1.1.2-py3-none-any.whl
| Download URL | traversify-1.1.2-py3-none-any.whl |
|---|---|
| Size | 20.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
66955ea198270b499dd6b1f7af49b2baf794572c4b74e228b4e563451f8619f2
|
|
BLAKE2b-256 checksum How to use checksums |
076730c6e6393b8ed82be287a7ad3d99f73c66fc08837faa0309a502ef9afde7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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
|
Security for traversify 1.1.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.