The Swiss Army knife for nested Python dicts. Access, query, transform, and validate nested data — no schemas, no DSLs, just Python.
Project description
nestdict
The Swiss Army knife for nested Python dicts.
Access, query, transform, and validate nested data — no schemas, no DSLs, just Python.
Pydantic is for data you define. nestdict is for data that arrives.
The Problem
Working with nested dicts in Python is painful:
# The .get().get().get() chain of sadness
city = response.get("data", {}).get("customer", {}).get("address", {}).get("city")
# Or the try/except dance
try:
city = response["data"]["customer"]["address"]["city"]
except (KeyError, TypeError):
city = None
The Solution
from nestdict import NestDict
nd = NestDict(api_response)
city = nd.get("data.customer.address.city") # Done. Returns None if missing.
Installation
pip install nestdict==2.0.0a1 --pre
Quick Start
from nestdict import NestDict
# Wrap any nested dict or list
data = {
"user": {
"name": "Alice",
"age": 30,
"address": {"city": "New York", "zip": "10001"}
},
"tags": ["developer", "python"]
}
nd = NestDict(data)
# Access with dot paths
nd["user.name"] # 'Alice'
nd["user.address.city"] # 'New York'
nd["tags.[0]"] # 'developer'
# Safe access with defaults
nd.get("user.phone") # None
nd.get("user.phone", "N/A") # 'N/A'
# Set values (creates intermediates automatically)
nd["user.email"] = "alice@example.com"
nd["settings.theme"] = "dark" # Creates 'settings' dict automatically
# Delete values
del nd["user.address.zip"]
# Check existence
"user.name" in nd # True
"user.phone" in nd # False
# Get multiple values at once
nd.values_at("user.name", "user.age", "user.phone")
# ['Alice', 30, None]
# Export back to plain dict
plain = nd.to_dict()
# Flatten to dot-notation keys
nd.flatten()
# {'user.name': 'Alice', 'user.age': 30, 'user.address.city': 'New York', ...}
# List all leaf paths
nd.paths()
# ['user.name', 'user.age', 'user.address.city', 'user.email', ...]
Functional API
For one-shot operations, use the functional API — no need to create a NestDict:
from nestdict import get, set_at, delete_at, flatten, unflatten, paths, exists
# Direct access on plain dicts
city = get(api_response, "data.customer.address.city")
exists(config, "database.host") # True/False
# Immutable transforms (returns new dict, original unchanged)
updated = set_at(config, "database.port", 5433)
cleaned = delete_at(user_data, "password")
# Flatten/unflatten
flat = flatten({"a": {"b": 1, "c": 2}})
# {'a.b': 1, 'a.c': 2}
nested = unflatten({"a.b": 1, "a.c": 2})
# {'a': {'b': 1, 'c': 2}}
# All leaf paths
paths(data)
# ['user.name', 'user.age', 'user.address.city', ...]
Works Like a Dict
NestDict implements collections.abc.MutableMapping, so it works everywhere a dict does:
nd = NestDict({"x": 1, "y": 2})
len(nd) # 2
list(nd) # ['x', 'y']
dict(nd) # {'x': 1, 'y': 2}
bool(nd) # True
# Merge with | operator (Python 3.9+)
merged = nd | {"z": 3}
nd |= {"z": 3}
# Copy
import copy
shallow = copy.copy(nd)
deep = copy.deepcopy(nd)
List Support
Works with lists at any level, including as the root:
# Root list
nd = NestDict([{"name": "Alice"}, {"name": "Bob"}])
nd["[0].name"] # 'Alice'
nd["[1].name"] # 'Bob'
# Nested lists
data = {"matrix": [[1, 2], [3, 4]]}
nd = NestDict(data)
nd["matrix.[1].[0]"] # 3
# Negative indices
nd["matrix.[-1].[-1]"] # 4
Path Syntax
| Pattern | Meaning | Example |
|---|---|---|
key |
Dict key | "name" |
key1.key2 |
Nested dict keys | "user.address.city" |
[n] |
List index | "[0]", "[-1]" |
key.[n] |
List in dict | "items.[0].name" |
Error Handling
Clear, actionable error messages:
from nestdict import NestDict, PathNotFoundError
nd = NestDict({"user": {"name": "Alice"}})
try:
nd["user.address.city"]
except PathNotFoundError as e:
print(e)
# Path not found: 'user.address.city' — key 'address' does not exist at user
Exception hierarchy:
NestDictError— base for all nestdict errorsPathError— malformed path syntaxPathNotFoundError(also aKeyError) — path doesn't existValidationError(also aValueError) — validation failureFrozenPathError(also aTypeError) — frozen path mutation
Roadmap
nestdict v2 is a complete rewrite. Here's what's coming:
- v2.0.0a1 (current): Core CRUD, flatten/unflatten, functional API
- v2.0.0a2: Wildcard queries (
users.*.email,**.name), pick/omit - v2.0.0a3: Deep merge with strategies, structural diff
- v2.0.0b1: Validation, frozen paths, schema inference, serialization
- v2.0.0: Stable release
Why Not...?
| Library | What it does | What nestdict adds |
|---|---|---|
| Pydantic | Schema-first validation | nestdict works without defining models — for data that arrives |
| python-box | Dot attribute access | nestdict adds flatten, paths, functional API, and (coming) query/merge/diff |
| glom | Spec-based transforms | nestdict uses simple dot-path strings, not a DSL |
| jmespath | JSON query language | nestdict reads AND writes — not just queries |
Development
# Clone and install
git clone https://github.com/abhisaini880/nestdict.git
cd nestdict
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
# Run tests
pytest --cov=nestdict
# Lint and type check
ruff check nestdict/ tests/
mypy nestdict/
License
MIT License. See LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nestdict-2.0.0a1.tar.gz.
File metadata
- Download URL: nestdict-2.0.0a1.tar.gz
- Upload date:
- Size: 23.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2b38c627260ebc553a6a0df9b7b43db99a957de567376da3a7a21a9ca2c86eb3
|
|
| MD5 |
09b5c4ade5d9c2109134a6e6dc6f7f4a
|
|
| BLAKE2b-256 |
766ac4a90d0d73d86732d526266151ce5d157ecfde0e243aa3713967155682f6
|
File details
Details for the file nestdict-2.0.0a1-py3-none-any.whl.
File metadata
- Download URL: nestdict-2.0.0a1-py3-none-any.whl
- Upload date:
- Size: 15.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
42e10d1bf6bd363e421d9fb65c7a25019d52a402ff058c0180cf93c7e1ab59ef
|
|
| MD5 |
894001f9777afeb998a90cae57ee4bad
|
|
| BLAKE2b-256 |
8801bee9ccd7686f7d0257eb0e62f80f287201934e45fb463302f20693f79776
|