From 83469ad81a27f0b264bd93904b2b172fd889cad9 Mon Sep 17 00:00:00 2001 From: Doug Hellmann Date: Wed, 20 Jun 2012 17:27:08 -0400 Subject: Doc updates for API changes. Clean up docstrings. Bump version to 1.0. Change-Id: I1047c637ffed4ffac8bffbdaa1bddc56895716d9 --- announce.rst | 12 +++++++++--- cliff/app.py | 6 +++++- cliff/command.py | 14 ++++++++++---- cliff/help.py | 14 ++++++++++++-- demoapp/cliffdemo/simple.py | 4 ++-- docs/source/conf.py | 2 +- docs/source/demoapp.rst | 16 +++++++++++----- docs/source/history.rst | 8 +++++++- docs/source/introduction.rst | 2 +- docs/source/list_commands.rst | 12 ++++++------ docs/source/show_commands.rst | 9 +++++---- setup.py | 2 +- 12 files changed, 70 insertions(+), 31 deletions(-) diff --git a/announce.rst b/announce.rst index 033fcc4..39e3f67 100644 --- a/announce.rst +++ b/announce.rst @@ -11,9 +11,15 @@ other extensions. What's New In This Release? =========================== -- Clean up interactive mode flag settting. -- Add support for Python 2.6, contributed by heavenshell. -- Fix multi-word commands in interactive mode. +- Add trailing newlines after output from tablib-based formatters + (JSON, YAML, and HTML). Contributed by Matt Joyce. +- Some PEP-8 fixes. +- Refactor the API in ``Command`` to add ``take_action()`` + and make ``run()`` a concrete method. Existing users should only + need to rename ``run()`` to ``take_action()`` since the function + signatures have not changed. +- In ``Lister`` and ``ShowOne`` use ``take_action()`` instead of + ``get_data()``. Documentation ============= diff --git a/cliff/app.py b/cliff/app.py index 06c679f..bc0b65e 100644 --- a/cliff/app.py +++ b/cliff/app.py @@ -143,7 +143,11 @@ class App(object): self.interactive_mode = not remainder self.initialize_app(remainder) except Exception as err: - if self.options.debug: + if hasattr(self, 'options'): + debug = self.options.debug + else: + debug = True + if debug: LOG.exception(err) raise else: diff --git a/cliff/command.py b/cliff/command.py index e369988..1661313 100644 --- a/cliff/command.py +++ b/cliff/command.py @@ -23,7 +23,7 @@ class Command(object): return inspect.getdoc(self.__class__) or '' def get_parser(self, prog_name): - """Return an argparse.ArgumentParser. + """Return an :class:`argparse.ArgumentParser`. """ parser = argparse.ArgumentParser( description=self.get_description(), @@ -33,12 +33,18 @@ class Command(object): @abc.abstractmethod def take_action(self, parsed_args): - """Return a two-part tuple with a tuple of column names - and a tuple of values. + """Override to do something useful. """ def run(self, parsed_args): - """Do something useful. + """Invoked by the application when the command is run. + + Developers implementing commands should override + :meth:`take_action`. + + Developers creating new command base classes (such as + :class:`Lister` and :class:`ShowOne`) should override this + method to wrap :meth:`take_action`. """ self.take_action(parsed_args) return 0 diff --git a/cliff/help.py b/cliff/help.py index 49cfd16..9a7f848 100644 --- a/cliff/help.py +++ b/cliff/help.py @@ -1,4 +1,5 @@ import argparse +import logging import sys from .command import Command @@ -12,13 +13,22 @@ class HelpAction(argparse.Action): instance, passed in as the "default" value for the action. """ def __call__(self, parser, namespace, values, option_string=None): + log = logging.getLogger(__name__) app = self.default parser.print_help(app.stdout) app.stdout.write('\nCommands:\n') command_manager = app.command_manager for name, ep in sorted(command_manager): - factory = ep.load() - cmd = factory(self, None) + try: + factory = ep.load() + except Exception as err: + app.stdout.write('Could not load %r\n' % ep) + continue + try: + cmd = factory(self, None) + except Exception as err: + app.stdout.write('Could not instantiate %r: %s\n' % (ep, err)) + continue one_liner = cmd.get_description().split('\n')[0] app.stdout.write(' %-13s %s\n' % (name, one_liner)) sys.exit(0) diff --git a/demoapp/cliffdemo/simple.py b/demoapp/cliffdemo/simple.py index 5e8e98e..3800514 100644 --- a/demoapp/cliffdemo/simple.py +++ b/demoapp/cliffdemo/simple.py @@ -8,7 +8,7 @@ class Simple(Command): log = logging.getLogger(__name__) - def run(self, parsed_args): + def take_action(self, parsed_args): self.log.info('sending greeting') self.log.debug('debugging') self.app.stdout.write('hi!\n') @@ -19,6 +19,6 @@ class Error(Command): log = logging.getLogger(__name__) - def run(self, parsed_args): + def take_action(self, parsed_args): self.log.info('causing error') raise RuntimeError('this is the expected exception') diff --git a/docs/source/conf.py b/docs/source/conf.py index 9f71445..9e4b98e 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -48,7 +48,7 @@ copyright = u'2012, Doug Hellmann' # built documents. # # The short X.Y version. -version = '0.7' +version = '1.0' # The full version, including alpha/beta/rc tags. release = version diff --git a/docs/source/demoapp.rst b/docs/source/demoapp.rst index 84ca5d3..66e66cb 100644 --- a/docs/source/demoapp.rst +++ b/docs/source/demoapp.rst @@ -155,19 +155,25 @@ features of cliff. causing error this is the expected exception Traceback (most recent call last): - File ".../cliff/app.py", line 148, in run + File ".../cliff/app.py", line 218, in run_subcommand result = cmd.run(parsed_args) - File ".../demoapp/cliffdemo/simple.py", line 24, in run + File ".../cliff/command.py", line 43, in run + self.take_action(parsed_args) + File ".../demoapp/cliffdemo/simple.py", line 24, in take_action raise RuntimeError('this is the expected exception') RuntimeError: this is the expected exception Traceback (most recent call last): File "/Users/dhellmann/Envs/cliff/bin/cliffdemo", line 9, in load_entry_point('cliffdemo==0.1', 'console_scripts', 'cliffdemo')() - File ".../demoapp/cliffdemo/main.py", line 30, in main + File ".../demoapp/cliffdemo/main.py", line 33, in main return myapp.run(argv) - File ".../cliff/app.py", line 148, in run + File ".../cliff/app.py", line 160, in run + result = self.run_subcommand(remainder) + File ".../cliff/app.py", line 218, in run_subcommand result = cmd.run(parsed_args) - File ".../demoapp/cliffdemo/simple.py", line 24, in run + File ".../cliff/command.py", line 43, in run + self.take_action(parsed_args) + File ".../demoapp/cliffdemo/simple.py", line 24, in take_action raise RuntimeError('this is the expected exception') RuntimeError: this is the expected exception diff --git a/docs/source/history.rst b/docs/source/history.rst index 8775e0d..e391488 100644 --- a/docs/source/history.rst +++ b/docs/source/history.rst @@ -2,11 +2,17 @@ Release History ================= -dev +1.0 - Add trailing newlines after output from tablib-based formatters (JSON, YAML, and HTML). Contributed by Matt Joyce. - Some :pep:`8` fixes. + - Refactor the API in :class:`Command` to add :func:`take_action` + and make :func:`run` a concrete method. Existing users should only + need to rename :func:`run()` to :func:`take_action()` since the + function signatures have not changed. + - In :class:`Lister` and :class:`ShowOne` use :func:`take_action` + instead of :func:`get_data`. 0.7 diff --git a/docs/source/introduction.rst b/docs/source/introduction.rst index 0951f19..d9312b9 100644 --- a/docs/source/introduction.rst +++ b/docs/source/introduction.rst @@ -48,7 +48,7 @@ discover the command plugins and invoke them, and to provide runtime support for those plugins. Each :class:`Command` subclass is 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. +:func:`take_action` method that does the appropriate work. The Interactive Application --------------------------- diff --git a/docs/source/list_commands.rst b/docs/source/list_commands.rst index d4e697c..f76188b 100644 --- a/docs/source/list_commands.rst +++ b/docs/source/list_commands.rst @@ -12,12 +12,12 @@ Lister ====== The :class:`cliff.lister.Lister` base class API extends -:class:`Command` to add a :func:`get_data` method. Subclasses should -provide a :func:`get_data` implementation that returns a two member -tuple containing a tuple with the names of the columns in the dataset -and an iterable that will yield the data to be output. See the -description of :ref:`the files command in the demoapp ` -for details. +:class:`Command` to allow :func:`take_action` to return data to be +formatted using a user-selectable formatter. Subclasses should provide +a :func:`take_action` implementation that returns a two member tuple +containing a tuple with the names of the columns in the dataset and an +iterable that will yield the data to be output. See the description of +:ref:`the files command in the demoapp ` for details. List Output Formatters ====================== diff --git a/docs/source/show_commands.rst b/docs/source/show_commands.rst index 0aa7d9f..e848960 100644 --- a/docs/source/show_commands.rst +++ b/docs/source/show_commands.rst @@ -12,10 +12,11 @@ ShowOne ======= The :class:`cliff.show.ShowOne` base class API extends -:class:`Command` to add a :func:`get_data` method. Subclasses should -provide a :func:`get_data` implementation that returns a two member -tuple containing a tuple with the names of the columns in the dataset -and an iterable that contains the data values associated with those +:class:`Command` to allow :func:`take_action` to return data to be +formatted using a user-selectable formatter. Subclasses should provide +a :func:`take_action` implementation that returns a two member tuple +containing a tuple with the names of the columns in the dataset and an +iterable that contains the data values associated with those names. See the description of :ref:`the file command in the demoapp ` for details. diff --git a/setup.py b/setup.py index 0fd9695..be87252 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ PROJECT = 'cliff' # Change docs/source/conf.py too! -VERSION = '0.7' +VERSION = '1.0' # Bootstrap installation of Distribute import distribute_setup -- cgit v1.2.1