@@ -172,7 +172,10 @@ def with_argparser_and_unknown_args(parser: argparse.ArgumentParser, *,
172172 ns_provider : Optional [Callable [..., argparse .Namespace ]] = None ,
173173 preserve_quotes : bool = False ) -> \
174174 Callable [[argparse .Namespace , List ], Optional [bool ]]:
175- """A decorator to alter a cmd2 method to populate its ``args`` argument by parsing
175+ """
176+ Deprecated decorator. Use `with_argparser(parser, with_unknown_args=True)` instead.
177+
178+ A decorator to alter a cmd2 method to populate its ``args`` argument by parsing
176179 arguments with the given instance of argparse.ArgumentParser, but also returning
177180 unknown args as a list.
178181
@@ -194,77 +197,23 @@ def with_argparser_and_unknown_args(parser: argparse.ArgumentParser, *,
194197 >>> parser.add_argument('-r', '--repeat', type=int, help='output [n] times')
195198 >>>
196199 >>> class MyApp(cmd2.Cmd):
197- >>> @cmd2.with_argparser_and_unknown_args (parser)
200+ >>> @cmd2.with_argparser (parser, with_unknown_args=True )
198201 >>> def do_argprint(self, args, unknown):
199202 >>> "Print the options and argument list this options command was called with."
200203 >>> self.poutput('args: {!r}'.format(args))
201204 >>> self.poutput('unknowns: {}'.format(unknown))
202205 """
203- import functools
204-
205- def arg_decorator (func : Callable ):
206- @functools .wraps (func )
207- def cmd_wrapper (* args : Tuple [Any , ...], ** kwargs : Dict [str , Any ]) -> Optional [bool ]:
208- """
209- Command function wrapper which translates command line into argparse Namespace and calls actual
210- command function
211-
212- :param args: All positional arguments to this function. We're expecting there to be:
213- cmd2_app, statement: Union[Statement, str]
214- contiguously somewhere in the list
215- :param kwargs: any keyword arguments being passed to command function
216- :return: return value of command function
217- :raises: Cmd2ArgparseError if argparse has error parsing command line
218- """
219- cmd2_app , statement = _parse_positionals (args )
220- statement , parsed_arglist = cmd2_app .statement_parser .get_command_arg_list (command_name ,
221- statement ,
222- preserve_quotes )
223-
224- if ns_provider is None :
225- namespace = None
226- else :
227- namespace = ns_provider (cmd2_app )
228-
229- try :
230- ns , unknown = parser .parse_known_args (parsed_arglist , namespace )
231- except SystemExit :
232- raise Cmd2ArgparseError
233- else :
234- setattr (ns , '__statement__' , statement )
206+ import warnings
207+ warnings .warn ('This decorator will be deprecated. Use `with_argparser(parser, with_unknown_args=True)`.' ,
208+ PendingDeprecationWarning , stacklevel = 2 )
235209
236- def get_handler (self : argparse .Namespace ) -> Optional [Callable ]:
237- return getattr (self , constants .SUBCMD_HANDLER , None )
238-
239- setattr (ns , 'get_handler' , types .MethodType (get_handler , ns ))
240-
241- args_list = _arg_swap (args , statement , ns , unknown )
242- return func (* args_list , ** kwargs )
243-
244- # argparser defaults the program name to sys.argv[0], but we want it to be the name of our command
245- command_name = func .__name__ [len (constants .COMMAND_FUNC_PREFIX ):]
246- _set_parser_prog (parser , command_name )
247-
248- # If the description has not been set, then use the method docstring if one exists
249- if parser .description is None and func .__doc__ :
250- parser .description = func .__doc__
251-
252- # Set the command's help text as argparser.description (which can be None)
253- cmd_wrapper .__doc__ = parser .description
254-
255- # Set some custom attributes for this command
256- setattr (cmd_wrapper , constants .CMD_ATTR_ARGPARSER , parser )
257- setattr (cmd_wrapper , constants .CMD_ATTR_PRESERVE_QUOTES , preserve_quotes )
258-
259- return cmd_wrapper
260-
261- # noinspection PyTypeChecker
262- return arg_decorator
210+ return with_argparser (parser , ns_provider = ns_provider , preserve_quotes = preserve_quotes , with_unknown_args = True )
263211
264212
265213def with_argparser (parser : argparse .ArgumentParser , * ,
266214 ns_provider : Optional [Callable [..., argparse .Namespace ]] = None ,
267- preserve_quotes : bool = False ) -> Callable [[argparse .Namespace ], Optional [bool ]]:
215+ preserve_quotes : bool = False ,
216+ with_unknown_args : bool = False ) -> Callable [[argparse .Namespace ], Optional [bool ]]:
268217 """A decorator to alter a cmd2 method to populate its ``args`` argument by parsing arguments
269218 with the given instance of argparse.ArgumentParser.
270219
@@ -273,6 +222,7 @@ def with_argparser(parser: argparse.ArgumentParser, *,
273222 argparse.Namespace. This is useful if the Namespace needs to be prepopulated with
274223 state data that affects parsing.
275224 :param preserve_quotes: if True, then arguments passed to argparse maintain their quotes
225+ :param with_unknown_args: if true, then capture unknown args
276226 :return: function that gets passed the argparse-parsed args in a Namespace
277227 A member called __statement__ is added to the Namespace to provide command functions access to the
278228 Statement object. This can be useful if the command function needs to know the command line.
@@ -290,6 +240,21 @@ def with_argparser(parser: argparse.ArgumentParser, *,
290240 >>> def do_argprint(self, args):
291241 >>> "Print the options and argument list this options command was called with."
292242 >>> self.poutput('args: {!r}'.format(args))
243+
244+ :Example with unknown args:
245+
246+ >>> parser = argparse.ArgumentParser()
247+ >>> parser.add_argument('-p', '--piglatin', action='store_true', help='atinLay')
248+ >>> parser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE')
249+ >>> parser.add_argument('-r', '--repeat', type=int, help='output [n] times')
250+ >>>
251+ >>> class MyApp(cmd2.Cmd):
252+ >>> @cmd2.with_argparser(parser, with_unknown_args=True)
253+ >>> def do_argprint(self, args, unknown):
254+ >>> "Print the options and argument list this options command was called with."
255+ >>> self.poutput('args: {!r}'.format(args))
256+ >>> self.poutput('unknowns: {}'.format(unknown))
257+
293258 """
294259 import functools
295260
@@ -318,7 +283,11 @@ def cmd_wrapper(*args: Any, **kwargs: Dict[str, Any]) -> Optional[bool]:
318283 namespace = ns_provider (cmd2_app )
319284
320285 try :
321- ns = parser .parse_args (parsed_arglist , namespace )
286+ if with_unknown_args :
287+ new_args = parser .parse_known_args (parsed_arglist , namespace )
288+ else :
289+ new_args = (parser .parse_args (parsed_arglist , namespace ), )
290+ ns = new_args [0 ]
322291 except SystemExit :
323292 raise Cmd2ArgparseError
324293 else :
@@ -329,7 +298,7 @@ def get_handler(self: argparse.Namespace) -> Optional[Callable]:
329298
330299 setattr (ns , 'get_handler' , types .MethodType (get_handler , ns ))
331300
332- args_list = _arg_swap (args , statement , ns )
301+ args_list = _arg_swap (args , statement , * new_args )
333302 return func (* args_list , ** kwargs )
334303
335304 # argparser defaults the program name to sys.argv[0], but we want it to be the name of our command
0 commit comments