@@ -46,19 +46,19 @@ 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 (f"Argument `{ argument_name } ` not found in { self .typed_namespace } " )
5554 # The type_conversions map may contain a function to convert the argument type
56- return self .type_conversions .get (argtype , argtype )
55+ return self .type_conversions .get (argument_type , argument_type )
5756
5857 def add_argument (
59- self , options : Sequence [str ], metavars : Sequence [str ], action : str , help : str
58+ self , arguments : Sequence [str ], metavars : Sequence [str ], action : str , help : str
6059 ) -> None :
6160 kwargs : dict [str , Any ] = {}
61+ # Sort out the metavar options first
6262 if len (metavars ) > 1 :
6363 if metavars [- 1 ] == "..." :
6464 kwargs ["metavar" ] = metavars [0 ]
@@ -70,15 +70,11 @@ def add_argument(
7070 kwargs ["metavar" ] = metavars [0 ]
7171
7272 # 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 :
73+ argument_name = arguments [- 1 ].lstrip ("-" ).replace ("-" , "_" )
74+ argument_type = self ._get_argument_type (argument_name )
75+ if argument_type and argument_type not in (bool , str ) and len (metavars ) == 1 :
76+ kwargs ["type" ] = argument_type
77+ elif argument_type is bool and not action :
8278 # default for bool, unless action or fun have been set
8379 action = "store_true"
8480
@@ -87,7 +83,7 @@ def add_argument(
8783 if help :
8884 kwargs ["help" ] = help
8985
90- self .parser .add_argument (* options , ** kwargs )
86+ self .parser .add_argument (* arguments , ** kwargs )
9187
9288
9389# usage is a multiline string of the form:
@@ -131,21 +127,29 @@ def parser(usage: str, typed_namespace: Namespace | None = None) -> ArgumentPars
131127 prog , description , arguments , epilog = (
132128 paragraph .strip () for paragraph in f"{ usage } \n \n " .split ("\n \n " , 3 )
133129 )
134- typed_parser = TypedArgumentParser (
135- ArgumentParser (prog = prog , description = description , epilog = epilog ),
136- typed_namespace ,
137- )
130+
131+ # Construct a regular argparse ArgumentParser
132+ argparser = ArgumentParser (prog = prog , description = description , epilog = epilog )
133+ # Construct a TypedArgumentParser using the regular parser and the typed_namespace
134+ typed_parser = TypedArgumentParser (argparser , typed_namespace )
138135
139136 # Process each of the arguments in the `arguments` string (one per line)
140137 for line in arguments .splitlines ():
138+ # Split the line into parts: ARGUMENTS | HELP STRING | ACTION
139+ # eg. "-i --ignore | Ignore file | T"
141140 argstr , help , action , * _ = (s .strip () for s in f"{ line } |||" .split ("|" , 3 ))
142141
143142 # 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 )
143+ # eg. "-i --input FILE" -> options = ["-i", "--input"], metavars = ["FILE"]
144+ # eg. "filename" -> options = ["filename"], metavars = []
145+ argument_names = argstr .split ()
146+ option_names = list (takewhile (lambda s : s .startswith ("-" ), argument_names ))
147+ if not option_names :
148+ # There are no options, so all words are argument names.
149+ typed_parser .add_argument (argument_names , [], action , help )
150+ else :
151+ # If an option is provided, the metavars are the rest of the words.
152+ metavars = argument_names [len (option_names ) :]
153+ typed_parser .add_argument (option_names , metavars , action , help )
150154
151155 return typed_parser .parser
0 commit comments