Skip to main content

A lightweight Python library for safely navigating and manipulating nested data structures (dicts, lists) using simple dot-notation paths. Ideal for JSON APIs, configs, and complex dict/list objects.

Project description

Nested Utils

License Tests Python PyPI

A lightweight Python library for safely navigating and manipulating nested data structures (dicts, lists) using simple dot-notation paths. Ideal for JSON APIs, configs, and complex dict/list objects.

Why nestedutils?

Working with deeply nested data (like JSON API responses) often leads to verbose, error-prone boilerplate:

# The Standard Way: Verbose and hard to read
user_name = None
if data and "users" in data and len(data["users"]) > 0:
    user = data["users"][0]
    if "profile" in user:
        user_name = user["profile"].get("name")

# With nestedutils: Clean, safe, and readable
from nestedutils import get_path

user_name = get_path(data, "users.0.profile.name")

Features

  • Simple Path Syntax: Use dot-notation strings ("a.b.c") or lists (["a", "b", "c"]) to navigate nested structures
  • Mixed Data Types: Seamlessly work with dictionaries, lists
  • List Index Support: Access list elements using numeric indices, including negative indices
  • Auto-creation: Automatically create missing intermediate containers when setting values
  • Flexible Fill Strategies: Control how missing containers are created with different fill strategies
  • Type Safety: Comprehensive error handling with descriptive error messages and error codes
  • Zero Dependencies: Pure Python implementation with no external dependencies

Use Cases

  • JSON API Responses: Safely extract values from complex, unpredictable JSON responses without dozens of checks.
  • Configuration Management: easily read and modify deeply nested settings in configuration dictionaries.
  • Data Transformation: Rapidly remap data from one complex structure to another using get_path and set_path.

Installation

pip install nestedutils

Quick Start

from nestedutils import get_path, set_path, del_path

# Create a nested structure
data = {}

# Set values using dot-notation
set_path(data, "user.name", "John")
set_path(data, "user.age", 30)
set_path(data, "user.hobbies.0", "reading")
set_path(data, "user.hobbies.1", "coding")

# Access values
name = get_path(data, "user.name")  # "John"
age = get_path(data, "user.age")    # 30
first_hobby = get_path(data, "user.hobbies.0")  # "reading"

# Delete values
del_path(data, "user.age")

API Reference

get_path(data, path, default=None)

Retrieve a value from a nested data structure.

Parameters:

  • data: The data structure to navigate (dict, list, tuple, or nested combinations)
  • path: Path to the value (string with dot notation or list of keys/indices)
  • default: Value to return if path doesn't exist (default: None)

Returns: The value at the path, or default if not found

Examples:

data = {"a": {"b": {"c": 5}}}
get_path(data, "a.b.c")  # 5
get_path(data, "a.b.d", default=99)  # 99

data = {"items": [{"name": "apple"}, {"name": "banana"}]}
get_path(data, "items.1.name")  # "banana"
get_path(data, "items.-1.name")  # "banana" (negative index)

set_path(data, path, value, fill_strategy="auto")

Set a value in a nested data structure, creating intermediate containers as needed.

Parameters:

  • data: The data structure to modify (must be mutable: dict or list)
  • path: Path where to set the value (string with dot notation or list of keys/indices)
  • value: The value to set
  • fill_strategy: How to fill missing containers (default: "auto")
    • "auto": Intelligently creates {} for dicts, [] for lists
    • "none": Fills missing list items with None
    • "dict": Always creates dictionaries
    • "list": Always creates lists

Examples:

data = {}
set_path(data, "user.profile.name", "Alice")
# Creates: {"user": {"profile": {"name": "Alice"}}}

data = {}
set_path(data, "items.0.name", "Item 1")
# Creates: {"items": [{"name": "Item 1"}]}

data = {}
set_path(data, "items.5", "Item 6", fill_strategy="none")
# Creates: {"items": [None, None, None, None, None, "Item 6"]}

del_path(data, path, allow_list_mutation=False)

