8 from __future__
import with_statement
10 __doc__ =
"a library to ease the writing of sub-command scripts"
11 __author__ =
"Sebastien Binet"
26 ACMD_GROUPNAME =
'acmdlib.commands'
27 """The name under which all commands are grouped
30 ACMD_PARSER = argparse.ArgumentParser(
32 description=
"a general script interface with sub-commands",
35 ACMD_SUBPARSERS = ACMD_PARSER.add_subparsers(
43 """A wrapper class to manage the creation of commands and their arguments
45 this is very heavily inspired from:
46 http://pypi.python.org/pypi/django-boss (MIT licence)
54 plugin_name = kwargs.get(
'name')
or self.
name
59 return self.
fct.__name__.replace(
'_',
'-')
63 if getattr(self.
fct,
'__doc__',
None):
65 return self.
fct.__doc__.splitlines()[0]
69 if getattr(self.
fct,
'__doc__',
None):
70 return textwrap.dedent(self.
fct.__doc__)
74 return self.
parser.add_argument
77 return self.
fct(*args, **kwargs)
80 """Create and register a subparser for this command."""
82 kwargs.setdefault(
'help', self.
help)
83 kwargs.setdefault(
'formatter_class',argparse.RawDescriptionHelpFormatter)
85 kwargs.setdefault(
'name', self.
name)
86 names = (kwargs.get(
'name')
or self.
name).
split(
'.')
88 def _get_subparser(a):
90 for action
in a._subparsers._actions:
91 if isinstance(action, argparse._SubParsersAction):
93 raise RuntimeError(
'could not find adequate subparser')
94 return a.add_subparsers(dest=
'command',
97 def _get_parser(node, idx, names):
99 if name
in node.choices:
100 return node.choices[name]
103 'help' :
'a group of sub-commands',
105 return node.add_parser(**args)
108 node = _get_subparser(parser)
110 for i,n
in enumerate(names[:-1]):
111 node = _get_subparser(parser)
112 parser = _get_parser(node, i, names)
114 node = _get_subparser(parser)
115 kwargs[
'name'] = names[-1]
116 parser = node.add_parser(**kwargs)
123 if hasattr(self.
fct,
'_acmdlib_arguments'):
124 while self.
fct._acmdlib_arguments:
125 args, kwargs = self.
fct._acmdlib_arguments.pop()
128 if hasattr(self.
fct,
'_acmdlib_arguments_mutual'):
129 if not hasattr(self,
'_acmdlib_mutual_group'):
131 while self.
fct._acmdlib_arguments_mutual:
132 args, kwargs = self.
fct._acmdlib_arguments_mutual.pop()
138 """A simple plugin registration.
150 """Check if plugin exists
156 """Load given plugin and return it
159 return importlib.import_module(cls.
_plugins[name])
160 except Exception
as err:
161 print(
"** could not load command [%s]:\n%s" % (name, err))
173 """Decorator to declare that a function is a command.
182 """Decorator to add an argument to a command.
183 Use the `mutual=True` keyword to specify that the argument should belong to a mutual exclusion group.
185 is_mutual = kwargs.pop(
'mutual',
False)
188 if isinstance(fct, Command):
191 if not hasattr(cmd,
'_acmdlib_mutual_group'):
192 cmd._acmdlib_mutual_group = cmd.add_mutually_exclusive_group()
193 cmd._acmdlib_mutual_group.add_argument(*args, **kwargs)
195 cmd.add_argument(*args, **kwargs)
197 store_as =
'_acmdlib_arguments_mutual' if is_mutual
else '_acmdlib_arguments'
198 if not hasattr(fct, store_as):
199 setattr(fct, store_as, [])
200 getattr(fct, store_as).
append((args, kwargs))
206 """Registers a plugin, given a name and value.
208 ex: register('check-file', 'PyUtils.CheckFileLib:fct')
211 return Plugins.register(name, value)