glom
glom is a declarative nested-data toolkit for Python. A spec can retrieve a deep path, reshape dictionaries and lists, call transformations, provide fallbacks, filter or reduce collections, validate structures, mutate paths, and recurse through known tree shapes. Its main promise is that a reusable spec describes what output should look like while PathAccessError and related exceptions show where a nested lookup failed.
glom earns its dependency when nested transformations recur and deserve named, tested specifications. For a handful of direct lookups, plain Python stays easier to read, type-check, profile, and debug.
Use it if
- You repeatedly reshape nested API payloads into a stable application-facing structure
- You want deep-path errors that identify the failed segment instead of a generic KeyError or TypeError
- You need reusable transformations combining access, mapping, filtering, defaults, validation, and construction
- You want to prototype a transformation at the command line and move the same spec into Python
- The transformation is two or three obvious Python expressions; a glom spec introduces a second notation that may be harder for the next maintainer
- Specs will come from untrusted users; specs can contain callables, method calls, mutation, and custom spec types, so they are executable behavior rather than a safe query language
- You need a portable validation contract shared with other languages; Match and Check are Python constructs, not a JSON Schema or OpenAPI replacement
- You need automatic traversal of an arbitrary unknown tree; the project's snippets explicitly say glom does not provide full tree traversal and recommend remap for that case
- A hot loop needs the lowest possible overhead; declarative dispatch, scope handling, path interpretation, and rich error construction cost more than direct indexing and comprehensions
Setup reality
`pip install glom` installs a pure-Python package plus boltons, attrs, and face; there are no native builds or service credentials. The same install exposes a `glom` command that reads JSON by default and accepts Python, TOML, or YAML formats, but TOML on older Python and YAML require the documented optional extras. The real setup cost is teaching the spec language. Strings such as `a.b.c` are parsed as paths, dictionaries build output dictionaries, one-item lists map over an iterable, tuples run stages in series, callables execute against the current target, and `T`, `S`, `A`, `M`, `Coalesce`, `Iter`, `Match`, `Check`, `Call`, and `Ref` each alter evaluation. Literal keys containing dots need an explicit `Path` or `T[...]` expression. Missing data raises detailed exceptions unless the spec supplies a default or fallback; broad defaults can hide malformed upstream payloads, so catch only expected absence. Ordinary transformation is non-mutating, while `assign()` and `delete()` deliberately change the target unless you copy it first. A spec can call arbitrary Python and custom classes can implement `glomit`, so do not deserialize and run specs from an untrusted boundary. For a team, keep named specs close to representative input and output tests, and stop expanding the DSL when a normal function is clearer. The CLI is useful for experiments, but shell quoting complex Python specs becomes brittle quickly.
Patterns
Read a nested path with a useful errorget-nested-value
from glom import glom
data = {'account': {'profile': {'name': 'Ada'}}}
name = glom(data, 'account.profile.name')A missing segment raises PathAccessError identifying its location. Use a default only when absence is expected rather than malformed input.
Use a fallback for missing alternativesprovide-default
from glom import Coalesce, glom
email = glom(
user,
Coalesce('contact.primary_email', 'contact.backup_email', default=None),
)Coalesce tries specs in order. A final default suppresses missing-path errors, so distinguish optional fields from required ones.
Reshape a nested recordreshape-object
from glom import Coalesce, glom
spec = {
'id': 'user.id',
'display_name': 'user.profile.name',
'city': Coalesce('user.address.city', default='Unknown'),
}
result = glom(payload, spec)Dictionary keys in a spec are output keys; dictionary values are evaluated against the same current target.
Transform every item in a nested listmap-nested-list
from glom import glom
spec = ('orders', [{
'number': 'id',
'total': ('amount_cents', lambda cents: cents / 100),
}])
orders = glom(payload, spec)A one-item list maps its inner spec across the iterable. A tuple runs stages from left to right.
Handle literal keys and computed values with Tuse-target-expression
from glom import T, glom
data = {'a.b': 4, 'tax': 0.2}
result = glom(data, {
'raw': T['a.b'],
'with_tax': T['a.b'] * (1 + T['tax']),
})A string containing dots is treated as a path. Use `T['a.b']` when the dot is part of the literal key.
Filter mapped items with SKIPfilter-items
from glom import SKIP, glom
active_ids = glom(
users,
[lambda user: user['id'] if user.get('active') else SKIP],
)Returning SKIP removes the current item from list output. A regular `None` would remain in the result.
Validate record shapes with Matchvalidate-structure
from glom import Match, glom
spec = Match([{'id': int, 'email': str, object: object}])
validated = glom(records, spec)Literal dictionary keys are required by default here, while `object: object` permits additional keys. A mismatch raises a MatchError family exception.
Assign a value at a deep pathassign-deep-value
from glom import assign
record = {'profile': {'name': 'Old'}}
assign(record, 'profile.name', 'Ada')
assert record['profile']['name'] == 'Ada'`assign` mutates its target. Copy shared input first when callers expect transformation without side effects.
Delete a nested keydelete-deep-value
from glom import delete
record = {'user': {'name': 'Ada', 'temporary': True}}
delete(record, 'user.temporary')Deletion is in place and raises PathDeleteError when traversal or deletion fails.
Flatten one level of nested iterablesflatten-results
from glom import Flatten, glom
values = glom([[1, 2], [3], [], [4, 5]], Flatten())
assert values == [1, 2, 3, 4, 5]Flatten is a reduction specifier, not an arbitrary recursive tree walker. Repeated or recursive flattening needs an explicit design.
Construct an object with Callcall-constructor
from collections import deque
from glom import Call, T, glom
queue = glom([1, 2, 3], Call(deque, args=[T, 10]))
assert queue.maxlen == 10Call executes Python code and can accept positional and keyword specs. Never treat arbitrary Call-bearing specs as untrusted data.
Prototype a path query at the command linequery-from-cli
glom 'users.0.profile.name' '{"users":[{"profile":{"name":"Ada"}}]}'The CLI defaults to JSON input and Python-like specs. Complex specs are usually easier to keep in files than to quote through a shell.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| jmespath | PyPI | You need a portable, read-only JSON query language with implementations in several languages |
| jsonpath-ng | PyPI | You specifically want JSONPath selection and updates rather than Python-shaped restructuring specs |
| dpath | PyPI | You mainly need glob-like search, get, set, and merge operations on nested dictionaries |