Source code for src.options

#!/usr/bin/env python
#-*- coding:utf-8 -*-
#  Copyright (C) 2010-2013  CEA/DEN
#
#  This library is free software; you can redistribute it and/or
#  modify it under the terms of the GNU Lesser General Public
#  License as published by the Free Software Foundation; either
#  version 2.1 of the License.
#
#  This library is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#  Lesser General Public License for more details.
#
#  You should have received a copy of the GNU Lesser General Public
#  License along with this library; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

"""
The Options class that manages the access to all options passed as 
parameters in salomeTools command lines
"""

import getopt
import sys
import pprint as PP

from . import printcolors

import src
import src.debug as DBG # Easy print stderr (for DEBUG only)

[docs]class OptResult(object): """ An instance of this class will be the object manipulated in code of all salomeTools commands The aim of this class is to have an elegant syntax to manipulate the options. | Example: | >> options, remainderArgs = command.parseArguments(args) | >> print(options.output_verbose_level) | >> 'INFO' """ def __init__(self): """Initialization """ self.__dict__ = dict() def __getattr__(self, name): """ Overwrite of the __getattr__ function to customize it for option usage :param name: (str) The attribute to get the value. :return: (str int list boolean level) the value corresponding to the attribute. """ if name in self.__dict__: return self.__dict__[name] else: raise AttributeError("--" + name + _(u" is not a valid option")) def __setattr__(self, name, value): """ Overwrite of the __setattr__ function to customize it for option usage :param name: (str) The attribute to set. :param value: (str) The value corresponding to the attribute. :return: None """ object.__setattr__(self, name, value) def __repr__(self): aStr = PP.pformat(self.__dict__) res = "%s(\n %s\n)" % (self.__class__.__name__, aStr[1:-1]) return res
[docs]class Options(object): """ Class to manage all salomeTools options """ def __init__(self): """Initialization """ # The options field stocks all options of a command # in a list that contains dicts self.options = [] # The list of available option type self.availableOptions = "noboolean boolean string int float long list list2 level".split() self.noArgOptions = "noboolean boolean".split() self.default = None self.results = {}
[docs] def add_option(self, shortName, longName, optionType, destName, helpString="", default=None): """ Add an option to a command. It gets all attributes of an option and append it in the options field :param shortName: (str) The short name of the option (as '-l' for level option). :param longName: (str) The long name of the option (as '--level' for level option). :param optionType: (str) The type of the option (ex "int"). :param destName: (str) The name that will be used in the code. :param helpString: (str) The text to display when user ask for help on a command. :return: None """ tmp = [o['shortName'] for o in self.options if o['shortName'] != ''] if shortName in tmp: raise Exception("option '-%s' existing yet" % shortName) tmp = [o['longName'] for o in self.options if o['longName'] != ''] if longName in tmp: raise Exception("option '--%s' existing yet" % longName) option = dict() option['shortName'] = shortName option['longName'] = longName if optionType not in self.availableOptions: raise Exception("error optionType '%s' not available." % optionType) option['optionType'] = optionType option['destName'] = destName option['helpString'] = helpString option['result'] = default self.options.append(option)
[docs] def getDetailOption(self, option): """ for convenience :return: (tuple) 4-elements (shortName, longName, optionType, helpString) """ oos = option['shortName'] ool = option['longName'] oot = option['optionType'] ooh = option['helpString'] return (oos, ool, oot, ooh)
[docs] def get_help(self): """ Returns all options stored in self.options as help message colored string :return: (str) colored string """ msg = "" # Do nothing if there are no options #there is -h option, always #if len(self.options) == 0: # return _("No available options.") # for all options, gets its values. # "shortname" is an mandatory field of the options, could be '' msg += printcolors.printcHeader(_("Available options are:")) for option in self.options: oos, ool, oot, ooh = self.getDetailOption(option) if len(oos) > 0: msg += "\n -%1s, --%s (%s)\n" % (oos, ool, oot) else: msg += "\n --%s (%s)\n" % (ool, oot) msg += "%s\n" % self.indent(ooh, 10) return msg
[docs] def indent(self, text, amount, car=" "): """indent multi lines message""" padding = amount * car return ''.join(padding + line for line in text.splitlines(True))
[docs] def parse_args(self, argList=None): """ Instantiates the class OptResult that gives access to all options in the code :param argList: (list) the raw list of arguments that were passed :return: (OptResult, list) as (optResult, args) optResult is the option instance to manipulate in the code. args is the full raw list of passed options """ # see https://pymotw.com/2/getopt/ if argList is None: argList = sys.argv[1:] DBG.write("parse_args", argList) # DBG.write("options", self.options) # format shortNameOption and longNameOption # to make right arguments to getopt.getopt function shortNameOption = "" longNameOption = [] for option in self.options: shortNameOption = shortNameOption + option['shortName'] if option['shortName'] != "" and option['optionType'] not in self.noArgOptions: shortNameOption = shortNameOption + ":" if option['longName'] != "": if option['optionType'] not in self.noArgOptions: longNameOption.append(option['longName'] + "=") else: longNameOption.append(option['longName']) # call to getopt.getopt function to get the option # passed in the command regarding the available options try: optlist, args = getopt.getopt(argList, shortNameOption, longNameOption) except Exception as e: msg = str(e) + " on '%s'\n\n" % " ".join(argList) + self.get_help() raise Exception(msg) # instantiate and completing the optResult that will be returned optResult = OptResult() for option in self.options: shortOption = "-" + option['shortName'] longOption = "--" + option['longName'] optionType = option['optionType'] for opt in optlist: if opt[0] in [shortOption, longOption]: if optionType == "string": option['result'] = opt[1] elif optionType == "boolean": option['result'] = True elif optionType == "noboolean": option['result'] = False elif optionType == "int": option['result'] = int(opt[1]) elif optionType == "float": option['result'] = float(opt[1]) elif optionType == "long": option['result'] = long(opt[1]) elif optionType == "list": if option['result'] is None: option['result'] = list() option['result'].append(opt[1]) elif optionType == "level": #logger logging levels option['result'] = self.filterLevel(opt[1]) elif optionType == "list2": if option['result'] is None: option['result'] = list() option['result'] = self.filterList2(opt[1]) optResult.__setattr__(option['destName'], option['result']) # free the option in order to be able to make # a new free call of options (API case) option['result'] = None self.results = {"optlist": optlist, "optResult": optResult, "args": args, "argList": argList} DBG.write("results", self.results) return optResult, args
[docs] def filterLevel(self, aLevel): """filter level logging values""" import src.loggingSimple as LOG aLev = aLevel.upper() knownLevels = LOG._knownLevels maxLen = max([len(i) for i in knownLevels]) for i in range(maxLen): for lev in knownLevels: if aLev == lev[:i]: DBG.write("filterLevel", "%s -> %s" % (aLevel, lev)) return lev msg = "Unknown level '%s', accepted are:\n%s" % (aLev, ", ".join(knownLevels)) raise Exception(msg)
[docs] def filterList2(self, aStr): """filter a list as 'KERNEL,YACS,etc.'""" aList = aStr.strip().split(",") # fix list leading ',' as ',KERNEL,...' aList = [i for i in aList if i != ""] # split old list leadin "," as ",KERNEL,ETC..." return aList
def __repr__(self): """ repr for only self.options and self.results (if present) """ aDict = {'options': self.options, 'results': self.results} aStr = PP.pformat(aDict) res = "%s(\n %s\n)" % (self.__class__.__name__, aStr[1:-1]) return res def __str__(self): """ str for only resume expected self.options """ #aDict = [(k["longName"], k["shortName", k["helpString"]) for k in self.options} #aList = [(k, self.options[k]) for k in sorted(self.options.keys())] aDict = {} for o in self.options: aDict[o["longName"]] = (o["shortName"], o["helpString"]) aStr = PP.pformat(aDict) res = "%s(\n %s)" % (self.__class__.__name__, aStr[1:-1]) return res
[docs] def debug_write(self): DBG.write("options and results", self, True)