Salome HOME
merge from master 8B7B
authorChristian Van Wambeke <christian.van-wambeke@cea.fr>
Wed, 27 Jun 2018 09:28:28 +0000 (11:28 +0200)
committerChristian Van Wambeke <christian.van-wambeke@cea.fr>
Wed, 27 Jun 2018 09:28:28 +0000 (11:28 +0200)
1  2 
src/options.py

diff --combined src/options.py
index 911cb713f88df275343603f480dde43b0253c361,2cfeae0ae84246bbe33a8ffa966b5db2fbe801b3..b84eae14e81266b68f68332f2bf7390c634b8b16
mode 100755,100644..100755
  #  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
 -'''
 +
 +"""
 +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)
 +
  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. 
 -       ex: 
 -       print(options.level)
 -       5
 -    '''
 +    """
 +    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
 -        '''
 +        """Initialization
 +        """
          self.__dict__ = dict()
  
      def __getattr__(self, name):
 -        '''Overwrite of the __getattr__ function 
 -           to customize it for option usage
 +        """
 +        Overwrite of the __getattr__ function 
 +        to customize it for option usage
          
 -        :param name str: The attribute to get the value.
 -        :return: the value corresponding to the attribute.
 -        :rtype: str,int,list,boolean
 -        '''
 +        :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"))
 +            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
 +        """
 +        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: Nothing.
 -        :rtype: N\A
 -        '''
 -        object.__setattr__(self,name,value)
 -
 -class Options:
 -    '''Class to manage all salomeTools options
 -    '''
 +        :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
 +
 +class Options(object):
 +    """
 +    Class to manage all salomeTools options
 +    """
      def __init__(self):
 -        '''Initialization
 -        '''
 +        """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 = ["boolean", "string", "int", "float",
 -                                  "long", "list", "list2"]
 +        self.availableOptions = "noboolean boolean string int float long list list2 level".split()
 +        self.noArgOptions = "noboolean boolean".split()
          self.default = None
 +        self.results = {}
  
 -    def add_option(self, shortName, longName,
 -                    optionType, destName, helpString="", default = None):
 -        '''Method to add an option to a command. It gets all attributes
 -           of an option and append it in the options field
 +    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
 -                              (ex "l" for level option).
 -        :param longName str: The long name of the option 
 -                             (ex "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: Nothing.
 -        :rtype: N\A
 -        '''
 +        :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:
 -            print("error optionType", optionType, "not available.")
 -            sys.exit(-1)
 +          raise Exception("error optionType '%s' not available." % optionType)
  
          option['optionType'] = optionType
          option['destName'] = destName
          option['helpString'] = helpString
          option['result'] = default
 +        
          self.options.append(option)
 +        
 +    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)
  
 -    def print_help(self):
 -        '''Method that display all options stored in self.options and there help
 +    def get_help(self):
 +        """
 +        Returns all options stored in self.options 
 +        as help message colored string
          
 -        :return: Nothing.
 -        :rtype: N\A
 -        '''
 +        :return: (str) colored string
 +        """
 +        msg = ""
          # Do nothing if there are no options
 -        if len(self.options) == 0:
 -            return
  
 -        # for all options, print its values. 
 -        # "shortname" is an optional field of the options 
 -        print(printcolors.printcHeader(_("Available options are:")))
 +        #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:
 -            if 'shortName' in option and len(option['shortName']) > 0:
 -                print(" -%(shortName)1s, --%(longName)s"
 -                      " (%(optionType)s)\n\t%(helpString)s\n" % option)
 +            oos, ool, oot, ooh = self.getDetailOption(option)
 +            if len(oos) > 0:
 +                msg += "\n -%1s, --%s (%s)\n" % (oos, ool, oot)
              else:
 -                print(" --%(longName)s (%(optionType)s)\n\t%(helpString)s\n"
 -                       % option)
 +                msg += "\n --%s (%s)\n" % (ool, oot)
 +                
 +            msg += "%s\n" % self.indent(ooh, 10)
 +        return msg
  
 +    def indent(self, text, amount, car=" "):
 +        """indent multi lines message"""
 +        padding = amount * car
 +        return ''.join(padding + line for line in text.splitlines(True))
 +               
      def parse_args(self, argList=None):
 -        '''Method that instantiates the class OptResult 
 -           that gives access to all options in the code
 +        """
 +        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, args : optResult is the option instance 
 -                                   to manipulate in the code. args 
 -                                   is the full raw list of passed options 
 -        :rtype: (class 'common.options.OptResult',list)
 -        '''
 +        :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'] != "boolean":
 +            if option['shortName'] != "" and option['optionType'] not in self.noArgOptions:
                  shortNameOption = shortNameOption + ":"
  
              if option['longName'] != "":
 -                if option['optionType'] != "boolean":
 +                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
 -        optlist, args = getopt.getopt(argList, shortNameOption, longNameOption)
 -        
 +        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:
                          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":
                          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()
 -                        if opt[1].find(",") == -1:
 -                            option['result'].append(opt[1])
 -                        else:
 -                            elts = filter(lambda l: len(l) > 0, opt[1].split(","))
 -                            option['result'].extend(elts)
 +                        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
-       import src.loggingSimple as LOG
 +        
 +    def filterLevel(self, aLevel):
 +      """filter level logging values"""
++      import src.loggingSat 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)
 +      
 +    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
 +        
 +    def debug_write(self):
 +        DBG.write("options and results", self, True)
 +