1
0
Fork 0

code cleanup for argparse support (addresses #33)

* remove unused code from CliCommand class
 * improve parameter handling in BackendTo constructor
 * return entity in BackendEntityHandler's create method
 * add a default value for country in ClientCli
 * pass dictionary from parsed arguments to ClientHandler's create
   method
 * correctly handle special chars in ClientCli output
This commit is contained in:
Jan Dittberner 2009-08-01 17:10:28 +02:00
parent b8139e91f2
commit 45b2865e8e
4 changed files with 33 additions and 174 deletions

View file

@ -58,6 +58,7 @@ class BackendEntityHandler(object):
sess.rollback()
self.logger.exception("Exception in create.")
raise
return entity
def fetchall(self, **kwargs):
"""Fetches all entities of the managed entity type."""

View file

@ -26,13 +26,14 @@ class BackendTo(object):
"""Backend transfer object class."""
def __init__(self, config, **kwargs):
cols = object_mapper(self).local_table.columns.keys()
for (key, value) in kwargs.items():
if key in cols and value is not None:
self.__setattr__(key, unicode(value, 'utf8'))
def __repr__(self, **kwargs):
if 'verbose' in kwargs and kwargs['verbose']:
cols = [col for col in \
object_mapper(self).local_table.columns.keys()]
cols = object_mapper(self).local_table.columns.keys()
format = "%(class)s:"
format = format + ", ".join([col + "=%(" + col + ")s" for col in \
cols])

View file

@ -25,181 +25,38 @@ from gnuviechadmin.exceptions import GnuviechadminError
class CliCommand(object):
"""Base class for command line interface.
"""
Base class for command line interface.
A specific implementation class must define the fields name,
description and _optionmap.
The field name is the name of the subcommand.
The field description is a short, one line description of the
command.
The field _optionmap is a map which maps the subcommand names to
lists of tuples. Each tuple consists of four elements. The first
element is a list of command line arguments, short arguments start
with dash, long arguments with a double dash. The second element
is the name of the field in the data map of the command, it will
directly be sent to the underlying entity. The third field is a
description for the group of command line options in field
one. The fourth field is True for mandatory fields and False
otherwise.
A specific implementation class must implement the static
setup_arparser method and the _execute method.
"""
def _usage(self):
"""This method shows usage information. The implementation
relies on the information in the fields name, description and
_optionmap in the implementation classes."""
return """GNUViechAdmin command line interface
@staticmethod
def setup_argparser(subparsers):
"""
This static method is used to initialize the command line
argument parser.
Subcommand: %(command)s
%(description)s
Usage:
%(called)s %(command)s -h|--help
gives this usage information.
Common options:
%(option)s
%(mandatory)s %(optiondesc)s
""" % {'called': sys.argv[0],
'command': self.name,
'description': self.description,
'option': '-v, --verbose',
'optiondesc': 'verbose operation',
'mandatory': " "}
for commandname in self._optionmap.keys():
cmdl = "%(called)s %(command)s %(subcommand)s [-v|--verbose]" % {
'called': sys.argv[0],
'command': self.name,
'subcommand': commandname}
desc = """
%s
""" % (self._optionmap[commandname][0])
for (options, field, optiondesc, mandatory) in \
self._optionmap[commandname][1]:
cmd = " "
pairs = []
for option in options:
if field:
if option.startswith("--"):
pairs.append("%s=<%s>" % (option, field))
else:
pairs.append("%s <%s>" % (option, field))
else:
pairs.append(option)
if not mandatory:
cmd = cmd + "["
cmd = cmd + "|".join(pairs)
if not mandatory:
cmd = cmd + "]"
descmap = {
'option': ", ".join(pairs),
'optiondesc': optiondesc,
'mandatory': ' '}
if mandatory:
descmap['mandatory'] = '*'
desc = desc + """ %(option)s
%(mandatory)s %(optiondesc)s
""" % descmap
if (len(cmdl) + len(cmd)) > 79:
print cmdl
cmdl = cmd
else:
cmdl = cmdl + cmd
print cmdl
print desc
print "Mandatory options are marked with *"
def _subcommands(self):
"""Convenience method for retrieving the subcommand names from
the _optionmap field."""
return self._optionmap.keys()
def _longopts(self, subcommand):
"""This method retrieves available long options in a format
valid for getopt.gnu_getopt(...) from the _optionmap field."""
longopts = []
for cur in [(option[0], option[1]) for option in \
self._optionmap[subcommand][1]]:
for command in cur[0]:
if command.startswith("--"):
if cur[1]:
longopts.append(command[2:] + "=")
else:
longopts.append(command[2:])
return longopts
def _shortopts(self, subcommand):
"""This method retrieves available short options in a format
valid for getopt.gnu_getopt(...) from the _optionmap field."""
shortopts = ""
for cur in [(option[0], option[1]) for option in \
self._optionmap[subcommand][1]]:
for command in cur[0]:
if not command.startswith("--"):
if cur[1]:
shortopts = shortopts + command[1:] + ":"
else:
shortopts = shortopts + command[1:]
return shortopts
def _checkrequired(self, subcommand):
"""Checks whether the required fields of the given subcommand
are set."""
reqcheck = [True, []]
for req in [option for option in \
self._optionmap[subcommand][1] if option[3]]:
if not req[1] in self._data:
reqcheck[0] = False
reqcheck[1].append(""" %s
* %s""" % (", ".join(req[0]), req[2]))
return reqcheck
def _handleoption(self, subcommand, o, a):
"""Handles a command line option by assigning it to the
matching key as defined in the _optionmap property of the
implementation class."""
optionmap = [(option[0], option[1]) for option in \
self._optionmap[subcommand][1]]
if optionmap:
for (options, datakey) in optionmap:
if o in options:
self._data[datakey] = a
def _execute(self, subcommand):
"""This method is called when the subcommand of the command is
executed."""
The method has to be overridden by subclasses.
"""
raise NotImplementedError
def _parseopts(self, subcommand, args):
"""This method parses the options given on the command line."""
longopts = ["help", "verbose"]
longopts.extend(self._longopts(subcommand))
try:
opts, args = getopt.gnu_getopt(
args,
"hv" + self._shortopts(subcommand),
longopts)
except getopt.GetoptError:
self._usage()
sys.exit(2)
self._verbose = False
for o, a in opts:
if o in ("-v", "--verbose"):
self._verbose = True
if o in ("-h", "--help"):
self._usage()
sys.exit()
self._handleoption(subcommand, o, a)
def _execute(self):
"""
This method is called when the subcommand of the command is
executed.
The method has to be overridden by subclasses.
"""
raise NotImplementedError
def __init__(self, args, config):
"""This initializes the command with the given command line
arguments and executes it."""
"""
This initializes the command with the given command line
arguments and executes it.
"""
self.config = config
self.args = args
self.logger = logging.getLogger("%s.%s" % (

View file

@ -60,7 +60,7 @@ class ClientCli(CliCommand.CliCommand):
help = _("the city of the client's address"))
cmdparser.add_argument(
'--country',
help = _("the client's country"))
help = _("the client's country"), default='de')
cmdparser.add_argument(
'-e', '--email', required = True,
help = _("the client's email address"))
@ -91,9 +91,9 @@ class ClientCli(CliCommand.CliCommand):
ch = ClientHandler(self.config, self.args.verbose)
if self.args.subcommand == "create":
try:
myclient = ch.create(**self.args)
myclient = ch.create(**self.args.__dict__)
if self.args.verbose:
print myclient
print unicode(myclient).encode('utf8')
except CreationFailedError, cfe:
self._usage()
print cfe
@ -101,7 +101,7 @@ class ClientCli(CliCommand.CliCommand):
elif self.args.subcommand == "list":
clients = ch.fetchall()
for client in clients:
print client
print unicode(client).encode('utf8')
elif self.args.subcommand == "delete":
ch.delete(self.args.clientid)