add ShowOne base class for commands that need to show properties of an individual object
make the table formatter work as a single object formatter update the docs for the new features
This commit is contained in:
parent
b8f3ad548d
commit
556495e530
|
@ -18,9 +18,33 @@ class Formatter(object):
|
|||
|
||||
|
||||
class ListFormatter(Formatter):
|
||||
"""Base class for formatters that know how to deal with multiple objects.
|
||||
"""
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
@abc.abstractmethod
|
||||
def emit_list(self, column_names, data, stdout):
|
||||
def emit_list(self, column_names, data, stdout, parsed_args):
|
||||
"""Format and print the list from the iterable data source.
|
||||
|
||||
:param column_names: names of the columns
|
||||
:param data: iterable data source, one tuple per object
|
||||
with values in order of column names
|
||||
:param stdout: output stream where data should be written
|
||||
:param parsed_args: argparse namespace from our local options
|
||||
"""
|
||||
|
||||
|
||||
class SingleFormatter(Formatter):
|
||||
"""Base class for formatters that work with single objects.
|
||||
"""
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
@abc.abstractmethod
|
||||
def emit_one(self, column_names, data, stdout, parsed_args):
|
||||
"""Format and print the values associated with the single object.
|
||||
|
||||
:param column_names: names of the columns
|
||||
:param data: iterable data source with values in order of column names
|
||||
:param stdout: output stream where data should be written
|
||||
:param parsed_args: argparse namespace from our local options
|
||||
"""
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
|
||||
import prettytable
|
||||
|
||||
from .base import ListFormatter
|
||||
from .base import ListFormatter, SingleFormatter
|
||||
|
||||
|
||||
class TableLister(ListFormatter):
|
||||
class TableFormatter(ListFormatter, SingleFormatter):
|
||||
|
||||
ALIGNMENTS = {
|
||||
int: 'r',
|
||||
|
@ -48,3 +48,19 @@ class TableLister(ListFormatter):
|
|||
stdout.write(formatted)
|
||||
stdout.write('\n')
|
||||
return
|
||||
|
||||
def emit_one(self, column_names, data, stdout, parsed_args):
|
||||
x = prettytable.PrettyTable(('Field', 'Value'))
|
||||
x.set_padding_width(1)
|
||||
# Align all columns left because the values are
|
||||
# not all the same type.
|
||||
x.set_field_align('Field', 'l')
|
||||
x.set_field_align('Value', 'l')
|
||||
desired_columns = parsed_args.columns
|
||||
for name, value in zip(column_names, data):
|
||||
if name in desired_columns or not desired_columns:
|
||||
x.add_row((name, value))
|
||||
formatted = x.get_string(fields=('Field', 'Value'))
|
||||
stdout.write(formatted)
|
||||
stdout.write('\n')
|
||||
return
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
"""Application base class for displaying data about a single object.
|
||||
"""
|
||||
import abc
|
||||
import logging
|
||||
|
||||
import pkg_resources
|
||||
|
||||
from .command import Command
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ShowOne(Command):
|
||||
"""Command base class for displaying data about a single object.
|
||||
"""
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
def __init__(self, app, app_args):
|
||||
super(ShowOne, self).__init__(app, app_args)
|
||||
self.load_formatter_plugins()
|
||||
|
||||
def load_formatter_plugins(self):
|
||||
self.formatters = {}
|
||||
for ep in pkg_resources.iter_entry_points('cliff.formatter.show'):
|
||||
try:
|
||||
self.formatters[ep.name] = ep.load()()
|
||||
except Exception as err:
|
||||
LOG.error(err)
|
||||
if self.app_args.debug:
|
||||
raise
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowOne, self).get_parser(prog_name)
|
||||
formatter_group = parser.add_argument_group(
|
||||
title='Output Formatters',
|
||||
description='List output formatter options',
|
||||
)
|
||||
formatter_choices = sorted(self.formatters.keys())
|
||||
formatter_default = 'table'
|
||||
if formatter_default not in formatter_choices:
|
||||
formatter_default = formatter_choices[0]
|
||||
formatter_group.add_argument(
|
||||
'-f', '--format',
|
||||
dest='formatter',
|
||||
action='store',
|
||||
choices=formatter_choices,
|
||||
default=formatter_default,
|
||||
help='the output format to use, defaults to %s' % formatter_default,
|
||||
)
|
||||
for name, formatter in sorted(self.formatters.items()):
|
||||
formatter.add_argument_group(parser)
|
||||
return parser
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_data(self, parsed_args):
|
||||
"""Return a two-part tuple with a tuple of column names
|
||||
and a tuple of values.
|
||||
"""
|
||||
|
||||
def run(self, parsed_args):
|
||||
column_names, data = self.get_data(parsed_args)
|
||||
formatter = self.formatters[parsed_args.formatter]
|
||||
formatter.emit_one(column_names, data, self.app.stdout, parsed_args)
|
||||
return 0
|
|
@ -0,0 +1,31 @@
|
|||
import logging
|
||||
import os
|
||||
|
||||
from cliff.show import ShowOne
|
||||
|
||||
|
||||
class File(ShowOne):
|
||||
"Show details about a file"
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(File, self).get_parser(prog_name)
|
||||
parser.add_argument('filename', nargs='?', default='.')
|
||||
return parser
|
||||
|
||||
def get_data(self, parsed_args):
|
||||
stat_data = os.stat(parsed_args.filename)
|
||||
columns = ('Name',
|
||||
'Size',
|
||||
'UID',
|
||||
'GID',
|
||||
'Modified Time',
|
||||
)
|
||||
data = (parsed_args.filename,
|
||||
stat_data.st_size,
|
||||
stat_data.st_uid,
|
||||
stat_data.st_gid,
|
||||
stat_data.st_mtime,
|
||||
)
|
||||
return (columns, data)
|
|
@ -166,6 +166,7 @@ setup(
|
|||
'two_part = cliffdemo.simple:Simple',
|
||||
'error = cliffdemo.simple:Error',
|
||||
'files = cliffdemo.list:Files',
|
||||
'file = cliffdemo.show:File',
|
||||
],
|
||||
},
|
||||
|
||||
|
|
|
@ -20,6 +20,12 @@ Command
|
|||
.. autoclass:: cliff.command.Command
|
||||
:members:
|
||||
|
||||
ShowOne
|
||||
=======
|
||||
|
||||
.. autoclass:: cliff.show.ShowOne
|
||||
:members:
|
||||
|
||||
Lister
|
||||
======
|
||||
|
||||
|
@ -37,3 +43,9 @@ ListFormatter
|
|||
|
||||
.. autoclass:: cliff.formatters.base.ListFormatter
|
||||
:members:
|
||||
|
||||
SingleFormatter
|
||||
===============
|
||||
|
||||
.. autoclass:: cliff.formatters.base.SingleFormatter
|
||||
:members:
|
||||
|
|
|
@ -199,6 +199,35 @@ output formatter and printing the data to the console.
|
|||
"Makefile",5569
|
||||
"source",408
|
||||
|
||||
.. _demoapp-show:
|
||||
|
||||
show.py
|
||||
-------
|
||||
|
||||
``show.py`` includes a single command derived from
|
||||
:class:`cliff.show.ShowOne` which prints the properties of the named
|
||||
file.
|
||||
|
||||
.. literalinclude:: ../../demoapp/cliffdemo/show.py
|
||||
:linenos:
|
||||
|
||||
:class:`File` prepares the data, and :class:`ShowOne` manages the
|
||||
output formatter and printing the data to the console.
|
||||
|
||||
::
|
||||
|
||||
(.venv)$ cliffdemo file setup.py
|
||||
+---------------+--------------+
|
||||
| Field | Value |
|
||||
+---------------+--------------+
|
||||
| Name | setup.py |
|
||||
| Size | 5825 |
|
||||
| UID | 502 |
|
||||
| GID | 20 |
|
||||
| Modified Time | 1335569964.0 |
|
||||
+---------------+--------------+
|
||||
|
||||
|
||||
setup.py
|
||||
--------
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ Contents:
|
|||
introduction
|
||||
demoapp
|
||||
list_commands
|
||||
show_commands
|
||||
classes
|
||||
install
|
||||
developers
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
===============
|
||||
Show Commands
|
||||
===============
|
||||
|
||||
One of the most common patterns with command line programs is the need
|
||||
to print properties of objects. cliff provides a base class for
|
||||
commands of this type so that they only need to prepare the data, and
|
||||
the user can choose from one of several output formatter plugins to
|
||||
see the data in their preferred format.
|
||||
|
||||
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
|
||||
names. See the description of :ref:`the file command in the demoapp
|
||||
<demoapp-show>` for details.
|
||||
|
||||
Show Output Formatters
|
||||
======================
|
||||
|
||||
cliff is delivered with output formatters for show
|
||||
commands. :class:`ShowOne` adds a command line switch to let the user
|
||||
specify the formatter they want, so you don't have to do any extra
|
||||
work in your application.
|
||||
|
||||
PrettyTable
|
||||
-----------
|
||||
|
||||
The ``PrettyTable`` formatter uses PrettyTable_ to produce output
|
||||
formatted for human consumption.
|
||||
|
||||
.. _PrettyTable: http://code.google.com/p/prettytable/
|
||||
|
||||
::
|
||||
|
||||
(.venv)$ cliffdemo file setup.py
|
||||
+---------------+--------------+
|
||||
| Field | Value |
|
||||
+---------------+--------------+
|
||||
| Name | setup.py |
|
||||
| Size | 5825 |
|
||||
| UID | 502 |
|
||||
| GID | 20 |
|
||||
| Modified Time | 1335569964.0 |
|
||||
+---------------+--------------+
|
||||
|
||||
Creating Your Own Formatter
|
||||
---------------------------
|
||||
|
||||
If the standard formatters do not meet your needs, you can bundle
|
||||
another formatter with your program by subclassing from
|
||||
:class:`cliff.formatters.base.ShowFormatter` and registering the
|
||||
plugin in the ``cliff.formatter.show`` namespace.
|
||||
|
5
setup.py
5
setup.py
|
@ -162,9 +162,12 @@ setup(
|
|||
|
||||
entry_points={
|
||||
'cliff.formatter.list': [
|
||||
'table = cliff.formatters.table:TableLister',
|
||||
'table = cliff.formatters.table:TableFormatter',
|
||||
'csv = cliff.formatters.commaseparated:CSVLister',
|
||||
],
|
||||
'cliff.formatter.show': [
|
||||
'table = cliff.formatters.table:TableFormatter',
|
||||
],
|
||||
},
|
||||
|
||||
zip_safe=False,
|
||||
|
|
Loading…
Reference in New Issue