Repository navigation
Add public tree read/match/transform utilities - #43
Merged
Merged
Conversation
Add confingy.tree with get_init_args, is_fingy_of, walk_fingy, map_fingy, and replace_args, so callers can inspect and rewrite nested configs without reading or mutating _tracked_info. map_fingy rebuilds nodes through update() only when a child changed, so untouched subtrees keep their identity, laziness is preserved, and shared nodes are transformed once and stay shared. lens() and unlens() now memoise by id, so shared objects stay shared, and unlens() returns the original object for nodes that were not modified. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The validation model used pydantic's default extra="ignore", so unknown kwargs passed to Cls.lazy(), lazy(), or update() on a Lazy were silently accepted and only failed at instantiate(). Forbid extras unless __init__ accepts **kwargs. When an untracked subclass overrides a tracked base's __init__, the base wrapper now checks only the arguments the base declares, since init_kwargs follow the subclass signature. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
| Commit | Scanned at | New | Resolved | Net |
|---|---|---|---|---|
7d0f80e < |
2026-09-29 21:14 UTC | 0 | 0 | 0 |
Last scanned: 7d0f80e · 2026-09-29 21:14 UTC
|
| Commit | Scanned at | New | Resolved | Net |
|---|---|---|---|---|
7d0f80e |
2026-09-29 21:14 UTC | — | — | — |
7d0f80e < |
2026-09-29 21:14 UTC | 0 | 0 | 0 |
Last scanned: 7d0f80e · 2026-09-29 21:14 UTC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Changing "every
Xin this config" currently means writing a recursive walk that reads, and often mutates, the privateobj._tracked_info["init_args"]. Mutating in place is fragile: the live attributes and the recorded init args (which serialization reads) can drift apart. confingy has no public way to do this safely, so this PR adds one.New
confingy.treemodule (exported fromconfingy)get_init_args(node)is_fingy_of(obj, cls)clsor a subclass, including the subclasses created bytrack(cls)walk_fingy(obj)(path, node)for each tracked/lazy node, e.g."entries['a'].steps[0]"; shared nodes are yielded oncemap_fingy(obj, fn)replace_args(obj, cls, **args)map_fingy+update()on every matching node; returns(new_obj, n_rebuilt)What
map_fingyguarantees:update(), so attributes and recorded config can't drift apart.map_fingy(x, identity) is x.OrderedDict/defaultdict), sets and dataclasses.ValueError. Nodes created withtrack(existing_instance)record attributes rather than constructor args, so they raise aValueErrornaming their path if one needs rebuilding.Why not the existing helpers?
is_lazy_version_ofcompares classes with==.track(T)creates a new subclass on every call, so it never matcheslazy(track(T))(...)orlens(track(T)(...)). It is left unchanged, with a docstring note pointing tois_fingy_of.update()rebuilds a single node, so the caller still has to find it and rebuild every ancestor.lens()/unlens()split shared objects into copies and rebuilt every node.lens()/unlens()changesunlens().unlens()returns the original object for nodes that weren't modified afterlens(), and rebuilds only modified nodes and their ancestors. Behaviour change:lens(obj).unlens()with no edits now returnsobjitself rather than an equal copy.Unknown constructor arguments are now rejected up front
Previously the validation model silently ignored unknown kwargs, so a typo in
Foo.lazy(...),lazy(Foo)(...), orupdate(lazy_obj)(...)was accepted and only failed atinstantiate(), andreplace_argsinherited that. The model now forbids extra arguments unless__init__accepts**kwargs, so all of these raiseValidationErrorimmediately.track(Foo)(typo=1)andupdate(tracked)(typo=1)now raiseValidationErrorinstead ofTypeError. This matches how invalid values already fail.__init__, the base's wrapper checks only the arguments the base declares, so subclasses that pass a narrower set tosuper().__init__()keep working.strictbefore constructing.disable_validation()still skips the check.Other changes
track(existing_instance)now records"from_instance": Truein_tracked_info. Serialization ignores this key.confingy.utils.containershelpers are shared bytree.pyandunlens().confingy.treeandconfingy.utils.containers.Notes
__post_config__. This is documented.Test plan
pytest: 347 passed, including 34 new tests intests/test_tree.pyand 5 inTestUnknownArgumentsruff check,ruff format --checkmypy -p confingymkdocs build --strict🤖 Generated with Claude Code