Dict path traversal and mutation utilities
Project description
dictwalk
This library is basically overengineered and ridiculous.
It mostly exists because I kept asking an AI to add one more feature, then one more, then one more. Then I asked the AI to come up with features and I said screw it add them all. Please do not use this instead of just writing normal code.
This is bored-developer scope creep in library form. The original idea was basically “jq/yq, but for Python dicts, and here we are”. I hope you get some use out of it, because I didn't.
dictwalk is a small utility for traversing and mutating nested Python dict/list data using path expressions.
It supports:
- Deep reads (
get) - Existence checks (
exists) - In-place writes (
set) - In-place removals (
unset) - Predicate filtering for lists
- Wildcards (
*,**) - Transform/filter pipelines (
|$filter)
Requirements
- Python
>=3.10
Installation
From source:
pip install .
For local development:
uv sync
Quick Start
from dictwalk import dictwalk
data = {
"a": {
"users": [
{"id": 1, "name": "Ada", "active": True},
{"id": 2, "name": "Lin", "active": False},
]
}
}
# Read
names = dictwalk.get(data, "a.users[].name")
# ["Ada", "Lin"]
# Filter and map
active_names = dictwalk.get(data, "a.users[?active==True].name[]")
# ["Ada"]
# Write
dictwalk.set(data, "a.users[?id==2].active", True)
# Unset
dictwalk.unset(data, "a.users[?id==1].name")
Path Syntax
Dot traversal
a.b.c
Read nested object keys.
List map
a.items[].id
Apply the next token to every item in a list.
List index and slice
a.items[0]
a.items[-1]
a.items[1:3]
Predicates
a.items[?id==1]
a.items[?score>=10]
List predicates support:
==,!=,>,<,>=,<=
Predicate filters
Use registered filters on predicate values:
a.items[?id==$even]
a.items[?id==$gt(5)&&$lt(10)]
a.items[?id==!$odd]
Boolean operators in predicate filters:
&&(and)||(or)!(not)- parentheses for grouping
Wildcards
a.*.id
a.**.id
*: one level**: deep descendant traversal
Output transforms
Apply filters to the final read value:
a.value|$double|$string
a.list|$max
a.list|$double[]|$max
API
dictwalk.get(data, path, default=None, strict=False)
- Returns resolved value.
- If
strict=False: resolution failures returndefault. - If
strict=True: raisesDictWalkResolutionError.
Special root token support in read paths:
$$root.x
a.b.$$root.x
dictwalk.exists(data, path, strict=False) -> bool
- Returns
Trueif path resolves, elseFalse. - If
strict=True, raisesDictWalkResolutionErroron resolution failures.
dictwalk.set(data, path, value, *, strict=False, create_missing=True, create_filter_match=True, overwrite_incompatible=True) -> dict
Mutates and returns the same data object.
value can be:
- A direct value (
42,"x",{"k": 1}) - A filter string (
"$double","$add(2)|$string") - A root reference expression:
$$root$$root.some.path$$root.some.path|$filter
Notes:
$$rootis valid invalue, not in writepath.- With
strict=True, parent path must already resolve.
dictwalk.unset(data, path, *, strict=False) -> dict
Removes targeted values in-place and returns the same object.
At terminal paths this can:
- Remove dict keys
- Remove list indexes/slices
- Remove list items matching a filter
Filters
Built-in filters include arithmetic, string, collection, predicate, and datetime utilities.
Examples:
- Arithmetic:
$inc,$double,$add(2),$round(1) - Collection:
$len,$max,$min,$sum,$avg,$unique - String:
$lower,$upper,$replace("a","b"),$split(",") - Predicates:
$even,$odd,$gt(10),$contains("x") - Datetime:
$to_datetime,$timestamp,$age_seconds,$before(...),$after(...)
Register custom filters:
from dictwalk import dictwalk
dictwalk.register_path_filter("triple", lambda x: x * 3)
value = dictwalk.get({"a": {"b": 2}}, "a.b|$triple")
# 6
Errors
From dictwalk.errors:
DictWalkError(base)DictWalkParseErrorDictWalkOperatorErrorDictWalkResolutionError
Use strict=True when you want explicit failures instead of fallback defaults.
Development
Run tests:
make test
Run lint/type/dependency checks:
make lint
make type
make deptry
Run everything:
make ci
Direct tox usage:
uv run tox -e py310,py311,py312,py313,py314,lint,type,deptry
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 dictwalk-0.1.0.tar.gz.
File metadata
- Download URL: dictwalk-0.1.0.tar.gz
- Upload date:
- Size: 34.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9172367243b2628bbc9e4610429edf664bc0b715a42de750f8a369b8bc764a80
|
|
| MD5 |
4a671f0c3523ba76c3407a65cb281c8c
|
|
| BLAKE2b-256 |
2b0a5cae988afa9d8cece1413d49cfdfe6aeb9ddfd1b6a431c2e40514231038a
|
File details
Details for the file dictwalk-0.1.0-py3-none-any.whl.
File metadata
- Download URL: dictwalk-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
77ac5d480e36b3307f931289712113027b5fc77a436bc6c84fd92c92a7086cb8
|
|
| MD5 |
1f282745a7e26f82c0843b0621aa7c48
|
|
| BLAKE2b-256 |
cac660118b724be70aecff1b63ad80e6a09311fc6a9cd3f47b1004903a483992
|