summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthon van der Neut <anthon@mnt.org>2014-03-28 08:33:06 +0100
committerAnthon van der Neut <anthon@mnt.org>2014-03-28 08:33:06 +0100
commit9918adcba6cda48e9d51b04196ff632bdd5c74ac (patch)
treea342c062d0e1aa79df4b6d2ef65bab004bc4792b
parentb4a67a39ef0221ab4d0c7b9011b08fb05f173c45 (diff)
downloadruamel.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__.py155
-rw-r--r--test/test_program.py11
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')