Skip to main content

Safely navigate through unsafe data: dicts, tuples, lists, strings and objects

Project description

example workflow

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.

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

py_data_digger-0.2.0.tar.gz (4.4 kB view details)

Uploaded Source

Built Distribution

py_data_digger-0.2.0-py3-none-any.whl (5.1 kB view details)

Uploaded Python 3

File details

Details for the file py_data_digger-0.2.0.tar.gz.

File metadata

  • Download URL: py_data_digger-0.2.0.tar.gz
  • Upload date:
  • Size: 4.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.7.0 CPython/3.12.0 Linux/5.15.0-122-generic

File hashes

Hashes for py_data_digger-0.2.0.tar.gz
Algorithm Hash digest
SHA256 b1e641b07244a075143991d70f3e4cb58b7235d8df24144f3c7806787e86dfb4
MD5 5155000c32307da1784513c781edf7a9
BLAKE2b-256 6521c78aaf63759acb7b44a81ec92bbad23a27ddb58db3fefc72b52b9f9fdf6a

See more details on using hashes here.

File details

Details for the file py_data_digger-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: py_data_digger-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 5.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.7.0 CPython/3.12.0 Linux/5.15.0-122-generic

File hashes

Hashes for py_data_digger-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 67460d16c8d6a73c4d374687b8afa2d4b4c03b31a01cfba121c13a0178d24cc7
MD5 85531ce0c70b072470b53058a24042d8
BLAKE2b-256 4fa428adc00cf2d8e7152e9395db74deb219276d77effbb3e55bc6a35741ad78

See more details on using hashes here.

Supported by

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