Started cleanup work on CLI class, added unit tests for CLI.parse_globals()

This commit is contained in:
Jason Gerard DeRose 2008-10-27 14:48:02 -06:00
parent d76202fea3
commit 10026284db
3 changed files with 122 additions and 98 deletions

4
ipa
View File

@ -31,5 +31,7 @@ from ipalib.cli import CLI
api.load_plugins() api.load_plugins()
if __name__ == '__main__': if __name__ == '__main__':
cli = CLI(api) cli = CLI(api,
(s.decode('utf-8') for s in sys.args[1:])
)
sys.exit(cli.run()) sys.exit(cli.run())

View File

@ -84,6 +84,24 @@ class help(frontend.Application):
print 'Purpose: %s' % cmd.doc print 'Purpose: %s' % cmd.doc
self.application.build_parser(cmd).print_help() self.application.build_parser(cmd).print_help()
def print_commands(self):
std = set(self.api.Command) - set(self.api.Application)
print '\nStandard IPA commands:'
for key in sorted(std):
cmd = self.api.Command[key]
self.print_cmd(cmd)
print '\nSpecial CLI commands:'
for cmd in self.api.Application():
self.print_cmd(cmd)
print '\nUse the --help option to see all the global options'
print ''
def print_cmd(self, cmd):
print ' %s %s' % (
to_cli(cmd.name).ljust(self.mcl),
cmd.doc,
)
class console(frontend.Application): class console(frontend.Application):
'Start the IPA interactive Python console.' 'Start the IPA interactive Python console.'
@ -207,32 +225,24 @@ class CLI(object):
__d = None __d = None
__mcl = None __mcl = None
def __init__(self, api): def __init__(self, api, argv):
self.__api = api self.api = api
self.__all_interactive = False self.argv = tuple(argv)
self.__not_interactive = False self.__done = set()
def __get_api(self): def __doing(self, name):
return self.__api if name in self.__done:
api = property(__get_api) raise StandardError(
'%s.%s() already called' % (self.__class__.__name__, name)
def print_commands(self):
std = set(self.api.Command) - set(self.api.Application)
print '\nStandard IPA commands:'
for key in sorted(std):
cmd = self.api.Command[key]
self.print_cmd(cmd)
print '\nSpecial CLI commands:'
for cmd in self.api.Application():
self.print_cmd(cmd)
print '\nUse the --help option to see all the global options'
print ''
def print_cmd(self, cmd):
print ' %s %s' % (
to_cli(cmd.name).ljust(self.mcl),
cmd.doc,
) )
self.__done.add(name)
def __do_if_not_done(self, name):
if name not in self.__done:
getattr(self, name)()
def isdone(self, name):
return name in self.__done
def __contains__(self, key): def __contains__(self, key):
assert self.__d is not None, 'you must call finalize() first' assert self.__d is not None, 'you must call finalize() first'
@ -360,10 +370,11 @@ class CLI(object):
parser.add_option(o) parser.add_option(o)
return parser return parser
def parse_globals(self, argv=sys.argv[1:]): def parse_globals(self):
self.__doing('parse_globals')
parser = optparse.OptionParser() parser = optparse.OptionParser()
parser.disable_interspersed_args() parser.disable_interspersed_args()
parser.add_option('-a', dest='interactive', action='store_true', parser.add_option('-a', dest='prompt_all', action='store_true',
help='Prompt for all missing options interactively') help='Prompt for all missing options interactively')
parser.add_option('-n', dest='interactive', action='store_false', parser.add_option('-n', dest='interactive', action='store_false',
help='Don\'t prompt for any options interactively') help='Don\'t prompt for any options interactively')
@ -373,29 +384,39 @@ class CLI(object):
help='Specify or override environment variables') help='Specify or override environment variables')
parser.add_option('-v', dest='verbose', action='store_true', parser.add_option('-v', dest='verbose', action='store_true',
help='Verbose output') help='Verbose output')
(options, args) = parser.parse_args(argv) parser.set_defaults(
prompt_all=False,
interactive=True,
verbose=False,
)
(options, args) = parser.parse_args(list(self.argv))
self.options = options
self.cmd_argv = tuple(args)
if options.interactive == True: def bootstrap(self):
self.__all_interactive = True pass
elif options.interactive == False:
self.__not_interactive = True
if options.verbose != None:
self.api.env.verbose = True
if options.environment:
env_dict = {}
for a in options.environment.split(','):
a = a.split('=', 1)
if len(a) < 2:
parser.error('badly specified environment string,'\
'use var1=val1[,var2=val2]..')
env_dict[a[0].strip()] = a[1].strip()
self.api.env.update(env_dict, True)
if options.config_file:
self.api.env.update(read_config(options.config_file), True)
else:
self.api.env.update(read_config(), True)
return args # if options.interactive == True:
# self.__all_interactive = True
# elif options.interactive == False:
# self.__not_interactive = True
# if options.verbose != None:
# self.api.env.verbose = True
# if options.environment:
# env_dict = {}
# for a in options.environment.split(','):
# a = a.split('=', 1)
# if len(a) < 2:
# parser.error('badly specified environment string,'\
# 'use var1=val1[,var2=val2]..')
# env_dict[a[0].strip()] = a[1].strip()
# self.api.env.update(env_dict, True)
# if options.config_file:
# self.api.env.update(read_config(options.config_file), True)
# else:
# self.api.env.update(read_config(), True)
# return args
def get_usage(self, cmd): def get_usage(self, cmd):
return ' '.join(self.get_usage_iter(cmd)) return ' '.join(self.get_usage_iter(cmd))

