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.

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.1.1.tar.gz (4.3 kB view details)

Uploaded Source

Built Distribution

py_data_digger-0.1.1-py3-none-any.whl (5.0 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for py_data_digger-0.1.1.tar.gz
Algorithm Hash digest
SHA256 0d97760b3417d846ae0bef83ffa12fe799251823f8e2d810aebcc50660cadf38
MD5 0630a64c09c9fcd030832924b6756dc1
BLAKE2b-256 87d314e1626dfbe261ae432b08db5c6202b419e1ae0a7cbaa86538e89ca5ea25

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for py_data_digger-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 86d1e112b1e412959aedf585a2f2571fef04cf4cb93f3cc0c9a5649c8bced7bf
MD5 14e86d391dcbc39fe3c744b0863f66b6
BLAKE2b-256 ac4515c342b3f75589d753e38ae64abeb741836ad1387e6a1aab554806376399

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