@@ -172,7 +172,10 @@ def with_argparser_and_unknown_args(parser: argparse.ArgumentParser, *,
172
172
ns_provider : Optional [Callable [..., argparse .Namespace ]] = None ,
173
173
preserve_quotes : bool = False ) -> \
174
174
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
176
179
arguments with the given instance of argparse.ArgumentParser, but also returning
177
180
unknown args as a list.
178
181
@@ -194,77 +197,23 @@ def with_argparser_and_unknown_args(parser: argparse.ArgumentParser, *,
194
197
>>> parser.add_argument('-r', '--repeat', type=int, help='output [n] times')
195
198
>>>
196
199
>>> class MyApp(cmd2.Cmd):
197
- >>> @cmd2.with_argparser_and_unknown_args (parser)
200
+ >>> @cmd2.with_argparser (parser, with_unknown_args=True )
198
201
>>> def do_argprint(self, args, unknown):
199
202
>>> "Print the options and argument list this options command was called with."
200
203
>>> self.poutput('args: {!r}'.format(args))
201
204
>>> self.poutput('unknowns: {}'.format(unknown))
202
205
"""
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 )
235
209
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 )
263
211
264
212
265
213
def with_argparser (parser : argparse .ArgumentParser , * ,
266
214
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 ]]:
268
217
"""A decorator to alter a cmd2 method to populate its ``args`` argument by parsing arguments
269
218
with the given instance of argparse.ArgumentParser.
270
219
@@ -273,6 +222,7 @@ def with_argparser(parser: argparse.ArgumentParser, *,
273
222
argparse.Namespace. This is useful if the Namespace needs to be prepopulated with
274
223
state data that affects parsing.
275
224
:param preserve_quotes: if True, then arguments passed to argparse maintain their quotes
225
+ :param with_unknown_args: if true, then capture unknown args
276
226
:return: function that gets passed the argparse-parsed args in a Namespace
277
227
A member called __statement__ is added to the Namespace to provide command functions access to the
278
228
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, *,
290
240
>>> def do_argprint(self, args):
291
241
>>> "Print the options and argument list this options command was called with."
292
242
>>> 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
+
293
258
"""
294
259
import functools
295
260
@@ -318,7 +283,11 @@ def cmd_wrapper(*args: Any, **kwargs: Dict[str, Any]) -> Optional[bool]:
318
283
namespace = ns_provider (cmd2_app )
319
284
320
285
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 ]
322
291
except SystemExit :
323
292
raise Cmd2ArgparseError
324
293
else :
@@ -329,7 +298,7 @@ def get_handler(self: argparse.Namespace) -> Optional[Callable]:
329
298
330
299
setattr (ns , 'get_handler' , types .MethodType (get_handler , ns ))
331
300
332
- args_list = _arg_swap (args , statement , ns )
301
+ args_list = _arg_swap (args , statement , * new_args )
333
302
return func (* args_list , ** kwargs )
334
303
335
304
# argparser defaults the program name to sys.argv[0], but we want it to be the name of our command
0 commit comments