sppas 5.1.0

https://sppas.org/

Module sppas.core.preinstall

Class DepsFeatureChecker

Description

Check if the given python dependencies can be imported.

Constructor

__init__

Create a module import checker.

By default, the tested values are the required one, for core, i.e.: values = ((("whakerpy",), ("audioopy",)), None)

Parameters
  • values: tuple(modules, commands) to check, where: - modules: tuple of tuples, each inner tuple is an OR group, AND between groups. E.g. (('a', 'b'), ('c',)) means (a OR b) AND c - commands: tuple of commands to check (all must succeed).
Example
 >>> # Check core dependencies by default and create a report if error
 >>> core_checker = DepsFeatureChecker()
 >>> core_checker.check(do_report=True)
 >>> # The features needs a pip package but no command
 >>> wxpython_checker = DepsFeatureChecker(((("wx", ),), None))
 >>> wxpython_checker.check()
 >>> # The feature does not need a pip package but a command
 >>> julius_checker = DepsFeatureChecker((None, (("julius", ),)))
 >>> julius_checker.check()
 >>> # The features needs both pip packages and a command
 >>> stt_checker = DepsFeatureChecker(((("torch",), ("whisper",), ("transformers",)), ("ffmpeg -h",)))
 >>> stt_checker.check()
View Source
def __init__(self, values=None):
    """Create a module import checker.

    By default, the tested values are the required one, for core, i.e.:
    values = ((("whakerpy",), ("audioopy",)), None)

    :param values: tuple (modules, commands) to check, where:
           - modules: tuple of tuples, each inner tuple is an OR group, AND between groups.
             E.g. (('a', 'b'), ('c',)) means (a OR b) AND c
           - commands: tuple of commands to check (all must succeed).

    :example:
    >>> # Check core dependencies by default and create a report if error
    >>> core_checker = DepsFeatureChecker()
    >>> core_checker.check(do_report=True)
    >>> # The features needs a pip package but no command
    >>> wxpython_checker = DepsFeatureChecker(((("wx", ),), None))
    >>> wxpython_checker.check()
    >>> # The feature does not need a pip package but a command
    >>> julius_checker = DepsFeatureChecker((None, (("julius", ),)))
    >>> julius_checker.check()
    >>> # The features needs both pip packages and a command
    >>> stt_checker = DepsFeatureChecker(((("torch",), ("whisper",), ("transformers",)), ("ffmpeg -h",)))
    >>> stt_checker.check()

    """
    if values is None:
        values = ((('whakerpy',), ('audioopy',)), None)
    self.__values = values

Public functions

check

Check if the defined dependencies can be imported or executed.

Parameters
  • do_report: whether to report errors or not in a file and in web browser
Returns
  • (list) List of messages
Raises
  • ImportError: a module failed to be imported
  • RuntimeError: a command failed to be executed
View Source
def check(self, do_report=False) -> list:
    """Check if the defined dependencies can be imported or executed.

        :param do_report: whether to report errors or not in a file and in web browser
        :return: (list) List of messages
        :raises: ImportError: a module failed to be imported
        :raises: RuntimeError: a command failed to be executed

        """
    msg = list()
    try:
        test_modules, test_commands = self.__values
        if test_commands is not None:
            DepsFeatureChecker.check_commands(test_commands)
            msg.append(f" - Successfully executed: '{test_commands}'.")
        if test_modules is not None:
            DepsFeatureChecker.check_modules(test_modules)
            msg.append(f" - Successfully imported: '{test_modules}'.")
    except ImportError as e:
        if do_report is True:
            msg.append(str(e))
            self.report_message('\n'.join(msg))
        raise
    except RuntimeError as e:
        if do_report is True:
            msg.append(str(e))
            self.report_message('\n'.join(msg))
        raise
    return msg

check_modules

Check if the defined module dependencies can be imported.

Parameters
  • test_modules: tuple of tuples(OR-groups in AND-chain), e.g. (('a', 'b'), ('c',))
Raises
  • ImportError: if any AND-group fails (i.e., no module in OR-group can be imported)
View Source
@staticmethod
def check_modules(test_modules):
    """Check if the defined module dependencies can be imported.

        :param test_modules: tuple of tuples (OR-groups in AND-chain), e.g. (('a', 'b'), ('c',))
        :raises: ImportError: if any AND-group fails (i.e., no module in OR-group can be imported)

        """
    if test_modules is None:
        return
    if isinstance(test_modules, str):
        test_modules = ((test_modules,),)
    elif isinstance(test_modules, tuple) and all((isinstance(m, str) for m in test_modules)):
        test_modules = (test_modules,)
    for or_group in test_modules:
        found = False
        for module_name in or_group:
            try:
                __import__(module_name)
                found = True
                break
            except ImportError:
                continue
            except Exception as e:
                raise ImportError(f"Error while importing '{module_name}': {e}")
        if not found:
            raise ImportError(f'None of the modules in {or_group} could be imported.')

check_commands

Check if the defined command dependencies can be executed.

Parameters
  • test_commands: (list) the commands to check
Raises
  • RuntimeError: a command failed to be executed
View Source
@staticmethod
def check_commands(test_commands) -> None:
    """Check if the defined command dependencies can be executed.

        :param test_commands: (list) the commands to check
        :raises: RuntimeError: a command failed to be executed

        """
    if test_commands is not None:
        for command in test_commands:
            p = sppasExecProcess()
            success = p.test_command(command)
            if success is False:
                raise RuntimeError(f'Failed to execute the required command: {command}.')

report_message

Create a report of the error and open it in the web browser.

Parameters
  • message: the error message to be displayed
View Source
@staticmethod
def report_message(message: str) -> None:
    """Create a report of the error and open it in the web browser.

        :param message: the error message to be displayed

        """
    report = sppasLogFile(pattern='setup')
    with open(report.get_filename(), 'w') as f:
        f.write(report.get_header())
        f.write(message + '\n')
    webbrowser.open(url=report.get_filename())