Skip to content

Commit 04eac4b

Browse files
authored
Merge pull request #636 from python-cmd2/with_argument_list
Fix bug in with_argument_list decorator
2 parents dddf5d0 + d1a970b commit 04eac4b

File tree

5 files changed

+33
-15
lines changed

5 files changed

+33
-15
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## 0.9.11 (TBD, 2019)
22
* Bug Fixes
33
* Fixed bug in how **history** command deals with multiline commands when output to a script
4+
* Fixed a bug when the ``with_argument_list`` decorator is called with the optional ``preserve_quotes`` argument
45
* Enhancements
56
* Improvements to the **history** command
67
* Simplified the display format and made it more similar to **bash**

cmd2/cmd2.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -176,25 +176,30 @@ def cat_decorator(func):
176176
return cat_decorator
177177

178178

179-
def with_argument_list(func: Callable[[Statement], Optional[bool]],
180-
preserve_quotes: bool = False) -> Callable[[List], Optional[bool]]:
179+
def with_argument_list(*args: List[Callable], preserve_quotes: bool = False) -> Callable[[List], Optional[bool]]:
181180
"""A decorator to alter the arguments passed to a do_* cmd2 method. Default passes a string of whatever the user
182181
typed. With this decorator, the decorated method will receive a list of arguments parsed from user input using
183182
shlex.split().
184183
185-
:param func: do_* method this decorator is wrapping
184+
:param args: Single-element positional argument list containing do_* method this decorator is wrapping
186185
:param preserve_quotes: if True, then argument quotes will not be stripped
187186
:return: function that gets passed a list of argument strings
188187
"""
189188
import functools
190189

191-
@functools.wraps(func)
192-
def cmd_wrapper(self, cmdline):
193-
lexed_arglist = parse_quoted_string(cmdline, preserve_quotes)
194-
return func(self, lexed_arglist)
190+
def arg_decorator(func: Callable):
191+
@functools.wraps(func)
192+
def cmd_wrapper(self, cmdline):
193+
lexed_arglist = parse_quoted_string(cmdline, preserve_quotes)
194+
return func(self, lexed_arglist)
195195

196-
cmd_wrapper.__doc__ = func.__doc__
197-
return cmd_wrapper
196+
cmd_wrapper.__doc__ = func.__doc__
197+
return cmd_wrapper
198+
199+
if len(args) == 1 and callable(args[0]):
200+
return arg_decorator(args[0])
201+
else:
202+
return arg_decorator
198203

199204

200205
def with_argparser_and_unknown_args(argparser: argparse.ArgumentParser, preserve_quotes: bool = False) -> \

docs/freefeatures.rst

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -212,15 +212,14 @@ of using ``pyscript`` is shown below along with the arg_printer_ script::
212212

213213
.. note::
214214

215-
If you want to be able to pass arguments with spaces to scripts, then we strongly recommend using one of the decorators,
215+
If you want to be able to pass arguments with spaces to commands, then we strongly recommend using one of the decorators,
216216
such as ``with_argument_list``. ``cmd2`` will pass your **do_*** methods a list of arguments in this case.
217217

218-
When using this decorator, you can then put arguments in quotes like so (NOTE: the ``do_pyscript`` method uses this decorator::
218+
When using this decorator, you can then put arguments in quotes like so::
219219

220-
(Cmd) pyscript examples/scripts/arg_printer.py hello '23 fnord'
221-
Running Python script 'arg_printer.py' which was called with 2 arguments
222-
arg 1: 'hello'
223-
arg 2: '23 fnord'
220+
$ examples/arg_print.py
221+
(Cmd) lprint foo "bar baz"
222+
lprint was called with the following list of arguments: ['foo', 'bar baz']
224223

225224
.. _arg_printer: https://github.com/python-cmd2/cmd2/blob/master/examples/scripts/arg_printer.py
226225

examples/arg_print.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ def do_lprint(self, arglist):
3838
"""Print the argument list this basic command is called with."""
3939
self.poutput('lprint was called with the following list of arguments: {!r}'.format(arglist))
4040

41+
@cmd2.with_argument_list(preserve_quotes=True)
42+
def do_rprint(self, arglist):
43+
"""Print the argument list this basic command is called with (with quotes preserved)."""
44+
self.poutput('rprint was called with the following list of arguments: {!r}'.format(arglist))
45+
4146
oprint_parser = argparse.ArgumentParser()
4247
oprint_parser.add_argument('-p', '--piglatin', action='store_true', help='atinLay')
4348
oprint_parser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE')

tests/test_argparse.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ def do_arglist(self, arglist):
6868
else:
6969
self.stdout.write('False')
7070

71+
@cmd2.with_argument_list(preserve_quotes=True)
72+
def do_preservelist(self, arglist):
73+
self.stdout.write('{}'.format(arglist))
74+
7175
@cmd2.with_argument_list
7276
@cmd2.with_argument_list
7377
def do_arglisttwice(self, arglist):
@@ -170,6 +174,10 @@ def test_arglist(argparse_app):
170174
out = run_cmd(argparse_app, 'arglist "we should" get these')
171175
assert out[0] == 'True'
172176

177+
def test_preservelist(argparse_app):
178+
out = run_cmd(argparse_app, 'preservelist foo "bar baz"')
179+
assert out[0] == "['foo', '\"bar baz\"']"
180+
173181
def test_arglist_decorator_twice(argparse_app):
174182
out = run_cmd(argparse_app, 'arglisttwice "we should" get these')
175183
assert out[0] == 'we should get these'

0 commit comments

Comments
 (0)