SPPAS 4.22

https://sppas.org/

Module sppas.preinstall

Class Features

Description

Manager of the list of required external features of the software.

Constructor

Create a new Features instance.

A Features instance is a container for a list of features. It parses a '.ini' file to get each feature config.

Parameters
  • req: (str)
  • cmdos: (str)
View Source
def __init__(self, req='', cmdos='', filename=None):
    """Create a new Features instance.

    A Features instance is a container for a list of features.
    It parses a '.ini' file to get each feature config.

    :param req: (str)
    :param cmdos: (str)

    """
    self.__req = req
    self.__cmdos = cmdos
    self.__features = list()
    self.__filename = None
    if filename is not None:
        if os.path.exists(filename) and filename.endswith('.ini'):
            self.__filename = filename
    self.set_features()

Public functions

get_features_filename

Return the name of the file with the features descriptions.

View Source
def get_features_filename(self):
    """Return the name of the file with the features descriptions."""
    if self.__filename is not None:
        return self.__filename
    return os.path.join(paths.etc, 'features.ini')

get_ids

Return the list of feature identifiers of the given type.

Parameters
  • feat_type: (str) Feature type, or None to get all ids
Returns
  • (list) Feature identifiers
View Source
def get_ids(self, feat_type=None):
    """Return the list of feature identifiers of the given type.

        :param feat_type: (str) Feature type, or None to get all ids
        :return: (list) Feature identifiers

        """
    if feat_type is None:
        return [f.get_id() for f in self.__features]
    return [f.get_id() for f in self.__features if f.get_type() == feat_type]

feature_type

Return the feature type: deps, lang, annot.

Parameters
  • fid: (str) Identifier of a feature
View Source
def feature_type(self, fid):
    """Return the feature type: deps, lang, annot.

        :param fid: (str) Identifier of a feature

        """
    for feat in self.__features:
        if feat.get_id() == fid:
            return feat.get_type()
    logging.error('Unknown feature {}'.format(fid))
    return None

enable

Return True if the feature is enabled and/or set it.

Parameters
  • fid: (str) Identifier of a feature
  • value: (bool or None) Enable of disable the feature.
View Source
def enable(self, fid, value=None):
    """Return True if the feature is enabled and/or set it.

        :param fid: (str) Identifier of a feature
        :param value: (bool or None) Enable of disable the feature.

        """
    for feat in self.__features:
        if feat.get_id() == fid:
            if value is None:
                return feat.get_enable()
            return feat.set_enable(value)
    logging.error('Unknown feature {}'.format(fid))
    return False

available

Return True if the feature is available and/or set it.

Parameters
  • fid: (str) Identifier of a feature
  • value: (bool or None) Make the feature available or not.
View Source
def available(self, fid, value=None):
    """Return True if the feature is available and/or set it.

        :param fid: (str) Identifier of a feature
        :param value: (bool or None) Make the feature available or not.

        """
    for feat in self.__features:
        if feat.get_id() == fid:
            if value is None:
                return feat.get_available()
            return feat.set_available(value)
    logging.error('Unknown feature {}'.format(fid))
    return False

brief

Return the brief description of the feature.

Parameters
  • fid: (str) Identifier of a feature
View Source
def brief(self, fid):
    """Return the brief description of the feature.

        :param fid: (str) Identifier of a feature

        """
    for feat in self.__features:
        if feat.get_id() == fid:
            return feat.get_brief()
    logging.error('Unknown feature {}'.format(fid))
    return None

description

Return the description of the feature

Parameters
  • fid: (str) Identifier of a feature
View Source
def description(self, fid):
    """Return the description of the feature

        :param fid: (str) Identifier of a feature

        """
    for feat in self.__features:
        if feat.get_id() == fid:
            return feat.get_desc()
    logging.error('Unknown feature {}'.format(fid))
    return None

packages

Return the dictionary of system dependencies of the feature.

Parameters
  • fid: (str) Identifier of a feature
Returns
  • (dict) key=package; value=version
View Source
def packages(self, fid):
    """Return the dictionary of system dependencies of the feature.

        :param fid: (str) Identifier of a feature
        :return: (dict) key=package; value=version

        """
    for feat in self.__features:
        if feat.get_id() == fid:
            if isinstance(feat, DepsFeature) is True:
                return feat.get_packages()
            else:
                logging.error('Feature {} is not a DepsFeature:No packages are defined.'.format(fid))
    logging.error('Unknown feature {}'.format(fid))
    return dict()

pypi

Return the dictionary of pip dependencies of the feature.

Parameters
  • fid: (str) Identifier of a feature
Returns
  • (dict) key=package; value=version
