diff options
author | Todd Leonhardt <todd.leonhardt@gmail.com> | 2019-11-03 18:03:48 -0500 |
---|---|---|
committer | Todd Leonhardt <todd.leonhardt@gmail.com> | 2019-11-03 18:03:48 -0500 |
commit | bd1c6660079398a406d2160dd6869ea2bb9b25d0 (patch) | |
tree | 4062a6b8583cfaa1710e83f0f29d1f1bfe03ea1b | |
parent | 34158ac44cb993ae64fd7ef0a6102eb20cba3c7a (diff) | |
download | cmd2-git-bd1c6660079398a406d2160dd6869ea2bb9b25d0.tar.gz |
Improved documentation for Argument Parsing and Tab-Completion
Also:
- Added a couple examples
-rw-r--r-- | docs/features/argument_processing.rst | 24 | ||||
-rw-r--r-- | docs/features/completion.rst | 46 | ||||
-rwxr-xr-x | examples/arg_decorators.py | 59 | ||||
-rwxr-xr-x | examples/basic.py | 43 |
4 files changed, 168 insertions, 4 deletions
diff --git a/docs/features/argument_processing.rst b/docs/features/argument_processing.rst index a3d4a3aa..a8124292 100644 --- a/docs/features/argument_processing.rst +++ b/docs/features/argument_processing.rst @@ -1,5 +1,3 @@ -.. _decorators: - Argument Processing =================== @@ -33,6 +31,7 @@ applications. .. _argprint: https://github.com/python-cmd2/cmd2/blob/master/examples/arg_print.py .. _decorator: https://github.com/python-cmd2/cmd2/blob/master/examples/decorator_example.py +.. _decorators: Decorators provided by cmd2 for argument processing --------------------------------------------------- @@ -40,12 +39,12 @@ Decorators provided by cmd2 for argument processing ``cmd2`` provides the following decorators for assisting with parsing arguments passed to commands: -.. automethod:: cmd2.decorators.with_argument_list - :noindex: .. automethod:: cmd2.decorators.with_argparser :noindex: .. automethod:: cmd2.decorators.with_argparser_and_unknown_args :noindex: +.. automethod:: cmd2.decorators.with_argument_list + :noindex: All of these decorators accept an optional **preserve_quotes** argument which defaults to ``False``. Setting this argument to ``True`` is useful for cases @@ -342,3 +341,20 @@ use subcommands in your ``cmd2`` application. .. _subcommands: https://github.com/python-cmd2/cmd2/blob/master/examples/subcommands.py .. _tab_autocompletion: https://github.com/python-cmd2/cmd2/blob/master/examples/tab_autocompletion.py + + +Argprase Extensions +------------------- + +``cmd2`` augments the standard ``argparse.nargs`` with range tuple capability: + +- ``nargs=(5,)`` - accept 5 or more items +- ``nargs=(8, 12)`` - accept 8 to 12 items + +``cmd2`` also provides the ``Cmd2ArgumentParser`` class which inherits from +``argparse.ArgumentParser`` and improves error and help output: + +.. autoclass:: cmd2.argparse_custom.Cmd2ArgumentParser + :members: + + diff --git a/docs/features/completion.rst b/docs/features/completion.rst index 5d2a722c..dfeddb27 100644 --- a/docs/features/completion.rst +++ b/docs/features/completion.rst @@ -31,3 +31,49 @@ similar to the following to your class which inherits from ``cmd2.Cmd``:: # Make sure you have an "import functools" somewhere at the top complete_bar = functools.partialmethod(cmd2.Cmd.path_complete, path_filter=os.path.isdir) + + +Tab Completion Using Argparse Decorators +---------------------------------------- + +When using one the Argparse-based :ref:`decorators`, ``cmd2`` provides +automatic tab-completion of flag names. + +Tab-completion of argument values can be configured by using one of five +parameters to ``argparse.ArgumentParser.add_argument()`` + +- ``choices`` +- ``choices_function`` / ``choices_method`` +- ``completer_function`` / ``completer_method`` + +See the arg_decorators_ or colors_ example for a demonstration of how to +use the ``choices`` parameter. See the tab_autocompletion_ example for a +demonstration of how to use the ``choices_function`` and ``choices_method`` +parameters. See the arg_decorators_ or tab_autocompletion_ example for a +demonstration of how to use the ``completer_method`` parameter. + +When tab-completing flags and/or argument values for a ``cmd2`` command using +one of these decorators, ``cmd2`` keeps track of state so that once a flag has +already previously been provided, it won't attempt to tab-complete it again. +When no completion results exists, a hint for the current argument will be +displayed to help the user. + +.. _arg_decorators: https://github.com/python-cmd2/cmd2/blob/master/examples/arg_decorators.py +.. _colors: https://github.com/python-cmd2/cmd2/blob/master/examples/colors.py +.. _tab_autocompletion: https://github.com/python-cmd2/cmd2/blob/master/examples/tab_autocompletion..py + + +CompletionItem For Providing Extra Context +------------------------------------------ + +When tab-completing things like a unique ID from a database, it can often be +beneficial to provide the user with some extra context about the item being +completed, such as a description. To facilitate this, ``cmd2`` defines the +``CompletionItem`` class which can be used in combination with +``choices_function`` or ``choices_method``. + +.. autoclass:: cmd2.argparse_custom.CompletionItem + :members: + +See the tab_autocompletion_ example or the implementation of the built-in +**set** command for demonstration of how this is used. diff --git a/examples/arg_decorators.py b/examples/arg_decorators.py new file mode 100755 index 00000000..a085341d --- /dev/null +++ b/examples/arg_decorators.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +# coding=utf-8 +"""An example demonstrating how use one of cmd2's argument parsing decorators""" +import argparse +import os + +import cmd2 + + +class ArgparsingApp(cmd2.Cmd): + def __init__(self): + super().__init__(use_ipython=True) + self.intro = 'cmd2 has awesome decorators to make it easy to use Argparse to parse command arguments' + + # do_fsize parser + fsize_parser = cmd2.Cmd2ArgumentParser(description='Obtain the size of a file') + fsize_parser.add_argument('-c', '--comma', action='store_true', + help='add comma for thousands separator') + fsize_parser.add_argument('-u', '--unit', choices=['MB', 'KB'], help='unit to display size in') + fsize_parser.add_argument('file_path', help='path of file', + completer_method=cmd2.Cmd.path_complete) + + @cmd2.with_argparser(fsize_parser) + def do_fsize(self, args: argparse.Namespace) -> None: + """Obtain the size of a file""" + expanded_path = os.path.expanduser(args.file_path) + + try: + size = os.path.getsize(expanded_path) + except OSError as ex: + self.perror("Error retrieving size: {}".format(ex)) + return + + if args.unit == 'KB': + size /= 1024 + elif args.unit == 'MB': + size /= 1024 * 1024 + else: + args.unit = 'bytes' + size = round(size, 2) + + if args.comma: + size = '{:,}'.format(size) + self.poutput('{} {}'.format(size, args.unit)) + + # do_pow parser + pow_parser = argparse.ArgumentParser() + pow_parser.add_argument('base', type=int) + pow_parser.add_argument('exponent', type=int, choices=range(-5, 6)) + + @cmd2.with_argparser(pow_parser) + def do_pow(self, args: argparse.Namespace) -> None: + """Raise an integer to a small integer exponent, either positive or negative""" + self.poutput('{} ** {} == {}'.format(args.base, args.exponent, args.base ** args.exponent)) + + +if __name__ == '__main__': + app = ArgparsingApp() + app.cmdloop() diff --git a/examples/basic.py b/examples/basic.py new file mode 100755 index 00000000..75672a6b --- /dev/null +++ b/examples/basic.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# coding=utf-8 +"""A simple example demonstrating the following: + 1) How to add a command + 2) How to add help for that command + 3) Persistent history + 4) How to run an initialization script at startup + 5) How to add custom command aliases using the alias command + 6) Shell-like capabilities +""" +import cmd2 +from cmd2 import style + + +class BasicApp(cmd2.Cmd): + CUSTOM_CATEGORY = 'My Custom Commands' + + def __init__(self): + super().__init__(multiline_commands=['echo'], persistent_history_file='cmd2_history.dat', + startup_script='scripts/startup.txt', use_ipython=True) + + self.intro = style('Welcome to PyOhio 2019 and cmd2!', fg='red', bg='white', bold=True) + ' 😀' + + # Allow access to your application in py and ipy via self + self.locals_in_py = True + + # Set the default category name + self.default_category = 'cmd2 Built-in Commands' + + @cmd2.with_category(CUSTOM_CATEGORY) + def do_intro(self, _): + """Display the intro banner""" + self.poutput(self.intro) + + @cmd2.with_category(CUSTOM_CATEGORY) + def do_echo(self, arg): + """Example of a multiline command""" + self.poutput(arg) + + +if __name__ == '__main__': + app = BasicApp() + app.cmdloop() |