Skip to main content

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 return default.
  • If strict=True: raises DictWalkResolutionError.

Special root token support in read paths:

$$root.x
a.b.$$root.x

dictwalk.exists(data, path, strict=False) -> bool

  • Returns True if path resolves, else False.
  • If strict=True, raises DictWalkResolutionError on 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:

  • $$root is valid in value, not in write path.
  • 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)
  • DictWalkParseError
  • DictWalkOperatorError
  • DictWalkResolutionError

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dictwalk-0.1.0.tar.gz (34.9 kB view details)

Uploaded Source

Built Distribution

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

dictwalk-0.1.0-py3-none-any.whl (13.7 kB view details)

Uploaded Python 3

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

Hashes for dictwalk-0.1.0.tar.gz
Algorithm Hash digest
SHA256 9172367243b2628bbc9e4610429edf664bc0b715a42de750f8a369b8bc764a80
MD5 4a671f0c3523ba76c3407a65cb281c8c
BLAKE2b-256 2b0a5cae988afa9d8cece1413d49cfdfe6aeb9ddfd1b6a431c2e40514231038a

See more details on using hashes here.

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

Hashes for dictwalk-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 77ac5d480e36b3307f931289712113027b5fc77a436bc6c84fd92c92a7086cb8
MD5 1f282745a7e26f82c0843b0621aa7c48
BLAKE2b-256 cac660118b724be70aecff1b63ad80e6a09311fc6a9cd3f47b1004903a483992

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