View Source
def pypi(self, fid):
    """Return the dictionary of pip dependencies of the feature.

        :param fid: (str) Identifier of a feature
        :return: (dict) key=package; value=version

        """
    for feat in self.__features:
        if feat.get_id() == fid:
            if isinstance(feat, DepsFeature) is True:
                pips = dict()
                for key in feat.get_pypi_packages():
                    pips[key] = feat.get_pypi_package_version(key)
                return pips
            else:
                logging.error('Feature {} is not a DepsFeature:No pypi is defined.'.format(fid))
    logging.error('Unknown feature {}'.format(fid))
    return dict()

pypi_alt

Return the dictionary of alternative pip dependencies of the feature.

Parameters
  • fid: (str) Identifier of a feature
Returns
  • (dict) key=package; value=version
View Source
def pypi_alt(self, fid):
    """Return the dictionary of alternative pip dependencies of the feature.

        :param fid: (str) Identifier of a feature
        :return: (dict) key=package; value=version

        """
    for feat in self.__features:
        if feat.get_id() == fid:
            if isinstance(feat, DepsFeature) is True:
                pips = dict()
                for key in feat.get_pypi_alt_packages():
                    pips[key] = feat.get_pypi_alt_package_version(key)
                return pips
            else:
                logging.error('Feature {} is not a DepsFeature:No alt pypi is defined.'.format(fid))
    logging.error('Unknown feature {}'.format(fid))
    return dict()

pypi_opt

Return the options of a pip dependency of the feature.

Parameters
  • fid: (str) Identifier of a feature
Returns
  • (str)
View Source
def pypi_opt(self, fid):
    """Return the options of a pip dependency of the feature.

        :param fid: (str) Identifier of a feature
        :return: (str)

        """
    for feat in self.__features:
        if feat.get_id() == fid:
            if isinstance(feat, DepsFeature) is True:
                return feat.get_pip_options()
    return ''

cmd

Return the command to execute for the feature.

Parameters
  • fid: (str) Identifier of a feature
Returns
  • (str)
View Source
def cmd(self, fid):
    """Return the command to execute for the feature.

        :param fid: (str) Identifier of a feature
        :return: (str)

        """
    for feat in self.__features:
        if feat.get_id() == fid:
            if isinstance(feat, DepsFeature) is True:
                return feat.get_cmd()
            else:
                logging.error('Feature {} is not a DepsFeature:No cmd is defined.'.format(fid))
    logging.error('Unknown feature {}'.format(fid))
    return str()

lang

Return the lang code of the linguistic resource to download.

Parameters
  • fid: (str) Identifier of a feature
Returns
  • (str)
View Source
def lang(self, fid):
    """Return the lang code of the linguistic resource to download.

        :param fid: (str) Identifier of a feature
        :return: (str)

        """
    for feat in self.__features:
        if feat.get_id() == fid:
            if isinstance(feat, LangFeature) is True:
                return feat.get_lang()
            else:
                logging.error('Feature {} is not a LangFeature:No lang is defined.'.format(fid))
    logging.error('Unknown feature {}'.format(fid))
    return str()

annot

Return the name the annotation resource to download.

Parameters
  • fid: (str) Identifier of a feature
Returns
  • (str)
View Source
def annot(self, fid):
    """Return the name the annotation resource to download.

        :param fid: (str) Identifier of a feature
        :return: (str)

        """
    for feat in self.__features:
        if feat.get_id() == fid:
            if isinstance(feat, AnnotFeature) is True:
                return feat.get_annot()
            else:
                logging.error('Feature {} is not an AnnotFeature:No annot is defined.'.format(fid))
    logging.error('Unknown feature {}'.format(fid))
    return str()

set_features

Browses the features.ini file and instantiate a Feature().

Only unix-based systems can have package requirements. If they don't, the corresponding req_ attribute is missing or empty or with "nil".

A feature is not available for a system, if none of the corresponding "cmd" and "req" and the "pip" attributes are defined.

View Source
def set_features(self):
    """Browses the features.ini file and instantiate a Feature().

        Only unix-based systems can have package requirements. If they don't,
        the corresponding req_ attribute is missing or empty or with "nil".

        A feature is not available for a system, if none of the corresponding "cmd_"
        and "req_" and the "pip" attributes are defined.

        """
    self.__features = list()
    features_parser = self.__init_features()
    for fid in features_parser.sections():
        try:
            feature = self.__set_feature(fid, features_parser)
        except cp.NoOptionError:
            logging.error('Missing or wrong feature type for feature {}'.format(fid))
            continue
        self.__features.append(feature)
        try:
            desc = features_parser.get(fid, 'brief')
            feature.set_brief(desc)
        except cp.NoOptionError:
            pass
        try:
            desc = features_parser.get(fid, 'desc')
            feature.set_desc(desc)
        except cp.NoOptionError:
            pass
        try:
            e = features_parser.getboolean(fid, 'enable')
            feature.set_enable(e)
        except cp.NoOptionError:
            pass
    ids = self.get_ids()
    for fid in cfg.get_feature_ids():
        if fid in ids:
            self.enable(fid, not cfg.feature_installed(fid))
        else:
            logging.error('The config file contains an unknown feature identifier {}'.format(fid))

