Check if the given python dependencies can be imported.
Module sppas.core.preinstall
Class DepsFeatureChecker
Description
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())
