diff --git a/CHANGELOG.md b/CHANGELOG.md index dd9966cc9..fcf90db8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## 0.9.11 (TBD, 2019) * Bug Fixes * Fixed bug in how **history** command deals with multiline commands when output to a script + * Fixed a bug when the ``with_argument_list`` decorator is called with the optional ``preserve_quotes`` argument * Enhancements * Improvements to the **history** command * Simplified the display format and made it more similar to **bash** diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 5912bee37..66de84736 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -176,25 +176,30 @@ def cat_decorator(func): return cat_decorator -def with_argument_list(func: Callable[[Statement], Optional[bool]], - preserve_quotes: bool = False) -> Callable[[List], Optional[bool]]: +def with_argument_list(*args: List[Callable], preserve_quotes: bool = False) -> Callable[[List], Optional[bool]]: """A decorator to alter the arguments passed to a do_* cmd2 method. Default passes a string of whatever the user typed. With this decorator, the decorated method will receive a list of arguments parsed from user input using shlex.split(). - :param func: do_* method this decorator is wrapping + :param args: Single-element positional argument list containing do_* method this decorator is wrapping :param preserve_quotes: if True, then argument quotes will not be stripped :return: function that gets passed a list of argument strings """ import functools - @functools.wraps(func) - def cmd_wrapper(self, cmdline): - lexed_arglist = parse_quoted_string(cmdline, preserve_quotes) - return func(self, lexed_arglist) + def arg_decorator(func: Callable): + @functools.wraps(func) + def cmd_wrapper(self, cmdline): + lexed_arglist = parse_quoted_string(cmdline, preserve_quotes) + return func(self, lexed_arglist) - cmd_wrapper.__doc__ = func.__doc__ - return cmd_wrapper + cmd_wrapper.__doc__ = func.__doc__ + return cmd_wrapper + + if len(args) == 1 and callable(args[0]): + return arg_decorator(args[0]) + else: + return arg_decorator def with_argparser_and_unknown_args(argparser: argparse.ArgumentParser, preserve_quotes: bool = False) -> \ diff --git a/docs/freefeatures.rst b/docs/freefeatures.rst index 9e8c2cbf6..5c246798c 100644 --- a/docs/freefeatures.rst +++ b/docs/freefeatures.rst @@ -212,15 +212,14 @@ of using ``pyscript`` is shown below along with the arg_printer_ script:: .. note:: - If you want to be able to pass arguments with spaces to scripts, then we strongly recommend using one of the decorators, + If you want to be able to pass arguments with spaces to commands, then we strongly recommend using one of the decorators, such as ``with_argument_list``. ``cmd2`` will pass your **do_*** methods a list of arguments in this case. - When using this decorator, you can then put arguments in quotes like so (NOTE: the ``do_pyscript`` method uses this decorator:: + When using this decorator, you can then put arguments in quotes like so:: - (Cmd) pyscript examples/scripts/arg_printer.py hello '23 fnord' - Running Python script 'arg_printer.py' which was called with 2 arguments - arg 1: 'hello' - arg 2: '23 fnord' + $ examples/arg_print.py + (Cmd) lprint foo "bar baz" + lprint was called with the following list of arguments: ['foo', 'bar baz'] .. _arg_printer: https://github.com/python-cmd2/cmd2/blob/master/examples/scripts/arg_printer.py diff --git a/examples/arg_print.py b/examples/arg_print.py index 1a1038589..18d217875 100755 --- a/examples/arg_print.py +++ b/examples/arg_print.py @@ -38,6 +38,11 @@ def do_lprint(self, arglist): """Print the argument list this basic command is called with.""" self.poutput('lprint was called with the following list of arguments: {!r}'.format(arglist)) + @cmd2.with_argument_list(preserve_quotes=True) + def do_rprint(self, arglist): + """Print the argument list this basic command is called with (with quotes preserved).""" + self.poutput('rprint was called with the following list of arguments: {!r}'.format(arglist)) + oprint_parser = argparse.ArgumentParser() oprint_parser.add_argument('-p', '--piglatin', action='store_true', help='atinLay') oprint_parser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE') diff --git a/tests/test_argparse.py b/tests/test_argparse.py index 6b810b44c..f5948f031 100644 --- a/tests/test_argparse.py +++ b/tests/test_argparse.py @@ -68,6 +68,10 @@ def do_arglist(self, arglist): else: self.stdout.write('False') + @cmd2.with_argument_list(preserve_quotes=True) + def do_preservelist(self, arglist): + self.stdout.write('{}'.format(arglist)) + @cmd2.with_argument_list @cmd2.with_argument_list def do_arglisttwice(self, arglist): @@ -170,6 +174,10 @@ def test_arglist(argparse_app): out = run_cmd(argparse_app, 'arglist "we should" get these') assert out[0] == 'True' +def test_preservelist(argparse_app): + out = run_cmd(argparse_app, 'preservelist foo "bar baz"') + assert out[0] == "['foo', '\"bar baz\"']" + def test_arglist_decorator_twice(argparse_app): out = run_cmd(argparse_app, 'arglisttwice "we should" get these') assert out[0] == 'we should get these'