From 5c95fd5da840a4be6a03922995982d6750b6951c Mon Sep 17 00:00:00 2001 From: Michele Simionato Date: Fri, 31 Dec 2010 14:56:17 +0100 Subject: Fixed a bug with the help in subcommands (signaled by Paul Jacobson) --- plac/doc/example13.help | 9 +++++---- plac/doc/example13.py | 1 + plac/doc/test_plac.py | 5 +++++ plac/plac.py | 2 +- plac/plac_core.py | 47 +++++++++++++++++++++++++++++------------------ plac/plac_runner.py | 4 ++-- 6 files changed, 43 insertions(+), 25 deletions(-) diff --git a/plac/doc/example13.help b/plac/doc/example13.help index 94401ad..08e6f68 100644 --- a/plac/doc/example13.help +++ b/plac/doc/example13.help @@ -1,9 +1,10 @@ -usage: example13.py [-h] {status,commit,checkout,help} ... +usage: example13.py {status,commit,checkout,help} ... A Fake Version Control System -optional arguments: - -h, --help show this help message and exit - subcommands: {status,commit,checkout,help} + checkout + commit + status + help diff --git a/plac/doc/example13.py b/plac/doc/example13.py index 715f2e1..412a144 100644 --- a/plac/doc/example13.py +++ b/plac/doc/example13.py @@ -3,6 +3,7 @@ import plac class FVCS(object): "A Fake Version Control System" commands = 'checkout', 'commit', 'status', 'help' + add_help = False @plac.annotations( name=('a recognized command', 'positional', None, str, commands)) diff --git a/plac/doc/test_plac.py b/plac/doc/test_plac.py index df6c060..dda456b 100644 --- a/plac/doc/test_plac.py +++ b/plac/doc/test_plac.py @@ -179,6 +179,11 @@ def test_cmd_abbrevs(): assert ['help', 'foo'] == plac.call(cmds, ['h', 'foo']) expect(SystemExit, plac.call, cmds, ['foo']) +def test_sub_help(): + c = Cmds() + c.add_help = True + expect(SystemExit, plac.call, c, ['commit', '-h']) + def test_yield(): def main(): for i in (1, 2, 3): diff --git a/plac/plac.py b/plac/plac.py index af01d87..cc7b41d 100644 --- a/plac/plac.py +++ b/plac/plac.py @@ -1,6 +1,6 @@ ########################## LICENCE ############################### ## -## Copyright (c) 2010, Michele Simionato +## Copyright (c) 2010-2011, Michele Simionato ## All rights reserved. ## ## Redistributions of source code must retain the above copyright diff --git a/plac/plac_core.py b/plac/plac_core.py index fbd63b8..ec4a562 100644 --- a/plac/plac_core.py +++ b/plac/plac_core.py @@ -15,6 +15,30 @@ except NameError: # Python 2.3 from sets import Set as set from gettext import gettext as _ + +def getargspec(callableobj): + """Given a callable return an object with attributes .args, .varargs, + .varkw, .defaults. It tries to do the "right thing" with functions, + methods, classes and generic callables.""" + if inspect.isfunction(callableobj): + argspec = getfullargspec(callableobj) + elif inspect.ismethod(callableobj): + argspec = getfullargspec(callableobj) + del argspec.args[0] # remove first argument + elif inspect.isclass(callableobj): + if callableobj.__init__ is object.__init__: # to avoid an error + argspec = getfullargspec(lambda self: None) + else: + argspec = getfullargspec(callableobj.__init__) + del argspec.args[0] # remove first argument + elif hasattr(callableobj, '__call__'): + argspec = getfullargspec(callableobj.__call__) + del argspec.args[0] # remove first argument + else: + raise TypeError(_('Could not determine the signature of ') + + str(callableobj)) + return argspec + def annotations(**ann): """ Returns a decorator annotating a function with the given annotations. @@ -169,7 +193,7 @@ class ArgumentParser(argparse.ArgumentParser): def _extract_subparser_cmd(self, arglist): "Extract the right subparser from the first recognized argument" - optprefix = self.prefix_chars[0] + optprefix = self.prefix_chars[0] name_parser_map = self.subparsers._name_parser_map for i, arg in enumerate(arglist): if not arg.startswith(optprefix): @@ -187,31 +211,18 @@ class ArgumentParser(argparse.ArgumentParser): elif title: self.add_argument_group(title=title) # populate ._action_groups prefixlen = len(getattr(obj, 'cmdprefix', '')) + add_help = getattr(obj, 'add_help', True) for cmd in commands: func = getattr(obj, cmd[prefixlen:]) # strip the prefix self.subparsers.add_parser( - cmd, add_help=False, **pconf(func)).populate_from(func) + cmd, add_help=add_help, help=func.__doc__, **pconf(func) + ).populate_from(func) def _set_func_argspec(self, obj): """Extracts the signature from a callable object and adds an .argspec attribute to the parser. Also adds a .func reference to the object.""" - if inspect.isfunction(obj): - self.argspec = getfullargspec(obj) - elif inspect.ismethod(obj): - self.argspec = getfullargspec(obj) - del self.argspec.args[0] # remove first argument - elif inspect.isclass(obj): - if obj.__init__ is object.__init__: # to avoid an error - self.argspec = getfullargspec(lambda self: None) - else: - self.argspec = getfullargspec(obj.__init__) - del self.argspec.args[0] # remove first argument - elif hasattr(obj, '__call__'): - self.argspec = getfullargspec(obj.__call__) - del self.argspec.args[0] # remove first argument - else: - raise TypeError(_('Could not determine the signature of %r') % obj) self.func = obj + self.argspec = getargspec(obj) parser_registry[obj] = self def populate_from(self, func): diff --git a/plac/plac_runner.py b/plac/plac_runner.py index 6502efc..2fdfc6d 100644 --- a/plac/plac_runner.py +++ b/plac/plac_runner.py @@ -1,6 +1,6 @@ #!python from __future__ import with_statement -import os, sys, shlex, inspect +import os, sys, shlex import plac def run(fnames, cmd, verbose): @@ -62,4 +62,4 @@ def main(verbose, interactive, multiline, serve, batch, test, fname=None, main.add_help = False if __name__ == '__main__': - plac.call(main) \ No newline at end of file + plac.call(main) -- cgit v1.2.1