diff options
author | Anthon van der Neut <anthon@mnt.org> | 2014-03-28 08:33:06 +0100 |
---|---|---|
committer | Anthon van der Neut <anthon@mnt.org> | 2014-03-28 08:33:06 +0100 |
commit | 9918adcba6cda48e9d51b04196ff632bdd5c74ac (patch) | |
tree | a342c062d0e1aa79df4b6d2ef65bab004bc4792b | |
parent | b4a67a39ef0221ab4d0c7b9011b08fb05f173c45 (diff) | |
download | ruamel.std.argparse-9918adcba6cda48e9d51b04196ff632bdd5c74ac.tar.gz |
should not decorate __init__ if a class is going to be subclassed
special _pb_init function in the _pb_ namespace
-rw-r--r-- | __init__.py | 155 | ||||
-rw-r--r-- | test/test_program.py | 11 |
2 files changed, 23 insertions, 143 deletions
diff --git a/__init__.py b/__init__.py index fe57271..af658b3 100644 --- a/__init__.py +++ b/__init__.py @@ -103,130 +103,6 @@ class SmartFormatter(argparse.HelpFormatter): return help -# decorators - -# decorate method as a subparser, ToDo: signature -def sub_parser1(*args, **kw): - class Decorator(object): - def __init__(self): - self.target = None - - def __call__(self, target): - self.target = target - target.sub_parser = {'args': args, 'kw': kw} - target.option = self.option - return target - - def option(self, *a, **k): - """ after a method xyz is decorated as sub_parser, you can add - options with: - @xyz.option('--force') - def force(self): - pass - - if option argument is a short option ('-F'), add the long - option based on the function name - if no option argument, add function_name if 'nargs' in k - else add long option based on function name - """ - # here check if a is option name else take from function - def option_func(*args): - """called with the original function that is decorated - add function name to last options element - """ - self.target.options[-1]['fun'] = args[0].__name__ - pass - - if not hasattr(self.target, "options"): - self.target.options = [] - self.target.options.append({'args': a, 'kw': k}) - return option_func - decorator = Decorator() - return decorator - - -# global options can come before and after a sub_parser, ToDo: signature -def global_option1(*args, **kw): - def decorator(target): - target.global_option = {'args': args, 'kw': kw} - return target - return decorator - - -# global only options can come before a sub_parser only, ToDo: signature -def global_only_option1(*args, **kw): - def decorator(target): - target.global_only_option = {'args': args, 'kw': kw} - return target - return decorator - - -def create_argument_parser1(self, *args, **keywords): - argument_parser = argparse.ArgumentParser(**keywords) - self._subparsers = None - for x in dir(self): - if x.startswith('_'): - continue - method = getattr(self, x) - if hasattr(method, "sub_parser"): - if self._subparsers is None: - self._subparsers = argument_parser.add_subparsers( - dest="subparser_level_0", help='sub-command help') - # (name, aliases=aliases, help=help) - arg = method.sub_parser['args'] - if not arg or not isinstance(arg[0], basestring): - arg = list(arg) - arg.insert(0, x) - sp = self._subparsers.add_parser(*arg, - **method.sub_parser['kw']) - sp.set_defaults(func=method) - - # print x, method.sub_parser - if hasattr(method, "_options"): - for o in method._options: - # print 'arg1', o - arg = list(o['args']) - fun_name = o.get('fun') - if arg: - # short option name only, add long option name - # based on function name - if len(arg[0]) == 2 and arg[0][0] == '-': - if (fun_name): - arg.insert(0, '--' + fun_name) - else: - # no option name - if o['kw'].get('nargs') == '+': - # file names etc, no leading dashes - arg.insert(0, fun_name) - else: - # add long option based on function name - arg.insert(0, '--' + fun_name) - # print 'arg2', arg - sp.add_argument(*arg, **o['kw']) - # print ' opt:', x, method.options - if hasattr(method, "global_only_option"): - arg = method.global_only_option['args'] - kw = method.global_only_option['kw'] - if not arg or not arg[0].startswith('--'): - arg = list(arg) - arg.insert(0, '--' + x) - try: - argument_parser.add_argument(*arg, **kw) - except TypeError: - print('args, kw', arg, kw) - for x in dir(self): - if x.startswith('_'): - continue - method = getattr(self, x) - if hasattr(method, "global_option"): - for name in self._subparsers._name_parser_map: - sp = self._subparsers._name_parser_map[name] - arg = method.global_option['args'] - if not arg or not arg[0].startswith('--'): - arg = list(arg) - arg.insert(0, '--' + x) - sp.add_argument(*arg, **method.global_option['kw']) - return argument_parser class ProgramBase(object): @@ -264,7 +140,7 @@ class ProgramBase(object): if parent is None: method._sub_parser['level'] = 0 # parent sub parser - elif not 'level' in parent._sub_parser: + elif 'level' not in parent._sub_parser: print 'skipping', parent.__name__, method.__name__ continue else: # have a parent @@ -283,20 +159,17 @@ class ProgramBase(object): parent._sub_parser['sp'] = ssp sub_parsers = ssp arg = method._sub_parser['args'] - print 'arg', arg if not arg or not isinstance(arg[0], basestring): arg = list(arg) arg.insert(0, method.__name__) - print 'arg', arg sp = sub_parsers.add_parser(*arg, - **method._sub_parser['kw']) + **method._sub_parser['kw']) # add parser primarily for being able to add subparsers method._sub_parser['parser'] = sp sp.set_defaults(func=method) # print x, method._sub_parser for o in method._sub_parser['options']: - # print 'arg1', o arg = list(o['args']) fun_name = o.get('fun') if arg: @@ -307,19 +180,17 @@ class ProgramBase(object): arg.insert(0, '--' + fun_name) else: # no option name - if o['kw'].get('nargs') == '+': + if o['kw'].get('nargs') == '+ ': # file names etc, no leading dashes arg.insert(0, fun_name) else: # add long option based on function name arg.insert(0, '--' + fun_name) - # print 'arg2', arg sp.add_argument(*arg, **o['kw']) - # print ' opt:', x, method._options - print 'removing', method.__name__ + #print 'removing', method.__name__ methods_with_sub_parsers.remove(method) for x in dir(self): - if x.startswith('_') and not x == '__init__': + if x.startswith('_') and not x in ['__init__', '_pb_init']: continue method = getattr(self, x) if hasattr(method, "_options"): # not transfered to sub_parser @@ -341,7 +212,7 @@ class ProgramBase(object): return self._args @staticmethod - def option(*args, **kw): + def _pb_option(*args, **kw): def decorator(target): if not hasattr(target, '_options'): target._options = [] @@ -351,7 +222,7 @@ class ProgramBase(object): return decorator @staticmethod - def sub_parser(*args, **kw): + def _pb_sub_parser(*args, **kw): class Decorator(object): def __init__(self): self.target = None @@ -369,7 +240,6 @@ class ProgramBase(object): o = getattr(target, '_options', []) if o: del target._options - print '__call', a target._sub_parser = {'args': a, 'kw': k, 'options': o} # assign the name target.sub_parser = self.sub_parser @@ -390,16 +260,19 @@ class ProgramBase(object): return decorator decorator = Decorator() - #dbg('----', kw.get('_parent')) return decorator +# decorators + def option(*args, **kw): - return ProgramBase.option(*args, **kw) + return ProgramBase._pb_option(*args, **kw) + def sub_parser(*args, **kw): - return ProgramBase.sub_parser(*args, **kw) + return ProgramBase._pb_sub_parser(*args, **kw) + def version(version_string): - return ProgramBase.option( + return ProgramBase._pb_option( '--version', action='version', version=version_string)
\ No newline at end of file diff --git a/test/test_program.py b/test/test_program.py index c29599e..d5fa015 100644 --- a/test/test_program.py +++ b/test/test_program.py @@ -4,12 +4,19 @@ import pytest from ruamel.std.argparse import ProgramBase, option, sub_parser, version class Program(ProgramBase): + def __init__(self): + ProgramBase.__init__(self) + + # you can put these options on __init__, but if Program is going + # to be subclassed, there will be another __init__ scanned + # in ProgramBase.__init__ than the one decorated here + # defensive is to use a differently named option or the special _pb_init @option('--verbose', global_option=True, action='store_true') @option('--quiet', action='store_true') #@option('--version', action='version', version='version: 42') @version('version: 42') - def __init__(self): - ProgramBase.__init__(self) + def _pb_init(self): + pass @sub_parser(help="call mercurial") @option('--show', action='store_true') |