ATLAS Offline Software
Loading...
Searching...
No Matches
acmdlib.py
Go to the documentation of this file.
1# Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2
3# @file PyUtils.acmdlib
4# @purpose a library to ease the writing of sub-command scripts
5# @author Sebastien Binet
6# @date January 2010
7
8__doc__ = "a library to ease the writing of sub-command scripts"
9__author__ = "Sebastien Binet"
10
11__all__ = [
12 'Command',
13 'command',
14 'argument',
15 'register',
16 ]
17
18
19import argparse
20import textwrap
21import importlib
22
23
24ACMD_GROUPNAME = 'acmdlib.commands'
25"""The name under which all commands are grouped
26"""
27
28ACMD_PARSER = argparse.ArgumentParser(
29 prog="acmd",
30 description="a general script interface with sub-commands",
31 )
32
33ACMD_SUBPARSERS = ACMD_PARSER.add_subparsers(
34 dest='command',
35 title='commands',
36 metavar='COMMAND',
37 )
38
39
41 """A wrapper class to manage the creation of commands and their arguments
42
43 this is very heavily inspired from:
44 http://pypi.python.org/pypi/django-boss (MIT licence)
45 """
46
47 def __init__(self, fct, **kwargs):
48 object.__init__(self)
49 self.fct = fct
50 self.parser = self._make_parser(**kwargs)
51 self._init_arguments()
52 plugin_name = kwargs.get('name') or self.name
53 register(plugin_name, self.fct.__module__)
54
55 @property
56 def name(self):
57 return self.fct.__name__.replace('_','-')
58
59 @property
60 def help(self):
61 if getattr(self.fct, '__doc__', None):
62 # just the first line of the doc string
63 return self.fct.__doc__.splitlines()[0]
64
65 @property
66 def description(self):
67 if getattr(self.fct, '__doc__', None):
68 return textwrap.dedent(self.fct.__doc__)
69
70 @property
71 def add_argument(self):
72 return self.parser.add_argument
73
74 def __call__(self, *args, **kwargs):
75 return self.fct(*args, **kwargs)
76
77 def _make_parser(self, **kwargs):
78 """Create and register a subparser for this command."""
79
80 kwargs.setdefault('help', self.help)
81 kwargs.setdefault('formatter_class',argparse.RawDescriptionHelpFormatter)
82 kwargs.setdefault('description', self.description)
83 kwargs.setdefault('name', self.name)
84 names = (kwargs.get('name') or self.name).split('.')
85
86 def _get_subparser(a):
87 if a._subparsers:
88 for action in a._subparsers._actions:
89 if isinstance(action, argparse._SubParsersAction):
90 return action
91 raise RuntimeError('could not find adequate subparser')
92 return a.add_subparsers(dest='command',
93 title='commands',
94 metavar='COMMAND')
95 def _get_parser(node, idx, names):
96 name = names[idx]
97 if name in node.choices:
98 return node.choices[name]
99 args = {
100 'name' : name,
101 'help' : 'a group of sub-commands',
102 }
103 return node.add_parser(**args)
104
105 parser = ACMD_PARSER
106 node = _get_subparser(parser)
107
108 for i,n in enumerate(names[:-1]):
109 node = _get_subparser(parser)
110 parser = _get_parser(node, i, names)
111
112 node = _get_subparser(parser)
113 kwargs['name'] = names[-1]
114 parser = node.add_parser(**kwargs)
115 return parser
116
117 def add_mutually_exclusive_group(self, **kwargs):
118 return self.parser.add_mutually_exclusive_group(**kwargs)
119
121 if hasattr(self.fct, '_acmdlib_arguments'):
122 while self.fct._acmdlib_arguments:
123 args, kwargs = self.fct._acmdlib_arguments.pop()
124 self.add_argument(*args, **kwargs)
125
126 if hasattr(self.fct,'_acmdlib_arguments_mutual'):
127 if not hasattr(self, '_acmdlib_mutual_group'):
129 while self.fct._acmdlib_arguments_mutual:
130 args, kwargs = self.fct._acmdlib_arguments_mutual.pop()
131 self._acmdlib_mutual_group.add_argument(*args, **kwargs)
132
133 pass # Command
134
136 """A simple plugin registration.
137 """
138 _plugins = {}
139
140 @classmethod
141 def register(cls, name, value):
142 """Register plugin
143 """
144 cls._plugins[name] = value
145
146 @classmethod
147 def exists(cls, name):
148 """Check if plugin exists
149 """
150 return name in cls._plugins
151
152 @classmethod
153 def load(cls, name):
154 """Load given plugin and return it
155 """
156 try:
157 return importlib.import_module(cls._plugins[name])
158 except Exception as err:
159 print("** could not load command [%s]:\n%s" % (name, err))
160
161 @classmethod
162 def loadAll(cls):
163 """Load all plugins
164 """
165 for k in cls._plugins.keys():
166 cls.load(k)
167
168
169
170def command(*args, **kwargs):
171 """Decorator to declare that a function is a command.
172 """
173 def deco(fct):
174 return Command(fct, **kwargs)
175 if args:
176 return deco(*args)
177 return deco
178
179def argument(*args, **kwargs):
180 """Decorator to add an argument to a command.
181 Use the `mutual=True` keyword to specify that the argument should belong to a mutual exclusion group.
182 """
183 is_mutual = kwargs.pop('mutual', False)
184
185 def deco(fct):
186 if isinstance(fct, Command):
187 cmd = fct
188 if is_mutual:
189 if not hasattr(cmd, '_acmdlib_mutual_group'):
190 cmd._acmdlib_mutual_group = cmd.add_mutually_exclusive_group()
191 cmd._acmdlib_mutual_group.add_argument(*args, **kwargs)
192 else:
193 cmd.add_argument(*args, **kwargs)
194 else:
195 store_as = '_acmdlib_arguments_mutual' if is_mutual else '_acmdlib_arguments'
196 if not hasattr(fct, store_as):
197 setattr(fct, store_as, [])
198 getattr(fct, store_as).append((args, kwargs))
199 #print "===",args,kwargs,type(fct),fct
200 return fct
201 return deco
202
203def register(name, value):
204 """Registers a plugin, given a name and value.
205
206 ex: register('check-file', 'PyUtils.CheckFileLib:fct')
207 """
208
209 return Plugins.register(name, value)
void print(char *figname, TCanvas *c1)
classes ----------------------------------------------------------------—
Definition acmdlib.py:40
add_mutually_exclusive_group(self, **kwargs)
Definition acmdlib.py:117
__call__(self, *args, **kwargs)
Definition acmdlib.py:74
_make_parser(self, **kwargs)
Definition acmdlib.py:77
__init__(self, fct, **kwargs)
Definition acmdlib.py:47
#define register
Definition dictionary.h:21
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:177
argument(*args, **kwargs)
Definition acmdlib.py:179
command(*args, **kwargs)
Definition acmdlib.py:170