3 # Copyright (C) 2010-2013 CEA/DEN
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License.
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 The Options class that manages the access to all options passed as
21 parameters in salomeTools command lines
29 from . import printcolors
32 import src.debug as DBG # Easy print stderr (for DEBUG only)
34 class OptResult(object):
36 An instance of this class will be the object manipulated
37 in code of all salomeTools commands
38 The aim of this class is to have an elegant syntax to manipulate the options.
41 | >> options, remainderArgs = command.parseArguments(args)
42 | >> print(options.output_verbose_level)
48 self.__dict__ = dict()
50 def __getattr__(self, name):
52 Overwrite of the __getattr__ function
53 to customize it for option usage
55 :param name: (str) The attribute to get the value.
56 :return: (str int list boolean level)
57 the value corresponding to the attribute.
59 if name in self.__dict__:
60 return self.__dict__[name]
62 raise AttributeError("--" + name + _(u" is not a valid option"))
64 def __setattr__(self, name, value):
66 Overwrite of the __setattr__ function
67 to customize it for option usage
69 :param name: (str) The attribute to set.
70 :param value: (str) The value corresponding to the attribute.
73 object.__setattr__(self, name, value)
76 aStr = PP.pformat(self.__dict__)
77 res = "%s(\n %s\n)" % (self.__class__.__name__, aStr[1:-1])
80 class Options(object):
82 Class to manage all salomeTools options
87 # The options field stocks all options of a command
88 # in a list that contains dicts
89 self.PROPERTY_EXPRESSION = "^.+:.+$"
91 # The list of available option type
92 self.availableOptions = "noboolean boolean string int float long list list2 level properties".split()
93 self.noArgOptions = "noboolean boolean".split()
97 def add_option(self, shortName, longName, optionType, destName, helpString="", default=None):
99 Add an option to a command. It gets all attributes
100 of an option and append it in the options field
102 :param shortName: (str)
103 The short name of the option (as '-l' for level option).
104 :param longName: (str)
105 The long name of the option (as '--level' for level option).
106 :param optionType: (str) The type of the option (ex "int").
107 :param destName: (str) The name that will be used in the code.
108 :param helpString: (str)
109 The text to display when user ask for help on a command.
112 tmp = [o['shortName'] for o in self.options if o['shortName'] != '']
114 raise Exception("option '-%s' existing yet" % shortName)
115 tmp = [o['longName'] for o in self.options if o['longName'] != '']
117 raise Exception("option '--%s' existing yet" % longName)
120 option['shortName'] = shortName
121 option['longName'] = longName
123 if optionType not in self.availableOptions:
124 raise Exception("error optionType '%s' not available." % optionType)
126 option['optionType'] = optionType
127 option['destName'] = destName
128 option['helpString'] = helpString
129 option['result'] = default
131 self.options.append(option)
133 # add option properties unconditionaly if 'products' option added
134 if [shortName, longName] == ["p", "products"]:
135 self.add_option('', 'properties', 'properties', 'properties',
136 _('Optional: Filter the products by their properties.\n\tSyntax: '
137 '--properties <property>:<value>'))
141 def getDetailOption(self, option):
145 :return: (tuple) 4-elements (shortName, longName, optionType, helpString)
147 oos = option['shortName']
148 ool = option['longName']
149 oot = option['optionType']
150 ooh = option['helpString']
151 return (oos, ool, oot, ooh)
155 Returns all options stored in self.options
156 as help message colored string
158 :return: (str) colored string
161 # Do nothing if there are no options
163 #there is -h option, always
164 #if len(self.options) == 0:
165 # return _("No available options.")
167 # for all options, gets its values.
168 # "shortname" is an mandatory field of the options, could be ''
169 msg += printcolors.printcHeader(_("Available options are:"))
170 for option in self.options:
171 oos, ool, oot, ooh = self.getDetailOption(option)
173 msg += "\n -%1s, --%s (%s)\n" % (oos, ool, oot)
175 msg += "\n --%s (%s)\n" % (ool, oot)
177 msg += "%s\n" % self.indent(ooh, 10)
180 def indent(self, text, amount, car=" "):
181 """indent multi lines message"""
182 padding = amount * car
183 return ''.join(padding + line for line in text.splitlines(True))
185 def parse_args(self, argList=None):
187 Instantiates the class OptResult
188 that gives access to all options in the code
190 :param argList: (list) the raw list of arguments that were passed
191 :return: (OptResult, list) as (optResult, args)
192 optResult is the option instance to manipulate in the code.
193 args is the full raw list of passed options
195 # see https://pymotw.com/2/getopt/
197 argList = sys.argv[1:]
199 DBG.write("parse_args", argList)
200 # DBG.write("options", self.options)
201 # format shortNameOption and longNameOption
202 # to make right arguments to getopt.getopt function
205 for option in self.options:
206 shortNameOption = shortNameOption + option['shortName']
207 if option['shortName'] != "" and option['optionType'] not in self.noArgOptions:
208 shortNameOption = shortNameOption + ":"
210 if option['longName'] != "":
211 if option['optionType'] not in self.noArgOptions:
212 longNameOption.append(option['longName'] + "=")
214 longNameOption.append(option['longName'])
216 # call to getopt.getopt function to get the option
217 # passed in the command regarding the available options
219 optlist, args = getopt.getopt(argList, shortNameOption, longNameOption)
220 except Exception as e:
221 msg = str(e) + " on '%s'\n\n" % " ".join(argList) + self.get_help()
224 # instantiate and completing the optResult that will be returned
225 optResult = OptResult()
226 for option in self.options:
227 shortOption = "-" + option['shortName']
228 longOption = "--" + option['longName']
229 optionType = option['optionType']
231 if opt[0] in [shortOption, longOption]:
232 if optionType == "string":
233 option['result'] = opt[1]
234 elif optionType == "boolean":
235 option['result'] = True
236 elif optionType == "noboolean":
237 option['result'] = False
238 elif optionType == "int":
239 option['result'] = int(opt[1])
240 elif optionType == "float":
241 option['result'] = float(opt[1])
242 elif optionType == "long":
243 option['result'] = long(opt[1])
244 elif optionType == "list":
245 if option['result'] is None:
246 option['result'] = list()
247 option['result'].append(opt[1])
248 elif optionType == "level": #logger logging levels
249 option['result'] = self.filterLevel(opt[1])
250 elif optionType == "list2":
251 if option['result'] is None:
252 option['result'] = list()
253 option['result'] = self.filterList2(opt[1])
254 elif optionType == "properties":
255 option['result'] = self.filterProperties(opt[1])
257 optResult.__setattr__(option['destName'], option['result'])
258 # free the option in order to be able to make
259 # a new free call of options (API case)
260 option['result'] = None
262 self.results = {"optlist": optlist, "optResult": optResult, "args": args, "argList": argList}
263 DBG.write("results", self.results)
264 return optResult, args
266 def filterLevel(self, aLevel):
267 """filter level logging values"""
268 import src.loggingSimple as LOG
269 aLev = aLevel.upper()
270 knownLevels = LOG._knownLevels
271 maxLen = max([len(i) for i in knownLevels])
272 for i in range(maxLen):
273 for lev in knownLevels:
275 DBG.write("filterLevel", "%s -> %s" % (aLevel, lev))
277 msg = "Unknown level '%s', accepted are:\n%s" % (aLev, ", ".join(knownLevels))
280 def filterList2(self, aStr):
281 """filter a list as 'KERNEL,YACS,etc.'"""
282 aList = aStr.strip().split(",")
283 # fix list leading ',' as ',KERNEL,...'
284 aList = [i for i in aList if i != ""] # split old list leadin "," as ",KERNEL,ETC..."
287 def filterProperties(self, aStr):
289 filter properties values
292 >> sat -v 9 prepare $TRG -p KERNEL --properties is_SALOME_module:yes
294 msg = _('The "--properties" option must have the following syntax:\n--properties <property>:<value>')
295 oExpr = re.compile(self.PROPERTY_EXPRESSION)
296 if not oExpr.search(aStr):
298 res = aStr.split(":")
305 repr for only self.options and self.results (if present)
307 aDict = {'options': self.options, 'results': self.results}
308 aStr = PP.pformat(aDict)
309 res = "%s(\n %s\n)" % (self.__class__.__name__, aStr[1:-1])
314 str for only resume expected self.options
316 #aDict = [(k["longName"], k["shortName", k["helpString"]) for k in self.options}
317 #aList = [(k, self.options[k]) for k in sorted(self.options.keys())]
319 for o in self.options:
320 aDict[o["longName"]] = (o["shortName"], o["helpString"])
321 aStr = PP.pformat(aDict)
322 res = "%s(\n %s)" % (self.__class__.__name__, aStr[1:-1])
325 def debug_write(self):
326 DBG.write("options and results", self, True)