pydictnest
pydictnest is a small, typed Python library for working with nested mappings.
It provides focused helpers for reading, writing, traversing, flattening, and
reconstructing dictionary-like structures.
The package can:
- Get or set a value using a sequence of nested keys.
- Check whether a nested key path exists.
- Iterate over the paths and values of all leaf nodes.
- Flatten a nested mapping into string-keyed entries.
- Reconstruct a nested mapping from flattened keys.
- Read immutable
Mappingimplementations without copying them first. - Preserve the concrete mutable mapping type produced by a custom factory.
- Read, write, and traverse mixed dictionaries and lists with typed paths.
- Distinguish a missing mixed path from an explicit null value.
- Preserve empty containers during generic JSON-compatible traversal.
Installation
Install the latest release from PyPI:
python -m pip install pydictnest
To install the current development version directly from GitHub:
python -m pip install git+https://github.com/MSallermann/pydictnest.git
The package supports Python 3.9 and newer.
Quick start
from pydictnest import (
flatten_dict,
get_nested,
get_path,
has_nested,
has_path,
items_nested,
items_path,
set_nested,
set_path,
unflatten_dict,
)
data = {}
set_nested(data, ["model", "parameters", "sigma"], 3.2)
set_nested(data, ["model", "parameters", "epsilon"], 0.8)
assert get_nested(data, ["model", "parameters", "sigma"]) == 3.2
assert get_nested(data, ["metadata", "label"], default="unknown") == "unknown"
assert has_nested(data, ["model", "parameters", "epsilon"])
for path, value in items_nested(data):
print(path, value)
# ["model", "parameters", "sigma"] 3.2
# ["model", "parameters", "epsilon"] 0.8
flat = flatten_dict(data)
assert flat == {
"model.parameters.sigma": 3.2,
"model.parameters.epsilon": 0.8,
}
assert unflatten_dict(flat) == data
payload = {"runs": [{"score": None}], "metadata": {}}
set_path(payload, ("runs", 1, "score"), 0.93)
assert has_path(payload, ("runs", 0, "score"))
assert get_path(payload, ("runs", 1, "score")) == 0.93
assert not has_path(payload, ("runs", 2, "score"))
assert list(items_path(payload)) == [
(("runs", 0, "score"), None),
(("runs", 1, "score"), 0.93),
(("metadata",), {}),
]
Read-only mappings
Operations that only inspect their input accept any Mapping, including
immutable mapping proxies:
from types import MappingProxyType
from pydictnest import flatten_dict, get_nested
parameters = MappingProxyType(
{
"model": MappingProxyType({"sigma": 3.2, "epsilon": 0.8}),
}
)
assert get_nested(parameters, ["model", "sigma"]) == 3.2
assert flatten_dict(parameters) == {
"model.sigma": 3.2,
"model.epsilon": 0.8,
}
set_nested and set_path require mutable containers because they modify
their inputs.
Custom output mappings
flatten_dict and unflatten_dict create regular dictionaries by default.
Pass dict_factory to select another mutable mapping type:
from collections import defaultdict
from pydictnest import flatten_dict, unflatten_dict
def mapping_factory():
return defaultdict(dict)
flat = flatten_dict(
{"model": {"sigma": 3.2}},
dict_factory=mapping_factory,
)
nested = unflatten_dict(flat, dict_factory=mapping_factory)
assert isinstance(flat, defaultdict)
assert isinstance(nested, defaultdict)
The package includes a py.typed marker. Type checkers infer dict[str, Any]
for the default output and preserve the concrete return type of a custom
factory.
API reference
set_nested(dictionary, keys, value, subdict_factory=dict)
Set value at the specified key path. Missing intermediate mappings are
created with subdict_factory. Existing non-mutable intermediate values are
replaced. An empty key path raises ValueError.
get_nested(dictionary, keys, default=None)
Return the value at a key path. If any part of the path is missing or is not a
mapping, return default. An empty key path raises ValueError.
has_nested(dictionary, keys)
Return whether the complete key path exists. An empty key path raises
ValueError.
items_nested(dictionary, subkeys=None)
Yield (path, value) pairs for every leaf node in depth-first insertion order.
Each path is returned as a list[str]. subkeys is primarily used internally
to continue a traversal from an existing path.
keys_nested(dictionary)
Yield the list[str] path of every leaf node.
values_nested(dictionary)
Yield every leaf value in depth-first insertion order.
get_path(value, path, default=None) and has_path(value, path)
Read or test a path containing string mapping keys and integer list indices.
An empty path addresses the input itself. has_path remains true for an
explicit None, allowing callers to distinguish JSON null from missing data.
set_path(container, path, value, subdict_factory=dict, list_factory=list)
Set a value using string mapping keys and non-negative integer list indices.
Missing intermediate dictionaries and lists are created based on the next path
segment. subdict_factory and list_factory control the concrete mutable
container types. Lists are extended with None when needed, and incompatible
intermediate values are replaced. An empty path raises ValueError.
items_path(value, path=(), *, include_containers=False, preserve_empty=True, max_depth=None)
Traverse mappings and lists and yield (tuple_path, value) pairs. Leaves and,
by default, empty containers are retained. Container values and depth limiting
are optional. This API is independent of the mapping-only items_nested
behavior, which remains unchanged for backward compatibility.
flatten_dict(dictionary, sep=".", dict_factory=dict)
Join each leaf path with sep and return a new flat mutable mapping. The input
is not modified. The default result is a dict; a custom dict_factory
controls the concrete output type.
unflatten_dict(dictionary, sep=".", dict_factory=dict)
Split each flat key on sep and reconstruct a nested mutable mapping. The
default result is a dict; a custom dict_factory is used for both the root
and intermediate mappings.
Flattening constraints
Keys must be strings and sep must not be empty. Because the separator is not
escaped, flatten_dict raises ValueError if any source key contains sep.
Empty nested mappings contain no leaf to emit and therefore are not preserved
by a flatten/unflatten round trip.
Choose a separator that cannot occur in the source keys when round-trip reconstruction is required.
unflatten_dict also raises ValueError for conflicting paths such as "a"
and "a.b", where one path would otherwise overwrite the other depending on
input order.
Development
Clone the repository and install it in editable mode:
git clone https://github.com/MSallermann/pydictnest.git
cd pydictnest
python -m pip install -e .
Run the runtime, typing, and lint checks with:
pytest
pyright
ruff check .
ruff format --check .
Alternatively, nox runs the test suite across the supported Python versions
available on the system and executes the Pyright session.
Contributions and bug reports are welcome through the project repository.
License
pydictnest is distributed under the MIT License. See LICENSE for
details.
Metadata
Release files for pydictnest 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pydictnest-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for pydictnest-0.3.0-py3-none-any.whl |
Release files / pydictnest-0.3.0-py3-none-any.whl
| Download URL | pydictnest-0.3.0-py3-none-any.whl |
|---|---|
| Size | 9.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c10190b5583d2e1661a923efea1585ad90e61b637a05cb57180a856ac603e69d
|
|
BLAKE2b-256 checksum How to use checksums |
96885f611ef0fb1c488560d0a2fa7684041ba1a343729aa29e8d7d25dd816500
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.
Transparency logSecurity for pydictnest 0.3.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.
Full provenance
1 file in this release has been uploaded with provenance metadata.
Attestation for pydictnest-0.3.0-py3-none-any.whl
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.
Transparency logA 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.