@@ -31,9 +31,10 @@ The two decorators are interchangeable -- here is the same command written both
3131
3232 ```py
3333 parser = Cmd2ArgumentParser()
34- parser.add_argument('name', help='person to greet')
35- parser.add_argument('--count', type=int, default=1, help='repetitions')
36- parser.add_argument('--loud', action='store_true', help='shout')
34+ parser.add_argument("name", help="person to greet")
35+ parser.add_argument("--count", type=int, default=1, help="repetitions")
36+ parser.add_argument("--loud", action="store_true", help="shout")
37+
3738
3839 @with_argparser(parser)
3940 def do_greet(self, args):
@@ -61,6 +62,7 @@ Underscores in parameter names are converted to dashes in the generated flag, so
6162``` py
6263from cmd2.annotated import with_annotated
6364
65+
6466class MyApp (cmd2 .Cmd ):
6567 @with_annotated
6668 def do_greet (self , name : str , count : int = 1 , loud : bool = False ):
@@ -132,22 +134,30 @@ For finer control, use `typing.Annotated` with [Argument][cmd2.annotated.Argumen
132134from typing import Annotated
133135from cmd2.annotated import Argument, Option, with_annotated
134136
137+
135138class MyApp (cmd2 .Cmd ):
136139 def sport_choices (self ) -> cmd2.Choices:
137140 return cmd2.Choices.from_values([" football" , " basketball" ])
138141
139142 @with_annotated
140143 def do_play (
141144 self ,
142- sport : Annotated[str , Argument(
143- choices_provider = sport_choices,
144- help_text = " Sport to play" ,
145- )],
146- venue : Annotated[str , Option(
147- " --venue" , " -v" ,
148- help_text = " Where to play" ,
149- completer = cmd2.Cmd.path_complete,
150- )] = " home" ,
145+ sport : Annotated[
146+ str ,
147+ Argument(
148+ choices_provider = sport_choices,
149+ help_text = " Sport to play" ,
150+ ),
151+ ],
152+ venue : Annotated[
153+ str ,
154+ Option(
155+ " --venue" ,
156+ " -v" ,
157+ help_text = " Where to play" ,
158+ completer = cmd2.Cmd.path_complete,
159+ ),
160+ ] = " home" ,
151161 ):
152162 self .poutput(f " Playing { sport} at { venue} " )
153163```
@@ -173,6 +183,7 @@ import enum
173183from typing import Annotated
174184from cmd2.annotated import Argument, with_annotated
175185
186+
176187class Color (enum .Enum ):
177188 red = " red"
178189 green = " green"
@@ -183,6 +194,7 @@ class Color(enum.Enum):
183194 # map a special keyword onto a real member; return None to reject
184195 return cls .red if str (value).lower() == " auto" else None
185196
197+
186198class MyApp (cmd2 .Cmd ):
187199 @with_annotated
188200 def do_theme (self , choice : Annotated[Color, Argument(allow_unknown_entry = True )]) -> None :
@@ -265,6 +277,7 @@ class UpperAction(argparse.Action):
265277 def __call__ (self , parser , namespace , values , option_string = None ):
266278 setattr (namespace, self .dest, values.upper())
267279
280+
268281@with_annotated
269282def do_shout (self , name : Annotated[str , Option(" --name" , action = UpperAction)] = " " ):
270283 self .poutput(name)
@@ -298,6 +311,7 @@ forms are equivalent:
298311# Signature default
299312def do_x (self , name : Annotated[str , Option(" --name" )] = " HI" ): ...
300313
314+
301315# Metadata default (same behaviour)
302316def do_x (self , name : Annotated[str , Option(" --name" , default = " HI" )]): ...
303317```
@@ -359,11 +373,13 @@ import datetime
359373from typing import Annotated
360374from cmd2.annotated import Argument, Option, with_annotated
361375
376+
362377def parse_size (value : str ) -> int :
363378 """ Parse an integer with an optional K/M/G suffix."""
364379 multiplier = {" K" : 1_000 , " M" : 1_000_000 , " G" : 1_000_000_000 }.get(value[- 1 :].upper(), 1 )
365380 return int (value[:- 1 ] if multiplier != 1 else value) * multiplier
366381
382+
367383class MyApp (cmd2 .Cmd ):
368384 @with_annotated
369385 def do_alloc (self , size : Annotated[int , Argument(converter = parse_size)]) -> None :
@@ -382,9 +398,11 @@ instead infer `nargs` and split the input across several tokens:
382398``` py
383399from typing import Annotated, Any
384400
401+
385402def parse_intset (value : str ) -> set[int ]:
386403 return {int (piece) for piece in value.split(" ," )}
387404
405+
388406@with_annotated
389407def do_select (self , idx : Annotated[Any, Option(" --idx" , converter = parse_intset)]) -> None :
390408 self .poutput(sorted (idx)) # `select --idx 1,3,5` -> [1, 3, 5]
@@ -404,6 +422,7 @@ import os
404422from typing import Annotated
405423from cmd2.annotated import Argument, with_annotated
406424
425+
407426class MyApp (cmd2 .Cmd ):
408427 @with_annotated
409428 def do_tag (self , color : Annotated[Color, Argument(preprocess = str .lower)]) -> None :
@@ -486,6 +505,7 @@ and `description` for a titled help section (omit them for an untitled group):
486505``` py
487506from cmd2.annotated import Group, with_annotated
488507
508+
489509class App (cmd2 .Cmd ):
490510 @with_annotated (
491511 description = " Open a network connection." ,
@@ -509,6 +529,8 @@ def do_greet(self, name: str):
509529 :param name: who to greet
510530 """
511531 self .poutput(f " hello { name} " )
532+
533+
512534# parser.description == "Greet someone by name."
513535```
514536
@@ -532,9 +554,7 @@ choice reads as `[--json | --csv]` instead of expanding to `--json`/`--no-json`
532554
533555``` py
534556@with_annotated (
535- mutually_exclusive_groups = (
536- Group(" json" , " csv" , title = " output" , description = " how to write results" ),
537- ),
557+ mutually_exclusive_groups = (Group(" json" , " csv" , title = " output" , description = " how to write results" ),),
538558)
539559def do_render (
540560 self ,
@@ -560,6 +580,7 @@ class Conn(ArgumentBlock):
560580 host: Annotated[str , Option(" --host" )] = " localhost"
561581 port: Annotated[int , Option(" --port" )] = 8080
562582
583+
563584@with_annotated (groups = (Group(" host" , " port" , title = " connection" ),))
564585def do_connect (self , conn : Conn) -> None : ...
565586```
@@ -611,6 +632,7 @@ def do_manage(self, *, cmd2_subcommand_func):
611632 if cmd2_subcommand_func:
612633 cmd2_subcommand_func()
613634
635+
614636@with_annotated (subcommand_to = " manage" , help = " list projects" )
615637def manage_list (self ):
616638 self .poutput(" listing" )
@@ -626,6 +648,7 @@ def manage_project(self, *, cmd2_subcommand_func):
626648 if cmd2_subcommand_func:
627649 cmd2_subcommand_func()
628650
651+
629652@with_annotated (subcommand_to = " manage project" , help = " add a project" )
630653def manage_project_add (self , name : str ):
631654 self .poutput(f " added { name} " )
@@ -770,9 +793,11 @@ decorator, it skips the first parameter as the method receiver (`self`/`cls`).
770793``` py
771794from cmd2.annotated import build_parser_from_function
772795
796+
773797def greet (self , name : str , count : int = 1 ):
774798 """ Greet someone."""
775799
800+
776801parser = build_parser_from_function(greet)
777802namespace = parser.parse_args([" Alice" , " --count" , " 3" ])
778803# namespace.name == "Alice", namespace.count == 3
0 commit comments