|
| 1 | +=================== |
| 2 | +Argument Processing |
| 3 | +=================== |
| 4 | + |
| 5 | +``cmd2`` makes it easy to add sophisticated argument processing to your commands using the ``argparse`` python module. ``cmd2`` handles the following for you: |
| 6 | + |
| 7 | +1. Parsing input and quoted strings like the Unix shell |
| 8 | +2. Parse the resulting argument list using an instance of ``argparse.ArgumentParser`` that you provide |
| 9 | +3. Passes the resulting ``argparse.Namespace`` object to your command function |
| 10 | +4. Adds the usage message from the argument parser to your command. |
| 11 | +5. Checks if the ``-h/--help`` option is present, and if so, display the help message for the command |
| 12 | + |
| 13 | +These features are all provided by the ``@with_argument_parser`` decorator. |
| 14 | + |
| 15 | +Using the decorator |
| 16 | +=================== |
| 17 | + |
| 18 | +For each command in the ``cmd2`` subclass which requires argument parsing, |
| 19 | +create an instance of ``argparse.ArgumentParser()`` which can parse the |
| 20 | +input appropriately for the command. Then decorate the command method with |
| 21 | +the ``@with_argument_parser`` decorator, passing the argument parser as the |
| 22 | +first parameter to the decorator. Add a third variable to the command method, which will contain the results of ``ArgumentParser.parse_args()``. |
| 23 | + |
| 24 | +Here's what it looks like:: |
| 25 | + |
| 26 | + argparser = argparse.ArgumentParser() |
| 27 | + argparser.add_argument('-p', '--piglatin', action='store_true', help='atinLay') |
| 28 | + argparser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE') |
| 29 | + argparser.add_argument('-r', '--repeat', type=int, help='output [n] times') |
| 30 | + argparser.add_argument('word', nargs='?', help='word to say') |
| 31 | + |
| 32 | + @with_argument_parser(argparser) |
| 33 | + def do_speak(self, argv, opts) |
| 34 | + """Repeats what you tell me to.""" |
| 35 | + arg = opts.word |
| 36 | + if opts.piglatin: |
| 37 | + arg = '%s%say' % (arg[1:], arg[0]) |
| 38 | + if opts.shout: |
| 39 | + arg = arg.upper() |
| 40 | + repetitions = opts.repeat or 1 |
| 41 | + for i in range(min(repetitions, self.maxrepeats)): |
| 42 | + self.poutput(arg) |
| 43 | + |
| 44 | +.. note:: |
| 45 | + |
| 46 | + The ``@with_argument_parser`` decorator sets the ``prog`` variable in |
| 47 | + the argument parser based on the name of the method it is decorating. |
| 48 | + This will override anything you specify in ``prog`` variable when |
| 49 | + creating the argument parser. |
| 50 | + |
| 51 | + |
| 52 | +Help Messages |
| 53 | +============= |
| 54 | + |
| 55 | +By default, cmd2 uses the docstring of the command method when a user asks |
| 56 | +for help on the command. When you use the ``@with_argument_parser`` |
| 57 | +decorator, the formatted help from the ``argparse.ArgumentParser`` is |
| 58 | +appended to the docstring for the method of that command. With this code:: |
| 59 | + |
| 60 | + argparser = argparse.ArgumentParser() |
| 61 | + argparser.add_argument('tag', nargs=1, help='tag') |
| 62 | + argparser.add_argument('content', nargs='+', help='content to surround with tag') |
| 63 | + @with_argument_parser(argparser) |
| 64 | + def do_tag(self, cmdline, args=None): |
| 65 | + """create a html tag""" |
| 66 | + self.stdout.write('<{0}>{1}</{0}>'.format(args.tag[0], ' '.join(args.content))) |
| 67 | + self.stdout.write('\n') |
| 68 | + |
| 69 | +The ``help tag`` command displays: |
| 70 | + |
| 71 | +.. code-block:: none |
| 72 | +
|
| 73 | + create a html tag |
| 74 | + usage: tag [-h] tag content [content ...] |
| 75 | +
|
| 76 | + positional arguments: |
| 77 | + tag tag |
| 78 | + content content to surround with tag |
| 79 | +
|
| 80 | + optional arguments: |
| 81 | + -h, --help show this help message and exit |
| 82 | +
|
| 83 | + |
| 84 | +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:: |
| 85 | + |
| 86 | + argparser = argparse.ArgumentParser(description='create an html tag') |
| 87 | + argparser.add_argument('tag', nargs=1, help='tag') |
| 88 | + argparser.add_argument('content', nargs='+', help='content to surround with tag') |
| 89 | + @with_argument_parser(argparser) |
| 90 | + def do_tag(self, cmdline, args=None): |
| 91 | + self.stdout.write('<{0}>{1}</{0}>'.format(args.tag[0], ' '.join(args.content))) |
| 92 | + self.stdout.write('\n') |
| 93 | + |
| 94 | +Now when the user enters ``help tag`` they see: |
| 95 | + |
| 96 | +.. code-block:: none |
| 97 | +
|
| 98 | + usage: tag [-h] tag content [content ...] |
| 99 | +
|
| 100 | + create an html tag |
| 101 | +
|
| 102 | + positional arguments: |
| 103 | + tag tag |
| 104 | + content content to surround with tag |
| 105 | +
|
| 106 | + optional arguments: |
| 107 | + -h, --help show this help message and exit |
| 108 | +
|
| 109 | +
|
| 110 | +To add additional text to the end of the generated help message, use the ``epilog`` variable:: |
| 111 | + |
| 112 | + argparser = argparse.ArgumentParser( |
| 113 | + description='create an html tag', |
| 114 | + epilog='This command can not generate tags with no content, like <br/>.' |
| 115 | + ) |
| 116 | + argparser.add_argument('tag', nargs=1, help='tag') |
| 117 | + argparser.add_argument('content', nargs='+', help='content to surround with tag') |
| 118 | + @with_argument_parser(argparser) |
| 119 | + def do_tag(self, cmdline, args=None): |
| 120 | + self.stdout.write('<{0}>{1}</{0}>'.format(args.tag[0], ' '.join(args.content))) |
| 121 | + self.stdout.write('\n') |
| 122 | + |
| 123 | +Which yields: |
| 124 | + |
| 125 | +.. code-block:: none |
| 126 | +
|
| 127 | + usage: tag [-h] tag content [content ...] |
| 128 | +
|
| 129 | + create an html tag |
| 130 | +
|
| 131 | + positional arguments: |
| 132 | + tag tag |
| 133 | + content content to surround with tag |
| 134 | +
|
| 135 | + optional arguments: |
| 136 | + -h, --help show this help message and exit |
| 137 | +
|
| 138 | + This command can not generate tags with no content, like <br/> |
| 139 | +
|
| 140 | +
|
| 141 | +Deprecated optparse support |
| 142 | +=========================== |
| 143 | + |
| 144 | +The ``optparse`` library has been deprecated since Python 2.7 (released on July |
| 145 | +3rd 2010) and Python 3.2 (released on February 20th, 2011). ``optparse`` is |
| 146 | +still included in the python standard library, but the documentation |
| 147 | +recommends using ``argparse`` instead. |
| 148 | + |
| 149 | +``cmd2`` includes a decorator which can parse arguments using ``optparse``. This decorator is deprecated just like the ``optparse`` library. |
| 150 | + |
| 151 | +Here's an example:: |
| 152 | + |
| 153 | + opts = [make_option('-p', '--piglatin', action="store_true", help="atinLay"), |
| 154 | + make_option('-s', '--shout', action="store_true", help="N00B EMULATION MODE"), |
| 155 | + make_option('-r', '--repeat', type="int", help="output [n] times")] |
| 156 | + |
| 157 | + @options(opts, arg_desc='(text to say)') |
| 158 | + def do_speak(self, arg, opts=None): |
| 159 | + """Repeats what you tell me to.""" |
| 160 | + arg = ''.join(arg) |
| 161 | + if opts.piglatin: |
| 162 | + arg = '%s%say' % (arg[1:], arg[0]) |
| 163 | + if opts.shout: |
| 164 | + arg = arg.upper() |
| 165 | + repetitions = opts.repeat or 1 |
| 166 | + for i in range(min(repetitions, self.maxrepeats)): |
| 167 | + self.poutput(arg) |
| 168 | + |
| 169 | + |
| 170 | +The optparse decorator performs the following key functions for you: |
| 171 | + |
| 172 | +1. Use `shlex` to split the arguments entered by the user. |
| 173 | +2. Parse the arguments using the given optparse options. |
| 174 | +3. Replace the `__doc__` string of the decorated function (i.e. do_speak) with the help string generated by optparse. |
| 175 | +4. Call the decorated function (i.e. do_speak) passing an additional parameter which contains the parsed options. |
0 commit comments