@@ -46,19 +46,21 @@ def __init__(self, parser: ArgumentParser, typed_namespace: Namespace | None):
4646 # `typed_namespace` may also contain a type conversion function for some types
4747 self .type_conversions = getattr (typed_namespace , "_type_conversions" , {})
4848
49- def _get_argument_type (self , name : str ) -> Any :
50- # Get the field name by replacing "-" with "_" in the last word of options
51- name = name .lstrip ("-" ).replace ("-" , "_" )
52- argtype = self .argument_types .get (name ) # Get the argument type hint
53- if not argtype :
54- raise ValueError (f"Argument `{ name } ` not found in { self .typed_namespace } " )
49+ def _get_argument_type (self , argument_name : str ) -> Any :
50+ # Get the argument type hint from the typed_namespace
51+ argument_type = self .argument_types .get (argument_name )
52+ if not argument_type :
53+ raise ValueError (
54+ f"Argument `{ argument_name } ` not found in { self .typed_namespace } "
55+ )
5556 # The type_conversions map may contain a function to convert the argument type
56- return self .type_conversions .get (argtype , argtype )
57+ return self .type_conversions .get (argument_type , argument_type )
5758
5859 def add_argument (
59- self , options : Sequence [str ], metavars : Sequence [str ], action : str , help : str
60+ self , arguments : Sequence [str ], metavars : Sequence [str ], action : str , help : str
6061 ) -> None :
6162 kwargs : dict [str , Any ] = {}
63+ # Sort out the metavar options first
6264 if len (metavars ) > 1 :
6365 if metavars [- 1 ] == "..." :
6466 kwargs ["metavar" ] = metavars [0 ]
@@ -70,15 +72,11 @@ def add_argument(
7072 kwargs ["metavar" ] = metavars [0 ]
7173
7274 # Get the type hint for the argument from the typed_namespace
73- argtype = self ._get_argument_type (options [- 1 ])
74- if (
75- argtype
76- and argtype is not bool
77- and argtype is not str
78- and len (metavars ) == 1
79- ):
80- kwargs ["type" ] = argtype
81- elif argtype is bool and not action :
75+ argument_name = arguments [- 1 ].lstrip ("-" ).replace ("-" , "_" )
76+ argument_type = self ._get_argument_type (argument_name )
77+ if argument_type and argument_type not in (bool , str ) and len (metavars ) == 1 :
78+ kwargs ["type" ] = argument_type
79+ elif argument_type is bool and not action :
8280 # default for bool, unless action or fun have been set
8381 action = "store_true"
8482
@@ -87,7 +85,7 @@ def add_argument(
8785 if help :
8886 kwargs ["help" ] = help
8987
90- self .parser .add_argument (* options , ** kwargs )
88+ self .parser .add_argument (* arguments , ** kwargs )
9189
9290
9391# usage is a multiline string of the form:
@@ -131,21 +129,29 @@ def parser(usage: str, typed_namespace: Namespace | None = None) -> ArgumentPars
131129 prog , description , arguments , epilog = (
132130 paragraph .strip () for paragraph in f"{ usage } \n \n " .split ("\n \n " , 3 )
133131 )
134- typed_parser = TypedArgumentParser (
135- ArgumentParser (prog = prog , description = description , epilog = epilog ),
136- typed_namespace ,
137- )
132+
133+ # Construct a regular argparse ArgumentParser
134+ argparser = ArgumentParser (prog = prog , description = description , epilog = epilog )
135+ # Construct a TypedArgumentParser using the regular parser and the typed_namespace
136+ typed_parser = TypedArgumentParser (argparser , typed_namespace )
138137
139138 # Process each of the arguments in the `arguments` string (one per line)
140139 for line in arguments .splitlines ():
140+ # Split the line into parts: ARGUMENTS | HELP STRING | ACTION
141+ # eg. "-i --ignore | Ignore file | T"
141142 argstr , help , action , * _ = (s .strip () for s in f"{ line } |||" .split ("|" , 3 ))
142143
143144 # options contains leading words starting with "-" if any, else all words.
144- # eg. "-i --input FILE" -> opts = ["-i", "--input"], metavars = ["FILE"]
145- # eg. "filename" -> opts = ["filename"], metavars = []
146- words = argstr .split ()
147- options = list (takewhile (lambda s : s .startswith ("-" ), words )) or words
148- metavars = words [len (options ) :] # trailing words not in options.
149- typed_parser .add_argument (options , metavars , action , help )
145+ # eg. "-i --input FILE" -> options = ["-i", "--input"], metavars = ["FILE"]
146+ # eg. "filename" -> options = ["filename"], metavars = []
147+ argument_names = argstr .split ()
148+ option_names = list (takewhile (lambda s : s .startswith ("-" ), argument_names ))
149+ if not option_names :
150+ # There are no options, so all words are argument names.
151+ typed_parser .add_argument (argument_names , [], action , help )
152+ else :
153+ # If an option is provided, the metavars are the rest of the words.
154+ metavars = argument_names [len (option_names ) :]
155+ typed_parser .add_argument (option_names , metavars , action , help )
150156
151157 return typed_parser .parser
0 commit comments