From 28e44aac56ea21be8aa3bea5d93325d0edd836be Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Mon, 4 Mar 2019 20:40:28 -0500 Subject: [PATCH 1/4] Fix for when with_argument_list is called with preserve_quotes optional argument --- cmd2/cmd2.py | 23 ++++++++++++++--------- examples/arg_print.py | 5 +++++ tests/test_argparse.py | 8 ++++++++ 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 24e140fda..d124ac232 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -175,25 +175,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[[Statement], Optional[bool]]): + @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/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 7db35c714..a055ac724 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): @@ -174,6 +178,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' From 5e423f89572f148c2a26f8adbaa44915be9d405a Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Mon, 4 Mar 2019 20:50:10 -0500 Subject: [PATCH 2/4] Updated CHANGELOG and fixed Sphinx docs --- CHANGELOG.md | 2 ++ docs/freefeatures.rst | 9 ++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1139853fa..fad8ca2e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ ## 0.9.11 (TBD, 2019) +* Bug Fixes + * Fixed a bug when the ``with_argument_list`` decorator is called with the optional ``preserve_quotes`` argument * Enhancements * Added ``matches_sort_key`` to override the default way tab completion matches are sorted * Potentially breaking changes diff --git a/docs/freefeatures.rst b/docs/freefeatures.rst index c70a2d93b..b6c7bebdd 100644 --- a/docs/freefeatures.rst +++ b/docs/freefeatures.rst @@ -222,12 +222,11 @@ of using ``pyscript`` is shown below along with the **examples/arg_printer.py** If you want to be able to pass arguments with spaces to scripts, 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/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'] IPython (optional) From 123ac08169078cd8d232ae39102534782ac7fd87 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Mon, 4 Mar 2019 21:20:35 -0500 Subject: [PATCH 3/4] Simplifying type hint --- cmd2/cmd2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index d124ac232..1167e5298 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -186,7 +186,7 @@ def with_argument_list(*args: List[Callable], preserve_quotes: bool = False) -> """ import functools - def arg_decorator(func: Callable[[Statement], Optional[bool]]): + def arg_decorator(func: Callable): @functools.wraps(func) def cmd_wrapper(self, cmdline): lexed_arglist = parse_quoted_string(cmdline, preserve_quotes) From f765be2ce360cf104999f1440f1b13e75cbd957c Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Mon, 4 Mar 2019 22:33:58 -0500 Subject: [PATCH 4/4] Fixed wording in freefeatures.rst --- docs/freefeatures.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/freefeatures.rst b/docs/freefeatures.rst index a34d9fcc5..5c246798c 100644 --- a/docs/freefeatures.rst +++ b/docs/freefeatures.rst @@ -212,13 +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:: $ 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