View File

@ -22,7 +22,7 @@ Test the `ipalib.cli` module.
""" """
from tests.util import raises, getitem, no_set, no_del, read_only, ClassChecker from tests.util import raises, getitem, no_set, no_del, read_only, ClassChecker
from ipalib import cli, plugable from ipalib import cli, plugable, frontend, backend
def test_to_cli(): def test_to_cli():
@ -81,60 +81,61 @@ class test_CLI(ClassChecker):
""" """
_cls = cli.CLI _cls = cli.CLI
def test_class(self): def new(self, argv):
""" api = plugable.API(
Test the `ipalib.cli.CLI` class. frontend.Command,
""" frontend.Object,
assert type(self.cls.api) is property frontend.Method,
frontend.Property,
def test_api(self): frontend.Application,
""" backend.Backend,
Test the `ipalib.cli.CLI.api` property.
"""
api = 'the plugable.API instance'
o = self.cls(api)
assert read_only(o, 'api') is api
def dont_parse(self):
"""
Test the `ipalib.cli.CLI.parse` method.
"""
o = self.cls(None)
args = ['hello', 'naughty', 'nurse']
kw = dict(
first_name='Naughty',
last_name='Nurse',
) )
opts = ['--%s=%s' % (k.replace('_', '-'), v) for (k, v) in kw.items()] o = self.cls(api, argv)
assert o.parse(args + []) == (args, {}) assert o.api is api
assert o.parse(opts + []) == ([], kw) return o
assert o.parse(args + opts) == (args, kw)
assert o.parse(opts + args) == (args, kw)
def test_mcl(self): def test_init(self):
""" """
Test the `ipalib.cli.CLI.mcl` property . Test the `ipalib.cli.CLI.__init__` method.
""" """
cnt = 100 argv = ['-v', 'user-add', '--first=Jonh', '--last=Doe']
api = DummyAPI(cnt) o = self.new(argv)
len(api.Command) == cnt assert type(o.api) is plugable.API
o = self.cls(api) assert o.argv == tuple(argv)
assert o.mcl is None
o.build_map()
assert o.mcl == 6 # len('cmd_99')
def test_dict(self): def test_parse_globals(self):
""" """
Test container emulation of `ipalib.cli.CLI` class. Test the `ipalib.cli.CLI.parse_globals` method.
""" """
cnt = 25 # Test with empty argv
api = DummyAPI(cnt) o = self.new([])
assert len(api.Command) == cnt assert not hasattr(o, 'options')
o = self.cls(api) assert not hasattr(o, 'cmd_argv')
o.build_map() assert o.isdone('parse_globals') is False
for cmd in api.Command(): o.parse_globals()
key = cli.to_cli(cmd.name) assert o.isdone('parse_globals') is True
assert key in o assert o.options.interactive is True
assert o[key] is cmd assert o.options.verbose is False
assert cmd.name not in o assert o.options.config_file is None
raises(KeyError, getitem, o, cmd.name) assert o.options.environment is None
assert o.cmd_argv == tuple()
e = raises(StandardError, o.parse_globals)
assert str(e) == 'CLI.parse_globals() already called'
# Test with a populated argv
argv = ('-a', '-n', '-v', '-c', '/my/config.conf', '-e', 'my_key=my_val')
cmd_argv = ('user-add', '--first', 'John', '--last', 'Doe')
o = self.new(argv + cmd_argv)
assert not hasattr(o, 'options')
assert not hasattr(o, 'cmd_argv')
assert o.isdone('parse_globals') is False
o.parse_globals()
assert o.isdone('parse_globals') is True
assert o.options.prompt_all is True
assert o.options.interactive is False
assert o.options.verbose is True
assert o.options.config_file == '/my/config.conf'
assert o.options.environment == 'my_key=my_val'
assert o.cmd_argv == cmd_argv
e = raises(StandardError, o.parse_globals)
assert str(e) == 'CLI.parse_globals() already called'