2
Digress's CLI interface.
7
from optparse import OptionParser
11
from types import MethodType
13
from digress import __version__ as version
15
def dispatchable(func):
17
Mark a method as dispatchable.
19
func.digress_dispatchable = True
22
class Dispatcher(object):
24
Dispatcher for CLI commands.
26
def __init__(self, fixture):
27
self.fixture = fixture
28
fixture.dispatcher = self
30
def _monkey_print_help(self, optparse, *args, **kwargs):
31
# monkey patches OptionParser._print_help
32
OptionParser.print_help(optparse, *args, **kwargs)
34
print >>sys.stderr, "\nAvailable commands:"
36
maxlen = max([ len(command_name) for command_name in self.commands ])
38
descwidth = 80 - maxlen - 4
40
for command_name, command_meth in self.commands.iteritems():
41
print >>sys.stderr, " %s %s\n" % (
42
command_name.ljust(maxlen + 1),
43
("\n" + (maxlen + 4) * " ").join(
44
textwrap.wrap(" ".join(filter(
46
command_meth.__doc__.strip().replace("\n", " ").split(" ")
53
def _enable_flush(self):
54
self.fixture.flush_before = True
56
def _populate_parser(self):
57
self.commands = self._get_commands()
59
self.optparse = OptionParser(
60
usage = "usage: %prog [options] command [args]",
61
description = "Digress CLI frontend for %s." % self.fixture.__class__.__name__,
62
version = "Digress %s" % version
65
self.optparse.print_help = MethodType(self._monkey_print_help, self.optparse, OptionParser)
67
self.optparse.add_option(
71
callback=lambda option, opt, value, parser: self._enable_flush(),
72
help="flush existing data for a revision before testing"
75
self.optparse.add_option(
82
callback=lambda option, opt, value, parser: self._select_cases(*value.split(",")),
83
help="test cases to run, run with command list to see full list"
86
def _select_cases(self, *cases):
87
self.fixture.cases = filter(lambda case: case.__name__ in cases, self.fixture.cases)
89
def _get_commands(self):
92
for name, member in inspect.getmembers(self.fixture):
93
if hasattr(member, "digress_dispatchable"):
94
commands[name] = member
98
def _run_command(self, name, *args):
99
if name not in self.commands:
100
print >>sys.stderr, "error: %s is not a valid command\n" % name
101
self.optparse.print_help()
104
command = self.commands[name]
106
argspec = inspect.getargspec(command)
108
max_arg_len = len(argspec.args) - 1
109
min_arg_len = max_arg_len - ((argspec.defaults is not None) and len(argspec.defaults) or 0)
111
if len(args) < min_arg_len:
112
print >>sys.stderr, "error: %s takes at least %d arguments\n" % (
116
print >>sys.stderr, "%s\n" % command.__doc__
117
self.optparse.print_help()
120
if len(args) > max_arg_len:
121
print >>sys.stderr, "error: %s takes at most %d arguments\n" % (
125
print >>sys.stderr, "%s\n" % command.__doc__
126
self.optparse.print_help()
131
def pre_dispatch(self):
135
self._populate_parser()
137
self.optparse.parse_args()
139
args = self.optparse.parse_args()[1] # arguments may require reparsing after pre_dispatch; see test_x264.py
142
print >>sys.stderr, "error: no comamnd specified\n"
143
self.optparse.print_help()
149
self._run_command(command, *addenda)