Skip to main content

path-seeker

CI PyPI License: MIT

Find, count, and update keys anywhere in a nested dict or list of dicts — with full path disambiguation when the same key occurs at multiple depths.

Installation

pip install path-seeker

Usage

from path_seeker import PathSeeker

data = {
    "user": {
        "id": 1,
        "address": {"id": 42, "city": "Berlin"},
    },
    "orders": [
        {"id": 100, "status": "shipped"},
        {"id": 101, "status": "pending"},
    ],
}

seeker = PathSeeker(data)

# All values found under a key, at any depth
seeker.find_values("id")
# [1, 42, 100, 101]

# All (path, value) matches — use this to disambiguate duplicates
seeker.find_paths("id")
# [Match(path=['user', 'id'], value=1),
#  Match(path=['user', 'address', 'id'], value=42),
#  Match(path=['orders', 0, 'id'], value=100),
#  Match(path=['orders', 1, 'id'], value=101)]

# The first/last value found under a key, in traversal order
seeker.find_first_value("id")
# 1
seeker.find_last_value("id")
# 101

# The first/last (path, value) match found under a key, in traversal order
seeker.find_first_path("id")
# Match(path=['user', 'id'], value=1)
seeker.find_last_path("id")
# Match(path=['orders', 1, 'id'], value=101)

# Every distinct key name in the structure
seeker.get_keys()
# ['address', 'city', 'id', 'orders', 'status', 'user']

# How many times a key occurs
seeker.count_key("id")
# 4

# Whether a key occurs anywhere
seeker.has_key("id")
# True

# Update one exact occurrence, using a path from find_paths
seeker.set_value(["orders", 1, "status"], "cancelled")

# Update every occurrence of a key at once
seeker.update_values("id", 0)
# 4  (number of occurrences updated)

# Update just the first/last occurrence, in traversal order
seeker.update_first("id", -1)
# True
seeker.update_last("id", -2)
# True

# Delete every occurrence of a key
seeker.delete_key("status")
# 2  (number of occurrences deleted)

# Delete just the first/last occurrence, in traversal order
seeker.delete_first("id")
# True
seeker.delete_last("id")
# True

API

Method Returns Description
find_values(key) list[Any] Every value stored under key, at any depth.
find_paths(key) list[Match] Every (path, value) pair for key, at any depth.
find_first_value(key) Any The first value found under key, in traversal order. Raises UnknownKeyProvided if key doesn't occur anywhere.
find_last_value(key) Any The last value found under key, in traversal order. Raises UnknownKeyProvided if key doesn't occur anywhere.
find_first_path(key) Match The first (path, value) match found under key, in traversal order. Raises UnknownKeyProvided if key doesn't occur anywhere.
find_last_path(key) Match The last (path, value) match found under key, in traversal order. Raises UnknownKeyProvided if key doesn't occur anywhere.
get_keys() list[str] Every distinct key name in the structure, sorted.
count_key(key) int How many times key occurs.
has_key(key) bool Whether key occurs anywhere in the structure.
set_value(path, new_value) None Update the value at an exact path (from find_paths).
update_values(key, new_value) int Update every occurrence of key; returns count updated.
update_first(key, new_value) bool Update the first occurrence of key, in traversal order; False if absent.
update_last(key, new_value) bool Update the last occurrence of key, in traversal order; False if absent.
delete_key(key) int Delete every occurrence of key, at any depth; returns count deleted.
delete_first(key) bool Delete the first occurrence of key, in traversal order; False if absent.
delete_last(key) bool Delete the last occurrence of key, in traversal order; False if absent.
.data dict | list The current (possibly mutated) underlying structure.

Search is by key name, not by value — searching for a value and getting its path back is not supported yet.

find_first_*/find_last_* raise UnknownKeyProvided when key doesn't occur anywhere; update_first/update_last/delete_first/delete_last/delete_key return False/0 instead, since "the key wasn't there" is an expected outcome for a write, not an error.

Limitations

  • PathSeeker holds a reference to the structure you pass in — it does not make a defensive copy, so updates via set_value/update_values mutate your original object too.
  • Nested dicts and lists are traversed; other iterables (tuples, sets, generators) are treated as opaque values, since list-index-style paths don't make sense for them.
  • No cycle detection. This is fine for JSON/YAML-shaped data, which can't contain cycles, but a structure with a manually-introduced reference cycle will recurse forever.
  • count_key, has_key, and get_keys do a full traversal on every call — there's no indexing or caching, so repeated calls on a large structure cost proportionally more each time.

Development

make install      # uv sync --all-extras
make check        # lint + typecheck + test (what CI runs)

Individual targets: make test, make lint, make format, make typecheck.

See CONTRIBUTING.md for the full workflow.

License

MIT — see LICENSE.

Release files for path-seeker 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for path-seeker 0.4.0
File Size Uploaded
path_seeker-0.4.0.tar.gz 74.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for path-seeker 0.4.0
File Interpreter ABI Platform
path_seeker-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 80.6 kB

Release files / path_seeker-0.4.0.tar.gz

Download URL path_seeker-0.4.0.tar.gz
Size 74.5 kB
Tags Source
SHA-256 checksum
How to use checksums
566e8d6d3682d88c3ff9cc036c74d8ef83bdd15895c9495777d345229c26d4ec
BLAKE2b-256 checksum
How to use checksums
0c190dffa7c1b739eae8bafabdb9a3785b5c26dc7aa3041eb33d6c6baeb191e1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Aug 5, 2026.

Transparency log

Release files / path_seeker-0.4.0-py3-none-any.whl

Download URL path_seeker-0.4.0-py3-none-any.whl
Size 6.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
07c75c890553fb324d1e1669dd5467588194d47b4f0a279c495b47800879bcfe
BLAKE2b-256 checksum
How to use checksums
b693a7c97ff49e7c99fdcfdef8dc73fb4d336b3f225a5d3f45599fe2b76894dd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Aug 5, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page