Skip to content

Fix Argument typing, modernize to 3.10+, reserve internal attr names#46

Merged
mosquito merged 2 commits into
masterfrom
modernize-typing-and-reserved-names
Jun 12, 2026
Merged

Fix Argument typing, modernize to 3.10+, reserve internal attr names#46
mosquito merged 2 commits into
masterfrom
modernize-typing-and-reserved-names

Conversation

@mosquito

Copy link
Copy Markdown
Owner

Summary

Three related typing/quality improvements:

  1. Argument() no longer infers as Any. The fallback overload now
    returns a bare TypeVar, so annotated attributes adopt their declared
    type — tags: list[str] = Argument(nargs="+") infers list[str]
    silencing basedpyright's reportAny on the common untyped form.

  2. Modernized the library to PEP 604/585 (3.10+): Optional[X]X | None,
    Union|, List/Dict/Tuple/Type → builtins, typing.Callable
    /Iterable/Mappingcollections.abc. Enabled ruff's UP rules.
    Tests are exempt (they intentionally exercise legacy typing forms to
    verify backward compatibility).

  3. Reserved internal attribute names. current_subparsers,
    current_subparser, and __parent__ now raise ArgumentDefinitionError
    when used as user argument/group/subparser names, instead of silently
    clobbering parser state. This let the load-bearing type-comment on
    AbstractParser.current_subparsers become a normal annotation.

Tests & docs

  • New tests/test_reserved_names.py (10 tests).
  • Documented reserved names in docs/subparsers.md + a pitfalls.md cross-reference.

Verification

  • ruff check clean, ruff format clean.
  • mypy clean (only the pre-existing tomllib stdlib-stub baseline).
  • 655 tests pass; doc code blocks pass; Sphinx builds without warnings.

mosquito added 2 commits June 12, 2026 23:22
Three related typing/quality improvements:

1. Argument() no longer infers as Any. The fallback overload now returns
   a bare TypeVar so annotated attributes adopt their declared type
   (e.g. `tags: list[str] = Argument(nargs="+")` infers `list[str]`),
   silencing basedpyright's reportAny on the common untyped form.

2. Modernize the library to PEP 604/585 (3.10+): Optional[X] -> X | None,
   Union -> |, List/Dict/Tuple/Type -> builtins, typing.Callable/Iterable
   /Mapping -> collections.abc. Enabled ruff's UP rules (tests are exempt
   since they intentionally exercise legacy typing forms).

3. Reserve internal attribute names. current_subparsers,
   current_subparser, and __parent__ now raise ArgumentDefinitionError
   when used as user argument/group/subparser names, instead of silently
   clobbering parser state. This let the load-bearing type-comment on
   AbstractParser.current_subparsers become a normal annotation.

Adds tests/test_reserved_names.py and documents the reserved names in
docs/subparsers.md (+ a pitfalls.md cross-reference).
- store.py: bare type[Action]/type[ConfigAction] annotations collided
  with the TypedArgument.type field in the class annotation scope under
  PEP 649 lazy evaluation, breaking every Parser on 3.14. Qualify as
  builtins.type (Type[...] would just be reverted by ruff UP006).
- Reserved-name guard: cls.__dict__['__annotations__'] is absent on 3.14
  (lazy), so own_annotation_keys() falls back to annotationlib in
  FORWARDREF format to read a class's own annotation keys.
- ruff format tests/test_edge_cases.py (pre-existing drift CI flags).
@mosquito mosquito merged commit b4d7f01 into master Jun 12, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant