grabmonkey
Dot-path access, mutation, and flattening for deeply nested dict/JSON data — with error messages that tell you exactly which level failed.
Stop writing this:
data.get("response", {}).get("results", [{}])[0].get("metadata", {}).get("created_at", "")
Write this:
from grabmonkey import grab
grab(data, "response.results[0].metadata.created_at", default="")
Install
pip install grabmonkey
Requires Python 3.11+. No runtime dependencies.
Quick start
from grabmonkey import grab, grab_many, put, delete, flatten, unflatten
data = {"response": {"results": [{"metadata": {"id": 1, "created_at": "2026"}}]}}
# Read, any depth
grab(data, "response.results[0].metadata.created_at") # "2026"
# Safe default instead of an exception
grab(data, "response.results[0].missing", default="") # ""
# Type coercion on access
grab({"count": "42"}, "count", as_type=int) # 42
# Wildcards over lists
grab({"items": [{"n": 1}, {"n": 2}]}, "items[*].n") # [1, 2]
# Batch access
grab_many(data, {"id": "response.results[0].metadata.id"}) # {"id": 1}
# Set and delete (mutates in place, creates intermediate containers)
d = {}
put(d, "a.b[2].c", 9) # {"a": {"b": [None, None, {"c": 9}]}}
delete(d, "a.b[2].c") # {"a": {"b": [None, None, {}]}}
delete(d, "a.b[2]", prune=True) # {"a": {"b": [None, None]}} (prune drops empties)
# Flatten / unflatten
flatten({"a": {"b": [1, 2]}}) # {"a.b[0]": 1, "a.b[1]": 2}
unflatten({"a.b[0]": 1, "a.b[1]": 2}) # {"a": {"b": [1, 2]}}
Clear errors
grab(data, "response.results[0].nope")
# grabmonkey.errors.PathError:
# Path 'response.results[0].nope' failed at 'nope':
# key not found in dict with keys ['metadata']
PathError (a LookupError) means a structural miss — the case default=
absorbs. PathSyntaxError means a malformed path string. CoercionError means
the value was found but as_type could not convert it. The last two are not
absorbed by default=, on purpose.
Path syntax
| Syntax | Meaning |
|---|---|
a.b.c |
dict key or object attribute |
items[0], items[-1] |
sequence index |
items[*] |
every element of a sequence / value of a mapping |
data['weird.key'] |
quoted key for keys with dots/brackets/spaces |
Works on dicts, lists, dataclasses, named tuples, and any object with attribute access. Strings and bytes are treated as leaf values, not navigable containers (see LIMITATIONS.md).
CLI
Reads JSON from a file (--input) or stdin, prints JSON:
echo '{"user":{"name":"Alice"}}' | grabmonkey grab user.name # "Alice"
echo '{"a":{"b":1}}' | grabmonkey flatten # {"a.b": 1}
grabmonkey grab metadata.id --input response.json
Using with AI assistants
See SKILL.md for an LLM-consumable reference (decision table, worked examples, anti-patterns). See LIMITATIONS.md for deliberate design tradeoffs.
Development & review
grabmonkey is tested and reviewed under a portable review kit:
- CONTRIBUTING.md — testing philosophy and the competitive multi-model review-panel process.
- LIMITATIONS.md — deliberate tradeoffs reviewers should not re-litigate (read before "fixing" surprising behaviour).
- RELEASE_READINESS.md — the release rubric; run
python scripts/readiness.pyfor the score and convergence verdict. - REVIEW_HISTORY.md — the panel-by-panel trajectory.
review-kit/— the pristine, project-agnostic templates the above were derived from (inert to the project's own checks).
pip install -e ".[dev]"
pytest -q && ruff check src tests && mypy
python scripts/readiness.py
License
MIT
Metadata
Release files for grabmonkey 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| grabmonkey-1.1.0.tar.gz | 33.0 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| grabmonkey-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 55.9 kB
Release files / grabmonkey-1.1.0.tar.gz
| Download URL | grabmonkey-1.1.0.tar.gz |
|---|---|
| Size | 33.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
26640fc4d778c3a8994377c5d818ad4fe541501c157f6aa648dede2d8482fcfd
|
|
BLAKE2b-256 checksum How to use checksums |
457023e535ba0ba4fda8f68b91116b187a81c588ec9a66a1dffce2ea3a2bf28f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / grabmonkey-1.1.0-py3-none-any.whl
| Download URL | grabmonkey-1.1.0-py3-none-any.whl |
|---|---|
| Size | 22.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
01eda7b32bf02fb05751e306d4211858e4e30d1669283126587d95bf65c4cf36
|
|
BLAKE2b-256 checksum How to use checksums |
c34756ff0408ba078667862797d975b01a6173b35bd8861d5d2b80255c8bc3f6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Security for grabmonkey 1.1.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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A 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.