explore: drive the CLI from an argtree Cli spec#31
Draft
JPHutchins wants to merge 1 commit into
Draft
Conversation
Port camas.main.parser's hand-rolled argparse construction to a declarative argtree `Cli` NamedTuple, and consume the typed result in dispatch instead of an `Any`-typed argparse.Namespace. - parser.py: `Cli` spec built by argtree, bridged to CamasArgumentParser (custom --help) via argparse `parents=`. The dynamic per-axis flags, the state-dependent positional metavar, and the env-dependent --effects default stay imperative around the declarative core. - dispatch.py: read a typed `Cli` (reconstruct/from_namespace) rather than poking the namespace; resolve the --effects env default here. - parser.py excluded from mypyc — argtree resolves field types at runtime via get_type_hints, which mypyc erases — and argtree added to build-system requires so the compiled dispatcher's import still type-checks. Behavior unchanged: --help byte-identical, 639 tests pass, 100% coverage, all five type-checkers clean, and the mypyc wheel builds and runs end-to-end. Blocked on argtree enhancements before this is merge-ready: JPHutchins/argtree#9, JPHutchins/argtree#10, JPHutchins/argtree#11. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #31 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 54 54
Lines 5103 5116 +13
Branches 275 277 +2
=========================================
+ Hits 5103 5116 +13
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
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.
What this is
An exploration (not merge-ready — see Blockers) of replacing camas's hand-rolled
argparseparser with a declarativeargtreeClispec, and consuming the typed result in dispatch instead of anAny-typedargparse.Namespace.⛔ Blockers — resolve these argtree issues first
This PR rides on workarounds that should become first-class argtree support before merge:
parser_class=hook. camas's custom--helpneeds aCamasArgumentParsersubclass; argtree owns parser construction. Bridged here via argparse's publicparents=[...], but a real hook would drop the throwaway-parser dance.get_type_hints, which mypyc erases. Worked around by keeping the spec in an interpreted module (excluded frommypycify) + addingargtreeto[build-system] requires. A documented pattern and/or an AST fallback would make this clean.listfield breaksget_type_hintsfor a latermatrix: list[str]; renamed tolist_. A clearConfigErrorwould have saved the head-scratch.What changed
src/camas/main/parser.pyCliNamedTuple spec (one field per arg);build_parserbuilds it via argtree and adopts the actions intoCamasArgumentParserthroughparents=; newreconstruct()wrapsfrom_namespace. Excluded from mypyc.src/camas/main/dispatch.pyCliinstead of poking the namespace; resolves the env-dependent--effectsdefault here (None⇒ absent ⇒default_effects_expr(),""⇒ list Effects).setup.pyparser.pyadded to_main_excluded(mypyc).pyproject.tomlargtreeadded to runtime deps and[build-system] requires.tests/main/test_parser.pyCliviareconstructrather than the raw namespace.The declarative spec is the core; three runtime/state-dependent behaviors stay imperative around it — the dynamic per-matrix-axis
--PYflags, thetask | expressionpositional metavar, and the--effectsdefault. That "declarative core + imperative shell" shape is the honest result: argtree is great for the static surface, but camas's parser is unusually dynamic.Why bother — the payoff
The win isn't the prettier spec; it's types.
dispatchnow consumesCli(expression: str | None,dry_run: bool, …) instead of anargparse.Namespacewhere every field isAny. Under five strict type-checkers that removes a class of implicit-Anyreads.Verification (all green)
--helpoutput byte-identical to the current parserdispatch.so→ interpretedparser.py→ argtreeget_type_hints(Cli), including dynamically-added--PYaxis flagsOpen question for review
Is the typed-dispatch readability worth (a) a new runtime dependency on a 0.x library and (b)
parser.pyno longer being mypyc-compiled? Leaning yes as an experiment; not an obvious slam-dunk over the working argparse.🤖 Generated with Claude Code