documentation improvements

This commit is contained in:
Doug Hellmann 2012-04-28 19:11:25 -04:00
parent 0fba728779
commit ab200eb505
10 changed files with 189 additions and 19 deletions

View File

@ -15,6 +15,21 @@ LOG = logging.getLogger(__name__)
class App(object):
"""Application base class.
:param description: one-liner explaining the program purpose
:paramtype description: str
:param version: application version number
:paramtype version: str
:param command_manager: plugin loader
:paramtype command_manager: cliff.commandmanager.CommandManager
:param stdin: Standard input stream
:paramtype stdin: readable I/O stream
:param stdout: Standard output stream
:paramtype stdout: writable I/O stream
:param stderr: Standard error output stream
:paramtype stderr: writable I/O stream
:param interactive_app_factory: callable to create an interactive application
:paramtype interactive_app_factory: cliff.interactive.InteractiveApp
"""
NAME = os.path.splitext(os.path.basename(sys.argv[0]))[0]
@ -24,21 +39,16 @@ class App(object):
DEFAULT_VERBOSE_LEVEL = 1
def __init__(self, description, version, command_manager,
stdin=None, stdout=None, stderr=None):
stdin=None, stdout=None, stderr=None,
interactive_app_factory=InteractiveApp):
"""Initialize the application.
:param description: One liner explaining the program purpose
:param version: String containing the application version number
:param command_manager: A CommandManager instance
:param stdin: Standard input stream
:param stdout: Standard output stream
:param stderr: Standard error output stream
"""
self.command_manager = command_manager
self.command_manager.add_command('help', HelpCommand)
self.stdin = stdin or sys.stdin
self.stdout = stdout or sys.stdout
self.stderr = stderr or sys.stderr
self.interactive_app_factory = interactive_app_factory
self.parser = self.build_option_parser(description, version)
self.interactive_mode = False
@ -47,6 +57,11 @@ class App(object):
Subclasses may override this method to extend
the parser with more global options.
:param description: full description of the application
:paramtype description: str
:param version: version number for the application
:paramtype version: str
"""
parser = argparse.ArgumentParser(
description=description,
@ -116,6 +131,9 @@ class App(object):
def run(self, argv):
"""Equivalent to the main program for the application.
:param argv: input arguments and options
:paramtype argv: list of str
"""
self.options, remainder = self.parser.parse_known_args(argv)
self.configure_logging()
@ -138,17 +156,27 @@ class App(object):
def prepare_to_run_command(self, cmd):
"""Perform any preliminary work needed to run a command.
:param cmd: command processor being invoked
:paramtype cmd: cliff.command.Command
"""
return
def clean_up(self, cmd, result, err):
"""Hook run after a command is done to shutdown the app.
:param cmd: command processor being invoked
:paramtype cmd: cliff.command.Command
:param result: return value of cmd
:paramtype result: int
:param err: exception or None
:paramtype err: Exception
"""
return
def interact(self):
self.interactive_mode = True
interpreter = InteractiveApp(self, self.command_manager, self.stdin, self.stdout)
interpreter = self.interactive_app_factory(self, self.command_manager, self.stdin, self.stdout)
interpreter.prompt = '(%s) ' % self.NAME
interpreter.cmdloop()
return 0

View File

@ -6,6 +6,9 @@ import inspect
class Command(object):
"""Base class for command plugins.
:param app: Application instance invoking the command.
:paramtype app: cliff.app.App
"""
__metaclass__ = abc.ABCMeta

View File

@ -23,6 +23,10 @@ class EntryPointWrapper(object):
class CommandManager(object):
"""Discovers commands and handles lookup based on argv data.
:param namespace: String containing the setuptools entrypoint namespace
for the plugins to be loaded. For example,
``'cliff.formatter.list'``.
"""
def __init__(self, namespace):
self.commands = {}

View File

@ -12,6 +12,20 @@ LOG = logging.getLogger(__name__)
class InteractiveApp(cmd2.Cmd):
"""Provides "interactive mode" features.
Refer to the cmd2_ and cmd_ documentation for details
about subclassing and configuring this class.
.. _cmd2: http://packages.python.org/cmd2/index.html
.. _cmd: http://docs.python.org/library/cmd.html
:param parent_app: The calling application (expected to be derived
from :class:`cliff.main.App`).
:param command_manager: A :class:`cliff.commandmanager.CommandManager` instance.
:param stdin: Standard input stream
:param stdout: Standard output stream
"""
use_rawinput = True
doc_header = "Shell commands (type help <topic>):"
@ -32,10 +46,8 @@ class InteractiveApp(cmd2.Cmd):
self.parent_app.run_subcommand(line_parts)
def completedefault(self, text, line, begidx, endidx):
"""Tab-completion for commands known to the command manager.
Does not handle options on the commands.
"""
# Tab-completion for commands known to the command manager.
# Does not handle options on the commands.
if not text:
completions = sorted(n for n, v in self.command_manager)
else:
@ -75,6 +87,9 @@ class InteractiveApp(cmd2.Cmd):
return
def get_names(self):
# Override the base class version to filter out
# things that look like they should be hidden
# from the user.
return [n
for n in cmd2.Cmd.get_names(self)
if not n.startswith('do__')

View File

@ -8,6 +8,12 @@ App
.. autoclass:: cliff.app.App
:members:
InteractiveApp
==============
.. autoclass:: cliff.interactive.InteractiveApp
:members:
CommandManager
==============

View File

@ -85,14 +85,20 @@ The :class:`DemoApp` class inherits from :class:`App` and overrides
also passes a :class:`CommandManager` instance configured to look for
plugins in the ``cliff.demo`` namespace.
The :func:`prepare_to_run_command` method of :class:`DemoApp` will be
invoked after the main program arguments are parsed and the command is
identified, but before the command is given its arguments and
run. This hook is intended for opening connections to remote web
The :func:`initialize_app` method of :class:`DemoApp` will be invoked
after the main program arguments are parsed, but before any command
processing is performed and before the application enters interactive
mode. This hook is intended for opening connections to remote web
services, databases, etc. using arguments passed to the main
application.
The :func:`clean_up` method of :class:`DemoApp` is invoked after the
The :func:`prepare_to_run_command` method of :class:`DemoApp` will be
invoked after a command is identified, but before the command is given
its arguments and run. This hook is intended for pre-command
validation or setup that must be repeated and cannot be handled by
:func:`initialize_app`.
The :func:`clean_up` method of :class:`DemoApp` is invoked after a
command runs. If the command raised an exception, the exception object
is passed to :func:`clean_up`. Otherwise the ``err`` argument is
``None``.

View File

@ -5,6 +5,8 @@
dev
- Add shell formatter for single objects.
- Add interactive mode.
- Expand documentation.
0.3

View File

@ -15,6 +15,7 @@ Contents:
demoapp
list_commands
show_commands
interactive_mode
classes
install
developers
@ -27,3 +28,5 @@ Indices and tables
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
.. todolist::

View File

@ -0,0 +1,94 @@
==================
Interactive Mode
==================
In addition to running single commands from the command line, cliff
supports an interactive mode in which the user is presented with a
separate command shell. All of the command plugins available from the
command line are automatically configured as commands within the
shell.
Refer to the cmd2_ documentation for more details about features of
the shell.
.. _cmd2: http://packages.python.org/cmd2/index.html
.. todo:: Add details about configuring and interacting with the shell (copy from cmd2 docs)
Example
=======
The ``cliffdemo`` application enters interactive mode if no command is
specified on the command line.
::
(.venv)$ cliffdemo
(cliffdemo) help
Shell commands (type help <topic>):
===================================
cmdenvironment edit hi l list pause r save shell show
ed help history li load py run set shortcuts
Undocumented commands:
======================
EOF eof exit q quit
Application commands (type help <topic>):
=========================================
files help simple file error two part
To obtain instructions for a built-in or application command, use the
``help`` command:
::
(cliffdemo) help simple
usage: simple [-h]
A simple command that prints a message.
optional arguments:
-h, --help show this help message and exit
The commands can be run, including options and arguments, as on the
regular command line:
::
(cliffdemo) simple
sending greeting
hi!
(cliffdemo) files
+----------------------+-------+
| Name | Size |
+----------------------+-------+
| .git | 578 |
| .gitignore | 268 |
| .tox | 238 |
| .venv | 204 |
| announce.rst | 1015 |
| announce.rst~ | 708 |
| cliff | 884 |
| cliff.egg-info | 340 |
| cliffdemo.log | 2193 |
| cliffdemo.log.1 | 10225 |
| demoapp | 408 |
| dist | 136 |
| distribute_setup.py | 15285 |
| distribute_setup.pyc | 15196 |
| docs | 238 |
| LICENSE | 11358 |
| Makefile | 376 |
| Makefile~ | 94 |
| MANIFEST.in | 186 |
| MANIFEST.in~ | 344 |
| README.rst | 1063 |
| setup.py | 5855 |
| setup.py~ | 8128 |
| tests | 204 |
| tox.ini | 76 |
| tox.ini~ | 421 |
+----------------------+-------+
(cliffdemo)

View File

@ -19,7 +19,7 @@ fit.
Cliff Objects
=============
Cliff is organized around three objects that are combined to create a
Cliff is organized around four objects that are combined to create a
useful command line program.
The Application
@ -50,6 +50,15 @@ responsible for taking action based on instructions from the user. It
defines its own local argument parser (usually using argparse_) and a
:func:`run` method that does the appropriate work.
The Interactive Application
---------------------------
The main program uses an :class:`cliff.interactive.InteractiveApp`
instance to provide a command-shell mode in which the user can type
multiple commands before the program exits. Many cliff-based
applications will be able to use the default implementation of
:class:`InteractiveApp` without subclassing it.
.. _setuptools entry points: http://packages.python.org/distribute/setuptools.html
.. _argparse: http://docs.python.org/library/argparse.html