# HG changeset patch # User Alexander Solovyov <piranha@piranha.org.ua> # Date 1249407002 -10800 # Node ID 74b690e796068c6e3be622f020caea985988f214 # Parent bf6cd5a1fc9e124e3ac1a9ebed90b3ab658a57cd ability to decorate all subcommands and example of such decorator diff -r bf6cd5a1fc9e -r 74b690e79606 finaloption.py --- a/finaloption.py Tue Aug 04 17:04:08 2009 +0300 +++ b/finaloption.py Tue Aug 04 20:30:02 2009 +0300 @@ -84,14 +84,16 @@ return wrapper -def dispatch(args=None, cmdtable=None, globalopts=None): +def dispatch(args=None, cmdtable=None, globaloptions=None, + middleware=lambda x: x): '''Dispatch command arguments based on subcommands. - ``args``: list of arguments, default: ``sys.argv[1:]`` - ``cmdtable``: dict of commands in format described below. If not supplied, will use functions decorated with ``@command``. - - ``globalopts``: list of options which are applied to all - commands, if not supplied will contain ``--help`` option + - ``globaloptions``: list of options which are applied to all + commands, will contain ``--help`` option at least. + - ``middleware``: global decorator for all commands. cmdtable format description:: @@ -108,18 +110,18 @@ args = args or sys.argv[1:] cmdtable = cmdtable or CMDTABLE - globalopts = globalopts or [] - globalopts.append(('h', 'help', False, 'display help')) + globaloptions = globaloptions or [] + globaloptions.append(('h', 'help', False, 'display help')) - cmdtable['help'] = (help_(cmdtable, globalopts), [], '[TOPIC]') + cmdtable['help'] = (help_(cmdtable, globaloptions), [], '[TOPIC]') help_func = cmdtable['help'][0] try: name, func, args, kwargs = catcher( - lambda: _dispatch(args, cmdtable, globalopts), + lambda: _dispatch(args, cmdtable, globaloptions), help_func) return catcher( - lambda: call_cmd(name, func, *args, **kwargs), + lambda: call_cmd(name, middleware(func), *args, **kwargs), help_func) except Abort: pass @@ -130,7 +132,7 @@ # -------- def help_(cmdtable, globalopts): - def inner(name=None): + def help_inner(name=None): '''Show help for a given help topic or a help overview With no arguments, print a list of commands with short help messages. @@ -175,7 +177,7 @@ return help_cmd(cmd, replace_name(usage, sysname() + ' ' + aliases[0]), options + globalopts) - return inner + return help_inner def help_cmd(func, usage, options): '''show help for given command diff -r bf6cd5a1fc9e -r 74b690e79606 test.py --- a/test.py Tue Aug 04 17:04:08 2009 +0300 +++ b/test.py Tue Aug 04 20:30:02 2009 +0300 @@ -6,18 +6,20 @@ @command(usage='[-t]', shortlist=True) -def simple(test=('t', False, 'just test execution')): +def simple(ui, + test=('t', False, 'just test execution')): '''Just simple command to do nothing. I assure you! Nothing to look here. ;-) ''' - print locals() + ui.write(str(locals())) + ui.write('\n') cplx_opts = [('p', 'pass', False, 'don\'t run the command'), ('', 'exit', 0, 'exit with supplied code (default: 0)')] @command(cplx_opts, usage='[-p] [--exit value] ...', name='complex', hide=True) -def complex_(*args, **opts): +def complex_(ui, *args, **opts): '''That's more complex command indented to do something Let's try to do that (what?!) @@ -25,8 +27,59 @@ if opts.get('pass'): return # test ui + ui.write('preved\n') if opts.get('exit'): sys.exit(opts['exit']) +def ui_middleware(func): + if func.__name__ == 'help_inner': + return func + def extract_dict(source, *keys): + dest = {} + for k in keys: + dest[k] = source.pop(k, None) + return dest + + def inner(*args, **kwargs): + ui = UI(**extract_dict(kwargs, 'verbose', 'quiet')) + return func(ui, *args, **kwargs) + return inner + +class UI(object): + '''User interface helper. + + Intended to ease handling of quiet/verbose output and more. + + You have three methods to handle program messages output: + + - ``UI.info`` is printed by default, but hidden with quiet option + - ``UI.note`` is printed only if output is verbose + - ``UI.write`` is printed in any case + + Additionally there is ``UI.warn`` method, which prints to stderr. + ''' + + options = [('v', 'verbose', False, 'enable additional output'), + ('q', 'quiet', False, 'suppress output')] + + def __init__(self, verbose=False, quiet=False): + self.verbose = verbose + # disabling quiet in favor of verbose is more safe + self.quiet = (not verbose and quiet) + + def write(self, *messages): + for m in messages: + sys.stdout.write(m) + + def warn(self, *messages): + for m in messages: + sys.stderr.write(m) + + info = lambda self, *m: not self.quiet and self.write(*m) + note = lambda self, *m: self.verbose and self.write(*m) + + if __name__ == '__main__': - dispatch() + dispatch(globaloptions=UI.options, middleware=ui_middleware) + +