Delete a value from a nested data structure.

Parameters:

  • data: The data structure to modify
  • path: Path to the value to delete
  • allow_list_mutation: If True, allows deletion from lists (default: False)

Returns: The deleted value

Raises: PathError if the path doesn't exist or deletion is not allowed

Examples:

data = {"a": {"b": 1, "c": 2}}
del_path(data, "a.b")  # Returns 1, data becomes {"a": {"c": 2}}

data = {"items": [1, 2, 3]}
del_path(data, "items.1", allow_list_mutation=True)  # Returns 2
# data becomes {"items": [1, 3]}

Error Handling

The library uses PathError exceptions with error codes for different failure scenarios:

from nestedutils import PathError, PathErrorCode

try:
    set_path(data, "invalid.path", 1)
except PathError as e:
    print(e.message)  # Error message
    print(e.code)     # Error code (PathErrorCode enum)

Error Codes:

  • INVALID_PATH: Invalid path format or type
  • INVALID_INDEX: Invalid list index
  • MISSING_KEY: Key doesn't exist in dictionary
  • EMPTY_PATH: Path is empty
  • IMMUTABLE_CONTAINER: Attempted to modify a tuple
  • INVALID_FILL_STRATEGY: Invalid fill strategy value

Advanced Usage

Using List Paths

List paths are useful when keys contain dots:

data = {}
set_path(data, ["user.name", "first"], "John")
set_path(data, ["user.name", "last"], "Doe")
# Creates: {"user.name": {"first": "John", "last": "Doe"}}

Negative List Indices

Negative indices work like Python list indexing:

data = {"items": [10, 20, 30]}
get_path(data, "items.-1")  # 30 (last item)
set_path(data, "items.-1", 999)  # Updates last item

Working with Tuples

Tuples are read-only. You can read from them but cannot modify:

data = {"items": (1, 2, 3)}
get_path(data, "items.0")  # 1 (works)
set_path(data, "items.0", 9)  # Raises PathError (tuples are immutable)

Handling None Values

The library can navigate through None values when setting:

data = {"a": None}
set_path(data, "a.b.c", 10)
# Replaces None with container: {"a": {"b": {"c": 10}}}

Requirements

  • Python 3.8+

Development

For development setup, building, and contributing, see DEVELOPMENT.md.

Changelog

See CHANGELOG.md for a detailed list of changes and version history.

License

MIT License - see LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Support

If you find this library useful, please consider:

  • Starring the repository on GitHub to help others discover it.
  • 💖 Sponsoring to support ongoing maintenance and development.

Become a Sponsor on GitHub | Support on Patreon

Links

Author

Y. Siva Sai Krishna

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

nestedutils-1.0.0.tar.gz (22.2 kB view details)

Uploaded Source

Built Distribution

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

nestedutils-1.0.0-py3-none-any.whl (8.0 kB view details)

Uploaded Python 3

File details

Details for the file nestedutils-1.0.0.tar.gz.

File metadata

  • Download URL: nestedutils-1.0.0.tar.gz
  • Upload date:
  • Size: 22.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.15 {"installer":{"name":"uv","version":"0.9.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for nestedutils-1.0.0.tar.gz
Algorithm Hash digest
SHA256 183375f756e3fdcd668cb06d7aa44250a57397c9a5a7d528726bfc924b53adfb
MD5 daf0ebb55fb1c07ed902c89de9a4f211
BLAKE2b-256 eca9c396bd39da0b0f77b008baa2fc67e3dd840e6bffc5cf38196fe4e27c9dbb

See more details on using hashes here.

File details

Details for the file nestedutils-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: nestedutils-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 8.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.15 {"installer":{"name":"uv","version":"0.9.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for nestedutils-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 01150d2181095c211edf3885fe7e337eb7bb37c41213668884c0fd9aa2e15252
MD5 bff18510b21733f413c9e49eb96e054c
BLAKE2b-256 4132d105fd05bc1f790af8bf8c8decb928b18b14ae1a74925b6d314831040e9d

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