Source code for preinstall.feature
# -*- coding : UTF-8 -*-
"""
:filename: sppas.src.preinstall.feature.py
:author: Florian Hocquet, Brigitte Bigi
:contact: develop@sppas.org
:summary: Data structure for one of the feature of SPPAS dependencies.
.. _This file is part of SPPAS: http://www.sppas.org/
..
-------------------------------------------------------------------------
___ __ __ __ ___
/ | \ | \ | \ / the automatic
\__ |__/ |__/ |___| \__ annotation and
\ | | | | \ analysis
___/ | | | | ___/ of speech
Copyright (C) 2011-2021 Brigitte Bigi
Laboratoire Parole et Langage, Aix-en-Provence, France
Use of this software is governed by the GNU Public License, version 3.
SPPAS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
SPPAS 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with SPPAS. If not, see <http://www.gnu.org/licenses/>.
This banner notice must not be removed.
-------------------------------------------------------------------------
"""
import logging
import uuid
import re
from sppas.src.config import paths
from sppas.src.config import info
# ---------------------------------------------------------------------------
def _info(identifier):
return info(identifier, "globals")
MSG_NO_BRIEF = _info("No brief description available.")
MSG_NO_DESCR = _info("No description is available for this feature.")
# ---------------------------------------------------------------------------
[docs]class Feature(object):
"""Store information of one feature required by the application.
:Example:
>>> feature = Feature("feature")
>>> feature.get_id()
>>> "feature"
>>> feature.set_enable(True)
>>> feature.set_available(True)
>>> feature.set_desc("An example of feature")
>>> feature.set_packages({"wxpython": ">;4.0"})
>>> feature.set_pypi({"numpy": ">;0.0"})
>>> feature.set_cmd("pip freeze")
"""
[docs] def __init__(self, identifier):
"""Create a new Feature instance.
:param identifier: (str) An identifier string.
The identifier must contain at least 2 characters and US-ASCII only.
If these requirements are not satisfied, a GUID is used instead.
"""
# Represent the identifier of the feature
self.__id = str(uuid.uuid4())
self.__set_id(identifier)
# Represent if the feature is enable
self.__enable = False
# Represent if the feature is available
self.__available = False
# Represent a short description of the feature
self.__brief = MSG_NO_BRIEF
# Represent a full description of the feature
self.__descr = MSG_NO_DESCR
# ------------------------------------------------------------------------
[docs] def get_type(self):
return str()
# ------------------------------------------------------------------------
def __set_id(self, identifier):
"""Private. Set the id if valid."""
identifier = identifier.strip()
# Check length
if len(identifier) > 1:
# Check if US-ASCII only characters
ra = re.sub(r'[^a-zA-Z0-9_]', '', identifier)
if identifier == ra:
self.__id = identifier
# ------------------------------------------------------------------------
[docs] def get_id(self):
"""Return the feature identifier."""
return self.__id
# ------------------------------------------------------------------------
[docs] def get_enable(self):
"""Return True if the feature is enabled."""
return self.__enable
# ------------------------------------------------------------------------
[docs] def set_enable(self, value):
"""Set the value of enable.
:param value: (bool) Enable or disable the feature.
"""
if not self.get_available():
self.__enable = False
else:
value = bool(value)
self.__enable = value
# ------------------------------------------------------------------------
[docs] def get_available(self):
"""Return True if the feature is available."""
return self.__available
# ------------------------------------------------------------------------
[docs] def set_available(self, value):
"""Set the value of available.
:param value: (bool) Make the feature available or not.
"""
value = bool(value)
if not value:
self.set_enable(False)
self.__available = value
# ------------------------------------------------------------------------
[docs] def get_brief(self):
"""Return a short description of the feature."""
return self.__brief
# ------------------------------------------------------------------------
[docs] def set_brief(self, value):
"""Set the brief description of the feature.
:param value: (str) The description to describe the feature.
"""
value = str(value)
value = value.strip()
if len(value) == 0:
value = MSG_NO_BRIEF
self.__brief = value
# ------------------------------------------------------------------------
[docs] def get_desc(self):
"""Return the description of the feature."""
return self.__descr
# ------------------------------------------------------------------------
[docs] def set_desc(self, value):
"""Set the description of the feature.
:param value: (str) The description to describe the feature.
"""
value = str(value)
value = value.strip()
if len(value) == 0:
value = MSG_NO_DESCR
self.__descr = value
# ------------------------------------------------------------------------
def __str__(self):
return "id: " + str(self.get_id()) + "\n" \
"enable: " + str(self.get_enable()) + "\n" \
"available: " + str(self.get_available()) + "\n" \
"brief: " + str(self.get_brief()) + "\n" \
"description: " + str(self.get_desc()) + "\n"
# ---------------------------------------------------------------------------
[docs]class DepsFeature(Feature):
"""Store information of one feature required by the application.
Sub-class to represent a package to be installed or a command to be
executed, or both, ie the need of external programs.
"""
[docs] def __init__(self, identifier):
super(DepsFeature, self).__init__(identifier)
# Represent the required system packages
self.__packages = dict()
# Represent the required pip packages
self.__pypi = dict()
# Represent a command to be executed
self.__cmd = str()
# ------------------------------------------------------------------------
[docs] def get_type(self):
return "deps"
# ------------------------------------------------------------------------
[docs] def get_packages(self):
"""Return the dictionary of system dependencies."""
return self.__packages
# ------------------------------------------------------------------------
[docs] def set_packages(self, dependencies):
"""Set the dictionary of system dependencies.
:param dependencies: (dict)
"""
dependencies = dict(dependencies)
self.__packages = dependencies
# ------------------------------------------------------------------------
[docs] def get_pypi(self):
"""Return the dictionary of pip dependencies."""
return self.__pypi
# ------------------------------------------------------------------------
[docs] def set_pypi(self, dependencies):
"""Set the dictionary of pip dependencies.
:param dependencies: (dict)
"""
dependencies = dict(dependencies)
self.__pypi = dependencies
# ------------------------------------------------------------------------
[docs] def get_cmd(self):
"""Return the command to execute."""
return self.__cmd
# ------------------------------------------------------------------------
[docs] def set_cmd(self, value):
"""Set the command to execute.
:param value: (str) The system command for the OS.
"""
value = str(value)
if "$SPPAS" in value:
base_dir = paths.basedir
if "\\" in base_dir:
base_dir = base_dir.replace("\\", "\\\\")
value = value.replace("$SPPAS", base_dir)
self.__cmd = value
# ---------------------------------------------------------------------------
[docs]class LangFeature(Feature):
"""Store information of one feature required by the application.
Sub-class to represent a language support, ie the need to download
linguistic resources of a given language to enable language-dependent
automatic annotations.
"""
[docs] def __init__(self, identifier):
super(LangFeature, self).__init__(identifier)
self.__lang = str()
# ------------------------------------------------------------------------
[docs] def get_type(self):
return "lang"
# ------------------------------------------------------------------------
[docs] def get_lang(self):
"""Return the lang resource name to be downloaded."""
return self.__lang
# ------------------------------------------------------------------------
[docs] def set_lang(self, value):
"""Set the iso-6639-3 code of the lang resource to download.
:param value: (str) 3 chars if standard name
"""
value = str(value)
value = value.strip()
if len(value) != 3:
logging.warning("Set a non-standard language name '{:s}'"
" for feature '{}'.".format(value, self.get_id()))
self.__lang = value
# ---------------------------------------------------------------------------
[docs]class AnnotFeature(Feature):
"""Store information of one feature required by the application.
Sub-class to represent a the support of an automatic annotation, ie
the need to download resources (models, protos...) to enable the
automatic annotation.
"""
[docs] def __init__(self, identifier):
super(AnnotFeature, self).__init__(identifier)
self.__annot = str()
# ------------------------------------------------------------------------
[docs] def get_type(self):
return "annot"
# ------------------------------------------------------------------------
[docs] def get_annot(self):
"""Return the annotation resource name to be downloaded."""
return self.__annot
# ------------------------------------------------------------------------
[docs] def set_annot(self, value):
"""Set the annotation resource name to download.
:param value: (str) ascii-only chars
"""
value = str(value)
value = value.strip()
if len(value) == 0:
logging.warning("Attempted to set a wrong annot name '{:s}' for "
"feature '{}'.".format(value, self.get_id()))
else:
self.__annot = value