summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xcmd2.py18
-rw-r--r--docs/argument_processing.rst51
-rwxr-xr-xexamples/argparse_example.py20
-rw-r--r--tests/test_argparse.py15
4 files changed, 97 insertions, 7 deletions
diff --git a/cmd2.py b/cmd2.py
index a660b348..fe6213a8 100755
--- a/cmd2.py
+++ b/cmd2.py
@@ -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'