summaryrefslogtreecommitdiff
path: root/docs/argument_processing.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/argument_processing.rst')
-rw-r--r--docs/argument_processing.rst258
1 files changed, 146 insertions, 112 deletions
diff --git a/docs/argument_processing.rst b/docs/argument_processing.rst
index 279dbe47..79c19d19 100644
--- a/docs/argument_processing.rst
+++ b/docs/argument_processing.rst
@@ -2,140 +2,174 @@
Argument Processing
===================
-cmd2 currently includes code which makes it easier to add arguments to the
-commands in your cmd2 subclass. This support utilizes the optparse library,
-which has been deprecated since Python 2.7 (released on July 3rd 2010) and
-Python 3.2 (released on February 20th, 2011). Optparse is still included in the
-python standard library, but the documentation recommends using argparse
-instead. It's time to modernize cmd2 to utilize argparse.
-
-I don't believe there is a way to change cmd2 to use argparse instead of
-optparse without requiring subclasses of cmd2 to make some change. The long
-recomended way to use optparse in cmd2 includes the use of the
-optparse.make_option, which must be changed in order to use argparse.
-
-There are two potential ways to use argument parsing with cmd2: to parse
-options given at the shell prompt when invoked, and to parse options given at
-the cmd2 prompt prior to executing a command.
-
-optparse example
-================
-
-Here's an example of the current optparse support:
-
- opts = [make_option('-p', '--piglatin', action="store_true", help="atinLay"),
- make_option('-s', '--shout', action="store_true", help="N00B EMULATION MODE"),
- make_option('-r', '--repeat', type="int", help="output [n] times")]
-
- @options(opts, arg_desc='(text to say)')
- def do_speak(self, arg, opts=None):
- """Repeats what you tell me to."""
- arg = ''.join(arg)
- if opts.piglatin:
- arg = '%s%say' % (arg[1:], arg[0])
- if opts.shout:
- arg = arg.upper()
- repetitions = opts.repeat or 1
- for i in range(min(repetitions, self.maxrepeats)):
- self.poutput(arg)
+``cmd2`` makes it easy to add sophisticated argument processing to your commands using the ``argparse`` python module. ``cmd2`` handles the following for you:
-The current optparse decorator performs the following key functions for you:
+1. Parsing input and quoted strings like the Unix shell
+2. Parse the resulting argument list using an instance of ``argparse.ArgumentParser`` that you provide
+3. Passes the resulting ``argparse.Namespace`` object to your command function
+4. Adds the usage message from the argument parser to your command.
+5. Checks if the ``-h/--help`` option is present, and if so, display the help message for the command
-1. Use `shlex` to split the arguments entered by the user.
-2. Parse the arguments using the given optparse options.
-3. Replace the `__doc__` string of the decorated function (i.e. do_speak) with
-the help string generated by optparse.
-4. Call the decorated function (i.e. do_speak) passing an additional parameter
-which contains the parsed options.
-
-Here are several options for replacing this functionality with argparse.
+These features are all provided by the ``@with_argument_parser`` decorator.
+Using the decorator
+===================
-No cmd2 support
-===============
+For each command in the ``cmd2`` subclass which requires argument parsing,
+create an instance of ``argparse.ArgumentParser()`` which can parse the
+input appropriately for the command. Then decorate the command method with
+the ``@with_argument_parser`` decorator, passing the argument parser as the
+first parameter to the decorator. Add a third variable to the command method, which will contain the results of ``ArgumentParser.parse_args()``.
-The easiest option would be to just remove the cmd2 specific support for
-argument parsing. The above example would then look something like this:
+Here's what it looks like::
- argparser = argparse.ArgumentParser(
- prog='speak',
- description='Repeats what you tell me to'
- )
+ argparser = argparse.ArgumentParser()
argparser.add_argument('-p', '--piglatin', action='store_true', help='atinLay')
argparser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE')
- argparser.add_argument('r', '--repeat', type='int', help='output [n] times')
+ argparser.add_argument('-r', '--repeat', type=int, help='output [n] times')
argparser.add_argument('word', nargs='?', help='word to say')
- def do_speak(self, argv)
- """Repeats what you tell me to."""
- opts = argparser.parse_args(shlex.split(argv, posix=POSIX_SHLEX))
- arg = opts.word
- if opts.piglatin:
+ @with_argument_parser(argparser)
+ def do_speak(self, argv, opts)
+ """Repeats what you tell me to."""
+ arg = opts.word
+ if opts.piglatin:
arg = '%s%say' % (arg[1:], arg[0])
- if opts.shout:
+ if opts.shout:
arg = arg.upper()
- repetitions = opts.repeat or 1
- for i in range(min(repetitions, self.maxrepeats)):
+ repetitions = opts.repeat or 1
+ for i in range(min(repetitions, self.maxrepeats)):
self.poutput(arg)
-Using shlex in this example is technically not necessary because the `do_speak`
-command only expects a single word argument. It is included here to show what
-would be required to replicate the current optparse based functionality.
+.. note::
+ The ``@with_argument_parser`` decorator sets the ``prog`` variable in
+ the argument parser based on the name of the method it is decorating.
+ This will override anything you specify in ``prog`` variable when
+ creating the argument parser.
-A single argparse specific decorator
-====================================
-In this approach, we would create one new decorator, perhaps called
-`with_argument_parser`. This single decorator would take as it's argument a fully
-defined `argparse.ArgumentParser`. This decorator would shelx the user input,
-apply the ArgumentParser, and pass the resulting object to the decorated method, like so:
+Help Messages
+=============
- argparser = argparse.ArgumentParser(
- prog='speak',
- description='Repeats what you tell me to'
- )
- argparser.add_argument('-p', '--piglatin', action='store_true', help='atinLay')
- argparser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE')
- argparser.add_argument('-r', '--repeat', type=int, help='output [n] times')
- argparser.add_argument('word', nargs='?', help='word to say')
+By default, cmd2 uses the docstring of the command method when a user asks
+for help on the command. When you use the ``@with_argument_parser``
+decorator, the formatted help from the ``argparse.ArgumentParser`` is
+appended to the docstring for the method of that command. With this code::
- @with_argument_parser(argparser)
- def do_speak(self, argv, opts)
- """Repeats what you tell me to."""
- arg = opts.word
- if opts.piglatin:
- arg = '%s%say' % (arg[1:], arg[0])
- if opts.shout:
- arg = arg.upper()
- repetitions = opts.repeat or 1
- for i in range(min(repetitions, self.maxrepeats)):
- self.poutput(arg)
+ 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, cmdline, args=None):
+ """create a html tag"""
+ self.stdout.write('<{0}>{1}</{0}>'.format(args.tag[0], ' '.join(args.content)))
+ self.stdout.write('\n')
-Compared to the no argparse support in cmd2 approach, this replaces a line of
-code with a nested function with a decorator without a nested function.
+The ``help tag`` command displays:
+.. code-block:: none
-A whole bunch of argparse specific decorators
-=============================================
+ create a html tag
+ usage: tag [-h] tag content [content ...]
-This approach would turn out something like the climax library
-(https://github.com/miguelgrinberg/climax), which includes a decorator for each method available
-on the `ArgumentParser()` object. Our `do_speak` command would look like this:
+ positional arguments:
+ tag tag
+ content content to surround with tag
- @command()
- @argument('-p', '--piglatin', action='store_true', help='atinLay')
- @argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE')
- @argument('r', '--repeat', type='int', help='output [n] times')
- @add_argument('word', nargs='?', help='word to say')
- def do_speak(self, argv, piglatin, shout, repeat, word)
- """Repeats what you tell me to."""
- arg = word
- if piglatin:
- arg = '%s%say' % (arg[1:], arg[0])
- if shout:
- arg = arg.upper()
- repetitions = repeat or 1
- for i in range(min(repetitions, self.maxrepeats)):
- self.poutput(arg)
+ optional arguments:
+ -h, --help show this help message and exit
+
+
+If you would prefer the short description of your command to come after the usage message, leave the docstring on your method empty, but supply a ``description`` variable to the argument parser::
+
+ argparser = argparse.ArgumentParser(description='create an html tag')
+ 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, cmdline, args=None):
+ self.stdout.write('<{0}>{1}</{0}>'.format(args.tag[0], ' '.join(args.content)))
+ self.stdout.write('\n')
+
+Now when the user enters ``help tag`` they see:
+
+.. code-block:: none
+
+ usage: tag [-h] tag content [content ...]
+
+ create an html tag
+
+ positional arguments:
+ tag tag
+ content content to surround with tag
+
+ optional arguments:
+ -h, --help show this help message and exit
+
+
+To add additional text to the end of the generated help message, use the ``epilog`` variable::
+
+ argparser = argparse.ArgumentParser(
+ description='create an html tag',
+ epilog='This command can not generate tags with no content, like <br/>.'
+ )
+ 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, cmdline, args=None):
+ self.stdout.write('<{0}>{1}</{0}>'.format(args.tag[0], ' '.join(args.content)))
+ self.stdout.write('\n')
+
+Which yields:
+
+.. code-block:: none
+
+ usage: tag [-h] tag content [content ...]
+
+ create an html tag
+
+ positional arguments:
+ tag tag
+ content content to surround with tag
+
+ optional arguments:
+ -h, --help show this help message and exit
+
+ This command can not generate tags with no content, like <br/>
+
+
+Deprecated optparse support
+===========================
+
+The ``optparse`` library has been deprecated since Python 2.7 (released on July
+3rd 2010) and Python 3.2 (released on February 20th, 2011). ``optparse`` is
+still included in the python standard library, but the documentation
+recommends using ``argparse`` instead.
+
+``cmd2`` includes a decorator which can parse arguments using ``optparse``. This decorator is deprecated just like the ``optparse`` library.
+
+Here's an example::
+
+ opts = [make_option('-p', '--piglatin', action="store_true", help="atinLay"),
+ make_option('-s', '--shout', action="store_true", help="N00B EMULATION MODE"),
+ make_option('-r', '--repeat', type="int", help="output [n] times")]
+
+ @options(opts, arg_desc='(text to say)')
+ def do_speak(self, arg, opts=None):
+ """Repeats what you tell me to."""
+ arg = ''.join(arg)
+ if opts.piglatin:
+ arg = '%s%say' % (arg[1:], arg[0])
+ if opts.shout:
+ arg = arg.upper()
+ repetitions = opts.repeat or 1
+ for i in range(min(repetitions, self.maxrepeats)):
+ self.poutput(arg)
+
+
+The optparse decorator performs the following key functions for you:
+1. Use `shlex` to split the arguments entered by the user.
+2. Parse the arguments using the given optparse options.
+3. Replace the `__doc__` string of the decorated function (i.e. do_speak) with the help string generated by optparse.
+4. Call the decorated function (i.e. do_speak) passing an additional parameter which contains the parsed options.