py-data-digger
Safely navigate through unsafe data: dicts, tuples, lists, strings and objects
Inspired on Ruby's dig.
pip install py-data-digger
Why?
TLDR:
Sometimes you don't want to deal with Python exceptions when accessing lists and dicts. If the data you need isn't there, you just want to move on...
No ifs, no try-excepts!
from py_data_digger import dig
components: list | None = dig(nasty_dict, "machines", 0, "engine", "components")
Detailed explanation
In some occasions (like when web scrapping) you need to grab some data from a deeply nested structure like this:
nasty_dict = {
"machines": [
{
"machine_id": "1234567890",
"engine": {
"id": "321abcde",
"name": "Motor XPTO",
"components": [
{"id": "0942323", "name": "Cog"},
{"id": "1642723", "name": "Piston"},
{"id": "8412321", "name": "Bar", "extras": ["Foo"]},
],
},
}
]
}
Suppose we want to take the list of components of the engine of a machine (the only present).
🚨 The unsafe strategy:
components: list = nasty_dict["machines"][0]["engine"]["components"]
This is unsafe because it is highly prone to raise IndexError, KeyError, TypeError if you use the wrong key/index or if the data just isn't there.
😴 The safe (but boring) strategy:
machines: list | None = nasty_dict.get("machines", None)
machine: dict | None = next(iter(machines), None) if machines else None
engine: dict | None = machine.get("engine", None) if machine is not None else None
components: list | None: engine.get("components", None) if engine is not None else None
This is not only tedious but labourious! At least, it's safe. We would not raise errors to break our code.
Introducing dig
With this tool we may quickly and securely navigate through all sorts of nested data.
Let's consider the nasty_dict from the past section and that we also want to access the list of components.
from py_data_digger import dig
components: list | None = dig(nasty_dict, "machines", 0, "engine", "components")
That's it! All the access problems are solved. If the data you want isn't there, it returns None and you can just move on!
components: list | None = dig(nasty_dict, "machines", 0, "engine_2", "components")
if components is None:
return None
Introducing seek
Not satisfied with None returns?
The seek function works just like dig, but it will raise an error if the path informed could not be found.
from py_data_digger import seek
components: list = seek(nasty_dict, "machines", 0, "engine_2", "components")
>>> SeekError: Data digger can't go any further: KeyError
Path traveled: dict -> machines -> 0 -> engine_2
The cool thing is, you would need to handle just one exception (SeekError). It also shows where it failed to seek 😎
Seeking/digging objects
And there is more! If you also want to look inside object attributes, you may do it by passing a special flag. This way it will be compatible with any nested objects like Pydantic models and dataclasses!
person = Person(name='John Doe')
my_dict = {
'item_with_object': person
}
dig(my_dict, 'item_with_object', 'name', dig_objects=True)
>>> 'John Doe'
dig(my_dict, 'item_with_object', 'age', dig_objects=True)
>>> None
seek(my_dict, 'item_with_object', 'name', seek_objects=True)
>>> 'John Doe'
seek(my_dict, 'item_with_object', 'age', seek_objects=True)
>>> SeekError
⚠️ The special flag is required because attribute names may conflict with other mapped keys. Use with caution.
Metadata
Release files for py-data-digger 0.2.0
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 |
|---|---|---|---|---|
| py_data_digger-0.2.0.tar.gz | 4.4 kB | Without provenance | Details for py_data_digger-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| py_data_digger-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for py_data_digger-0.2.0-py3-none-any.whl |
Total release size: 9.5 kB
Release files / py_data_digger-0.2.0.tar.gz
| Download URL | py_data_digger-0.2.0.tar.gz |
|---|---|
| Size | 4.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b1e641b07244a075143991d70f3e4cb58b7235d8df24144f3c7806787e86dfb4
|
|
BLAKE2b-256 checksum How to use checksums |
6521c78aaf63759acb7b44a81ec92bbad23a27ddb58db3fefc72b52b9f9fdf6a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.7.0 CPython/3.12.0 Linux/5.15.0-122-generic
|
Release files / py_data_digger-0.2.0-py3-none-any.whl
| Download URL | py_data_digger-0.2.0-py3-none-any.whl |
|---|---|
| Size | 5.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
67460d16c8d6a73c4d374687b8afa2d4b4c03b31a01cfba121c13a0178d24cc7
|
|
BLAKE2b-256 checksum How to use checksums |
4fa428adc00cf2d8e7152e9395db74deb219276d77effbb3e55bc6a35741ad78
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.7.0 CPython/3.12.0 Linux/5.15.0-122-generic
|
Security for py-data-digger 0.2.0
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.