Refactor arglite to use explicit flag declarations instead of source-code reflection - #5
Merged
Conversation
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
This PR replaces arglite's fragile source-code reflection approach with a small, explicit declaration API. The old parser flattened
sys.argvinto a string and regex-scanned the caller's source file to determine which flags were required or optional. That approach broke on aliases, dynamic access,from arglite import parser, and any non-trivial code structure.The new implementation parses
sys.argvdirectly as tokens, requires users to declare their flags explicitly, and handles the edge cases that were previously broken.New API
parser.require(name, short=None, type=None)parser.optional(name, short=None, default=None, type=None)parser.flag(name, short=None)If
shortis omitted, the first letter of the flag name is used automatically as a short alias (e.g.--namecan also be-n). Flags are accessed directly on the parser instance, not throughparser.required/parser.optionalnamespaces.Edge cases now handled
--flag value,--flag=value,-f value, and-f=value--name ""--offset -5--verbose=falseast.literal_evalfor structured literals when no explicit type is givenFiles changed
src/arglite/arglite.py—Parserorchestrates declarations, validation, and lazy accesssrc/arglite/flag.py—Flagdescriptor, value conversion, and boolean normalizationsrc/arglite/parse.py— statelesstokenize(argv, flags)functionsrc/arglite/help.py— Rich help table renderingsrc/arglite/exceptions.py—ParseErrorandRequirementErrorsrc/arglite/__init__.py— updated exportssrc/arglite/code.py— deletedsrc/arglite/argument.py— deletedpyproject.toml— removedvurzeand runtimetwine; addedrequires-pythonand dev dependenciesREADME.md— rewritten for the new API.github/workflows/main.yml— replacedvurzechecks withpytesttests/conftest.py— sharedparserfixturetests/test_flag.py— tests forFlagconversiontests/test_parse.py— tests for tokenizationtests/test_parser.py— tests forParserorchestrationtests/test_help.py— tests for help outputTesting
All 69 tests pass. The package also builds cleanly with
uv build.Breaking changes
This is a major API change. Existing code that relied on
parser.required.foo,parser.optional.foo, or implicit reflection will need to be updated to declare flags explicitly and access them asparser.foo.