Skip to content

Commit 9c5478c

Browse files
feat: Experimental annotated argparse (#1666)
Adds `@with_annotated`, a type-hint-driven alternative to `@with_argparser` that builds the parser automatically from a command's signature (positional/option inference, enum/literal/path/collection handling, subcommands, groups, mutex). Marked experimental. - New module `cmd2/annotated.py` plus `Argument` / `Option` metadata classes exported from `cmd2` - Underscored param names auto-dasherize in generated flags (`dry_run` → `--dry-run`); opt out via `Option("--my_flag")` - Dedicated docs page `docs/features/annotated.md` with an experimental admonition; `argument_processing.md` keeps a short pointer - Example app `examples/annotated_example.py` and test suite in `tests/test_annotated.py`
1 parent e2c061c commit 9c5478c

8 files changed

Lines changed: 6817 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## 4.0.0 (TBD 2026)
1+
## 4.0.0 (June TBD, 2026)
22

33
### Summary
44

@@ -171,6 +171,16 @@ prompt is displayed.
171171
is enabled.
172172
- `alias` and `macro` subcommands for `create` and `delete` now output their non-essential
173173
success case output using `pfeedback`
174+
- Experimental features
175+
- New `@with_annotated` decorator, a type-hint-driven alternative to `@with_argparse` that
176+
builds the parser automatically from a command's signature (positional/option inference,
177+
enum/literal/path/collection handling, subcommands, groups, mutex). See the
178+
[annotated_example.py](https://github.com/python-cmd2/cmd2/blob/main/examples/annotated_example.py)
179+
example for demonstration of usage.
180+
- This feature allows declaring `cmd2` command parameters using type hints using syntax
181+
essentially identical to that used by [Typer](https://typer.tiangolo.com/)
182+
- You use declarative syntax to define the arguments a command takes and the
183+
`@with_annotated` decorator builds an `argparse` parser for you
174184

175185
## 3.5.1 (April 24, 2026)
176186

cmd2/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
rich_utils,
1212
string_utils,
1313
)
14+
from .annotated import with_annotated
1415
from .argparse_completer import set_default_ap_completer_type
1516
from .argparse_utils import (
1617
Cmd2ArgumentParser,
@@ -88,6 +89,7 @@
8889
"CompletionItem",
8990
"Completions",
9091
# Decorators
92+
"with_annotated",
9193
"with_argument_list",
9294
"with_argparser",
9395
"with_category",

cmd2/annotated.py

Lines changed: 2323 additions & 0 deletions
Large diffs are not rendered by default.

docs/features/annotated.md

Lines changed: 445 additions & 0 deletions
Large diffs are not rendered by default.

docs/features/argument_processing.md

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,21 @@ following for you:
1616
1. Adds the usage message from the argument parser to your command's help.
1717
1. Checks if the `-h/--help` option is present, and if so, displays the help message for the command
1818

19-
These features are all provided by the [@with_argparser][cmd2.with_argparser] decorator which is
20-
imported from `cmd2`.
19+
These features are provided by two decorators:
20+
21+
- [@with_argparser][cmd2.with_argparser] -- build parsers manually with `add_argument()` calls
22+
- [@with_annotated][cmd2.with_annotated] -- build parsers automatically from type hints
2123

2224
See the
23-
[argparse_example](https://github.com/python-cmd2/cmd2/blob/main/examples/argparse_example.py)
24-
example to learn more about how to use the various `cmd2` argument processing decorators in your
25-
`cmd2` applications.
25+
[argparse_completion](https://github.com/python-cmd2/cmd2/blob/main/examples/argparse_completion.py)
26+
and [annotated_example](https://github.com/python-cmd2/cmd2/blob/main/examples/annotated_example.py)
27+
examples to compare the two styles side by side.
2628

2729
`cmd2` provides the following [decorators](../api/decorators.md) for assisting with parsing
2830
arguments passed to commands:
2931

3032
- [cmd2.decorators.with_argparser][]
33+
- [cmd2.annotated.with_annotated][]
3134
- [cmd2.decorators.with_argument_list][]
3235

3336
All of these decorators accept an optional **preserve_quotes** argument which defaults to `False`.
@@ -52,6 +55,17 @@ stores internally. A consequence is that parsers don't need to be unique across
5255
to dynamically modify this parser at a later time, you need to retrieve this deep copy. This can
5356
be done using `self.command_parsers.get(self.do_commandname)`.
5457

58+
## with_annotated decorator
59+
60+
!!! warning "Experimental"
61+
62+
The `@with_annotated` decorator is **experimental** and its API may change in future releases.
63+
64+
The [@with_annotated][cmd2.with_annotated] decorator builds an argparse parser automatically from
65+
the decorated function's type annotations -- no manual `add_argument()` calls required. See
66+
[Annotated Argument Processing](annotated.md) for the full reference, including type mapping,
67+
metadata classes, subcommands, and stability caveats.
68+
5569
## Argument Parsing
5670

5771
For each command in the `cmd2.Cmd` subclass which requires argument parsing, create an instance of

0 commit comments

Comments
 (0)