Protected functions

__set_feature

View Source
def __set_feature(self, fid, parser):
    feature = None
    try:
        ft = parser.get(fid, 'type')
        if ft == 'deps':
            feature = DepsFeature(fid)
            self.__fill_deps_feature(feature, parser)
        if ft == 'lang':
            feature = LangFeature(fid)
            self.__fill_lang_feature(feature)
        if ft == 'annot':
            feature = AnnotFeature(fid)
            self.__fill_annot_feature(feature)
    except cp.NoOptionError:
        pass
    if feature is not None:
        return feature
    raise cp.NoOptionError

__fill_deps_feature

View Source
def __fill_deps_feature(self, feature, parser):
    fid = feature.get_id()
    try:
        d = parser.get(fid, self.__req)
        if len(d) > 0 and d.lower() != 'nil':
            depend_packages = self.__parse_depend(d)
            feature.set_packages(depend_packages)
    except cp.NoOptionError:
        pass
    try:
        d = parser.get(fid, 'pip')
        if len(d) > 0 and d.lower() != 'nil':
            depend_pypi = self.__parse_depend(d)
            for key in depend_pypi:
                feature.add_pypi(key, depend_pypi[key])
        d = parser.get(fid, 'pip_alt')
        if len(d) > 0 and d.lower() != 'nil':
            depend_pypi = self.__parse_depend(d)
            for key in depend_pypi:
                feature.add_pypi_alt(key, depend_pypi[key])
        opt = parser.get(fid, 'pip_opt')
        if len(opt) > 0 and opt.lower() != 'nil':
            feature.set_pip_options(opt)
    except cp.NoOptionError:
        pass
    try:
        cmd = parser.get(fid, self.__cmdos)
        if len(cmd) > 0 and cmd != 'none' and (cmd != 'nil'):
            feature.set_cmd(cmd)
    except cp.NoOptionError:
        pass
    if len(feature.get_cmd()) > 0 or len(feature.get_pypi_packages()) > 0 or len(feature.get_packages()) > 0:
        feature.set_available(True)
        if fid not in cfg.get_feature_ids():
            logging.debug(' -->> newly available feature: {:s}'.format(fid))

__fill_lang_feature

View Source
def __fill_lang_feature(self, feature):
    fid = feature.get_id()
    feature.set_lang(fid)
    feature.set_available(True)

__fill_annot_feature

View Source
def __fill_annot_feature(self, feature):
    fid = feature.get_id()
    feature.set_annot(fid)
    feature.set_available(True)
    if fid not in cfg.get_feature_ids():
        cfg.set_feature(fid, False)
        logging.debug(' ----->>> new available feature: {:s}'.format(fid))
    else:
        logging.debug(' ----->>> already available feature: {:s}'.format(fid))

__init_features

Return a parsed version of the features.ini file.

View Source
def __init_features(self):
    """Return a parsed version of the features.ini file."""
    cfg = self.get_features_filename()
    if cfg is None:
        raise IOError('Installation error: the file {filename} to configure the software is missing.'.format(filename=cfg))
    features_parser = cp.ConfigParser()
    try:
        features_parser.read(self.get_features_filename())
    except cp.MissingSectionHeaderError:
        raise IOError('Malformed features configuration file {}: missing section header.'.format(cfg))
    return features_parser

__parse_depend

Create a dictionary from the string given as an argument.

Parameters
  • stringrequire: (*str*ing) The value of one of the req* key in one of the section of feature.ini.
Returns
  • (dict)
View Source
@staticmethod
def __parse_depend(string_require):
    """Create a dictionary from the string given as an argument.

        :param string_require: (string) The value of one of the req_*** key in one of the section of feature.ini.
        :return: (dict)

        """
    string_require = str(string_require)
    dependencies = string_require.split(' ')
    depend = dict()
    for line in dependencies:
        tab = line.split(':')
        depend[tab[0]] = tab[1]
    return depend

Overloads

__str__

Print each Feature of the list.

View Source
def __str__(self):
    """Print each Feature of the list. """
    for f in self.__features:
        print(f.__str__())

__format__

View Source
def __format__(self, fmt):
    return str(self).__format__(fmt)

__len__

Return the number of features.

View Source
def __len__(self):
    """Return the number of features."""
    return len(self.__features)

__contains__

Value can be either a Feature or its identifier.

Parameters
  • value
View Source
def __contains__(self, value):
    """Value can be either a Feature or its identifier."""
    if isinstance(value, Feature):
        return value in self.__features
    else:
        for f in self.__features:
            if f.get_id() == value:
                return True
    return False