diff options
Diffstat (limited to 'logilab/common/clcommands.py')
-rw-r--r-- | logilab/common/clcommands.py | 126 |
1 files changed, 77 insertions, 49 deletions
diff --git a/logilab/common/clcommands.py b/logilab/common/clcommands.py index 4778b99..f89a4b4 100644 --- a/logilab/common/clcommands.py +++ b/logilab/common/clcommands.py @@ -42,6 +42,7 @@ class BadCommandUsage(Exception): Trigger display of command usage. """ + class CommandError(Exception): """Raised when a command can't be processed and we want to display it and exit, without traceback nor usage displayed. @@ -50,6 +51,7 @@ class CommandError(Exception): # command line access point #################################################### + class CommandLine(dict): """Usage: @@ -77,9 +79,17 @@ class CommandLine(dict): * `logger`, logger to propagate to commands, default to `logging.getLogger(self.pgm))` """ - def __init__(self, pgm=None, doc=None, copyright=None, version=None, - rcfile=None, logthreshold=logging.ERROR, - check_duplicated_command=True): + + def __init__( + self, + pgm=None, + doc=None, + copyright=None, + version=None, + rcfile=None, + logthreshold=logging.ERROR, + check_duplicated_command=True, + ): if pgm is None: pgm = basename(sys.argv[0]) self.pgm = pgm @@ -93,8 +103,9 @@ class CommandLine(dict): def register(self, cls, force=False): """register the given :class:`Command` subclass""" - assert not self.check_duplicated_command or force or not cls.name in self, \ - 'a command %s is already defined' % cls.name + assert not self.check_duplicated_command or force or not cls.name in self, ( + "a command %s is already defined" % cls.name + ) self[cls.name] = cls return cls @@ -107,20 +118,22 @@ class CommandLine(dict): Terminate by :exc:`SystemExit` """ - init_log(debug=True, # so that we use StreamHandler - logthreshold=self.logthreshold, - logformat='%(levelname)s: %(message)s') + init_log( + debug=True, # so that we use StreamHandler + logthreshold=self.logthreshold, + logformat="%(levelname)s: %(message)s", + ) try: arg = args.pop(0) except IndexError: self.usage_and_exit(1) - if arg in ('-h', '--help'): + if arg in ("-h", "--help"): self.usage_and_exit(0) - if self.version is not None and arg in ('--version'): + if self.version is not None and arg in ("--version"): print(self.version) sys.exit(0) rcfile = self.rcfile - if rcfile is not None and arg in ('-C', '--rc-file'): + if rcfile is not None and arg in ("-C", "--rc-file"): try: rcfile = args.pop(0) arg = args.pop(0) @@ -129,19 +142,19 @@ class CommandLine(dict): try: command = self.get_command(arg) except KeyError: - print('ERROR: no %s command' % arg) + print("ERROR: no %s command" % arg) print() self.usage_and_exit(1) try: sys.exit(command.main_run(args, rcfile)) except KeyboardInterrupt as exc: - print('Interrupted', end=' ') + print("Interrupted", end=" ") if str(exc): - print(': %s' % exc, end=' ') + print(": %s" % exc, end=" ") print() sys.exit(4) except BadCommandUsage as err: - print('ERROR:', err) + print("ERROR:", err) print() print(command.help()) sys.exit(1) @@ -166,32 +179,44 @@ class CommandLine(dict): """display usage for the main program (i.e. when no command supplied) and exit """ - print('usage:', self.pgm, end=' ') + print("usage:", self.pgm, end=" ") if self.rcfile: - print('[--rc-file=<configuration file>]', end=' ') - print('<command> [options] <command argument>...') + print("[--rc-file=<configuration file>]", end=" ") + print("<command> [options] <command argument>...") if self.doc: - print('\n%s' % self.doc) - print(''' + print("\n%s" % self.doc) + print( + """ Type "%(pgm)s <command> --help" for more information about a specific -command. Available commands are :\n''' % self.__dict__) +command. Available commands are :\n""" + % self.__dict__ + ) max_len = max([len(cmd) for cmd in self]) - padding = ' ' * max_len + padding = " " * max_len for cmdname, cmd in sorted(self.items()): if not cmd.hidden: - print(' ', (cmdname + padding)[:max_len], cmd.short_description()) + print(" ", (cmdname + padding)[:max_len], cmd.short_description()) if self.rcfile: - print(''' + print( + """ Use --rc-file=<configuration file> / -C <configuration file> before the command to specify a configuration file. Default to %s. -''' % self.rcfile) - print('''%(pgm)s -h/--help - display this usage information and exit''' % self.__dict__) +""" + % self.rcfile + ) + print( + """%(pgm)s -h/--help + display this usage information and exit""" + % self.__dict__ + ) if self.version: - print('''%(pgm)s -v/--version - display version configuration and exit''' % self.__dict__) + print( + """%(pgm)s -v/--version + display version configuration and exit""" + % self.__dict__ + ) if self.copyright: - print('\n', self.copyright) + print("\n", self.copyright) def usage_and_exit(self, status): self.usage() @@ -200,6 +225,7 @@ to specify a configuration file. Default to %s. # base command classes ######################################################### + class Command(Configuration): """Base class for command line commands. @@ -219,8 +245,8 @@ class Command(Configuration): * `options`, options list, as allowed by :mod:configuration """ - arguments = '' - name = '' + arguments = "" + name = "" # hidden from help ? hidden = False # max/min args, None meaning unspecified @@ -229,24 +255,23 @@ class Command(Configuration): @classmethod def description(cls): - return cls.__doc__.replace(' ', '') + return cls.__doc__.replace(" ", "") @classmethod def short_description(cls): - return cls.description().split('.')[0] + return cls.description().split(".")[0] def __init__(self, logger): - usage = '%%prog %s %s\n\n%s' % (self.name, self.arguments, - self.description()) + usage = "%%prog %s %s\n\n%s" % (self.name, self.arguments, self.description()) Configuration.__init__(self, usage=usage) self.logger = logger def check_args(self, args): """check command's arguments are provided""" if self.min_args is not None and len(args) < self.min_args: - raise BadCommandUsage('missing argument') + raise BadCommandUsage("missing argument") if self.max_args is not None and len(args) > self.max_args: - raise BadCommandUsage('too many arguments') + raise BadCommandUsage("too many arguments") def main_run(self, args, rcfile=None): """Run the command and return status 0 if everything went fine. @@ -275,8 +300,9 @@ class Command(Configuration): class ListCommandsCommand(Command): """list available commands, useful for bash completion.""" - name = 'listcommands' - arguments = '[command]' + + name = "listcommands" + arguments = "[command]" hidden = True def run(self, args): @@ -285,8 +311,8 @@ class ListCommandsCommand(Command): command = args.pop() cmd = _COMMANDS[command] for optname, optdict in cmd.options: - print('--help') - print('--' + optname) + print("--help") + print("--" + optname) else: commands = sorted(_COMMANDS.keys()) for command in commands: @@ -299,17 +325,19 @@ class ListCommandsCommand(Command): _COMMANDS = CommandLine() -DEFAULT_COPYRIGHT = '''\ +DEFAULT_COPYRIGHT = """\ Copyright (c) 2004-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -http://www.logilab.fr/ -- mailto:contact@logilab.fr''' +http://www.logilab.fr/ -- mailto:contact@logilab.fr""" + -@deprecated('use cls.register(cli)') +@deprecated("use cls.register(cli)") def register_commands(commands): """register existing commands""" for command_klass in commands: _COMMANDS.register(command_klass) -@deprecated('use args.pop(0)') + +@deprecated("use args.pop(0)") def main_run(args, doc=None, copyright=None, version=None): """command line tool: run command specified by argument list (without the program name). Raise SystemExit with status 0 if everything went fine. @@ -321,7 +349,8 @@ def main_run(args, doc=None, copyright=None, version=None): _COMMANDS.version = version _COMMANDS.run(args) -@deprecated('use args.pop(0)') + +@deprecated("use args.pop(0)") def pop_arg(args_list, expected_size_after=None, msg="Missing argument"): """helper function to get and check command line arguments""" try: @@ -329,6 +358,5 @@ def pop_arg(args_list, expected_size_after=None, msg="Missing argument"): except IndexError: raise BadCommandUsage(msg) if expected_size_after is not None and len(args_list) > expected_size_after: - raise BadCommandUsage('too many arguments') + raise BadCommandUsage("too many arguments") return value - |