diff options
-rwxr-xr-x | cmd2.py | 18 | ||||
-rw-r--r-- | docs/argument_processing.rst | 51 | ||||
-rwxr-xr-x | examples/argparse_example.py | 20 | ||||
-rw-r--r-- | tests/test_argparse.py | 15 |
4 files changed, 97 insertions, 7 deletions
@@ -276,6 +276,24 @@ def with_argument_parser(argparser): return arg_decorator +def with_argument_list(func): + """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().""" + def cmd_wrapper(self, cmdline): + # Use shlex to split the command line into a list of arguments based on shell rules + lexed_arglist = shlex.split(cmdline, posix=POSIX_SHLEX) + # If not using POSIX shlex, make sure to strip off outer quotes for convenience + if not POSIX_SHLEX and STRIP_QUOTES_FOR_NON_POSIX: + temp_arglist = [] + for arg in lexed_arglist: + temp_arglist.append(strip_quotes(arg)) + lexed_arglist = temp_arglist + func(self, lexed_arglist) + return cmd_wrapper + + def options(option_list, arg_desc="arg"): """Used as a decorator and passed a list of optparse-style options, alters a cmd2 method to populate its ``opts`` argument from its diff --git a/docs/argument_processing.rst b/docs/argument_processing.rst index a8dabbab..fdbfb137 100644 --- a/docs/argument_processing.rst +++ b/docs/argument_processing.rst @@ -142,6 +142,57 @@ Which yields: This command can not generate tags with no content, like <br/> +Receiving an argument list +========================== + +The default behavior of ``cmd2`` is to pass the user input directly to your +``do_*`` methods as a string. If you don't want to use the full argument parser support outlined above, you can still have ``cmd2`` apply shell parsing rules to the user input and pass you a list of arguments instead of a string. There are two methods to effect this change. + +The ``use_argument_list`` attribute of a ``cmd2`` class or subclass defaults to ``False``. Set it to ``True`` and all of your ``do_*`` methods will receive a list of arguments parsed by ``shlex.split()`` instead of receiving a string:: + + class CmdLineApp(cmd2.Cmd): + """ Example cmd2 application. """ + def __init__(self): + self.use_argument_list = True + Cmd.__init__(self) + + def do_speak(self, arglist): + # instead of a string, arglist contains a list of arguments + pass + +Any ``do_*`` methods decorated with ``@with_argument_parser()`` will receive both a list of arguments (instead of a string) and the parsed options as parameters:: + + class CmdLineApp(cmd2.Cmd): + """ Example cmd2 application. """ + def __init__(self): + self.use_argument_list = True + Cmd.__init__(self) + + argparser = argparse.ArgumentParser() + argparser.add_argument('tag', nargs=1, help='tag') + argparser.add_argument('content', nargs='+', help='content to surround with tag') + @with_argument_parser(argparser) + def do_tag(self, arglist, args=None): + """create a html tag""" + # arglist contains a list of arguments, not a string + self.stdout.write('<{0}>{1}</{0}>'.format(args.tag[0], ' '.join(args.content))) + self.stdout.write('\n') + +Instead of having all of your ``do_*`` methods receive an argument list, you can choose to only have certain methods receive the argument list (instead of a string). Leave the ``use_argument_list`` attribute at it's default value of ``False``. Then apply the ``@with_argument_list`` decorator only to those methods that should receive an argument list instead of a string:: + + class CmdLineApp(cmd2.Cmd): + """ Example cmd2 application. """ + + def do_say(self, cmdline): + # cmdline contains a string + pass + + @with_argument_list + def do_speak(self, arglist): + # arglist contains a list of arguments + pass + + Deprecated optparse support =========================== diff --git a/examples/argparse_example.py b/examples/argparse_example.py index 3574f549..40ea372c 100755 --- a/examples/argparse_example.py +++ b/examples/argparse_example.py @@ -14,7 +14,7 @@ verifying that the output produced matches the transcript. import argparse import sys -from cmd2 import Cmd, make_option, options, with_argument_parser +from cmd2 import Cmd, make_option, options, with_argument_parser, with_argument_list class CmdLineApp(Cmd): @@ -69,10 +69,20 @@ class CmdLineApp(Cmd): argparser.add_argument('content', nargs='+', help='content to surround with tag') @with_argument_parser(argparser) def do_tag(self, arglist, args=None): - self.stdout.write('<{0}>{1}</{0}>'.format(args.tag[0], ' '.join(args.content))) - self.stdout.write('\n') - # self.stdout.write is better than "print", because Cmd can be - # initialized with a non-standard output destination + """create a html tag""" + self.poutput('<{0}>{1}</{0}>'.format(args.tag[0], ' '.join(args.content))) + + + @with_argument_list + def do_tagg(self, arglist): + """verion of creating an html tag using arglist instead of argparser""" + if len(arglist) >= 2: + tag = arglist[0] + content = arglist[1:] + self.poutput('<{0}>{1}</{0}>'.format(tag, ' '.join(content))) + else: + self.perror("tagg requires at least 2 arguments") + # @options uses the python optparse module which has been deprecated # since 2011. Use @with_argument_parser instead, which utilizes the diff --git a/tests/test_argparse.py b/tests/test_argparse.py index 1ca455e9..308824cf 100644 --- a/tests/test_argparse.py +++ b/tests/test_argparse.py @@ -58,7 +58,14 @@ class ArgparseApp(cmd2.Cmd): argparser = argparse.ArgumentParser() argparser.add_argument('args', nargs='*') @cmd2.with_argument_parser(argparser) - def do_arglist(self, arglist, args=None): + def do_argparse_arglist(self, arglist, args=None): + if isinstance(arglist, list): + self.stdout.write('True') + else: + self.stdout.write('False') + + @cmd2.with_argument_list + def do_arglist(self, arglist): if isinstance(arglist, list): self.stdout.write('True') else: @@ -114,5 +121,9 @@ def test_argparse_cmdline(argparse_app): assert out[0] == 'True' def test_argparse_arglist(argparse_app): - out = run_cmd(argparse_app, 'arglist "some arguments" and some more') + out = run_cmd(argparse_app, 'argparse_arglist "some arguments" and some more') + assert out[0] == 'True' + +def test_arglist(argparse_app): + out = run_cmd(argparse_app, 'arglist "we should" get these in a list, not a string') assert out[0] == 'True' |