"""Functionality to check for the availability and version of dependencies.
This file is generated by l2tdevtools update-dependencies.py, any dependency related
changes should be made in dependencies.ini.
"""
import re
# Dictionary that contains version tuples per module name.
#
# A version tuple consists of:
# (version_attribute_name, minimum_version, maximum_version, is_required)
#
# Where version_attribute_name is either a name of an attribute,
# property or method.
PYTHON_DEPENDENCIES = {
"acstore": ("__version__", "20240407", None, True),
"artifacts": ("__version__", "20220219", None, True),
"bencode": ("", "", None, True),
"certifi": ("__version__", "2016.9.26", None, True),
"dateutil": ("__version__", "1.5", None, True),
"defusedxml": ("__version__", "0.5.0", None, True),
"dfdatetime": ("__version__", "20251018", None, True),
"dfvfs": ("__version__", "20260411", None, True),
"dfwinreg": ("__version__", "20240229", None, True),
"dtfabric": ("__version__", "20230518", None, True),
"flor": ("__version__", "1.1.3", None, False),
"lz4": ("__version__", "0.10.0", None, True),
"opensearchpy": ("__versionstr__", "", None, False),
"pefile": ("__version__", "2023.2.7", None, True),
"psutil": ("__version__", "5.4.3", None, True),
"pybde": ("get_version()", "20220121", None, True),
"pycaes": ("get_version()", "20240114", None, True),
"pycreg": ("get_version()", "20200725", None, True),
"pyesedb": ("get_version()", "20220806", None, True),
"pyevt": ("get_version()", "20191104", None, True),
"pyevtx": ("get_version()", "20220724", None, True),
"pyewf": ("get_version()", "20131210", None, True),
"pyfcrypto": ("get_version()", "20240114", None, True),
"pyfsapfs": ("get_version()", "20220709", None, True),
"pyfsext": ("get_version()", "20220829", None, True),
"pyfsfat": ("get_version()", "20220925", None, True),
"pyfshfs": ("get_version()", "20220831", None, True),
"pyfsntfs": ("get_version()", "20211229", None, True),
"pyfsxfs": ("get_version()", "20220829", None, True),
"pyfvde": ("get_version()", "20220121", None, True),
"pyfwnt": ("get_version()", "20210717", None, True),
"pyfwsi": ("get_version()", "20240225", None, True),
"pylnk": ("get_version()", "20230716", None, True),
"pyluksde": ("get_version()", "20220121", None, True),
"pymodi": ("get_version()", "20210405", None, True),
"pymsiecf": ("get_version()", "20150314", None, True),
"pyolecf": ("get_version()", "20151223", None, True),
"pyparsing": ("__version__", "3.0.0", None, True),
"pyphdi": ("get_version()", "20220228", None, True),
"pyqcow": ("get_version()", "20201213", None, True),
"pyregf": ("get_version()", "20201002", None, True),
"pyscca": ("get_version()", "20190605", None, True),
"pysigscan": ("get_version()", "20230109", None, True),
"pysmdev": ("get_version()", "20140529", None, True),
"pysmraw": ("get_version()", "20140612", None, True),
"pytsk3": ("get_version()", "20210419", None, True),
"pytz": ("__version__", "", None, True),
"pyvhdi": ("get_version()", "20201014", None, True),
"pyvmdk": ("get_version()", "20140421", None, True),
"pyvsapm": ("get_version()", "20230506", None, True),
"pyvsgpt": ("get_version()", "20211115", None, True),
"pyvshadow": ("get_version()", "20160109", None, True),
"pyvslvm": ("get_version()", "20160109", None, True),
"redis": ("__version__", "3.4", None, False),
"requests": ("__version__", "2.18.0", None, True),
"urllib3": ("__version__", "1.21.1", None, True),
"xattr": ("__version__", "0.7.2", None, False),
"xlsxwriter": ("__version__", "0.9.3", None, True),
"yaml": ("__version__", "3.10", None, True),
"yara": ("YARA_VERSION", "3.4.0", None, True),
"zmq": ("__version__", "2.1.11", None, True),
"zstd": ("version()", "1.3.0.2", None, True),
}
_VERSION_SPLIT_REGEX = re.compile(r"\.|\-")
def _CheckPythonModule(
module_name,
version_attribute_name,
minimum_version,
is_required=True,
maximum_version=None,
verbose_output=True,
):
"""Checks the availability of a Python module.
Args:
module_name (str): name of the module.
version_attribute_name (str): name of the attribute that contains
the module version or method to retrieve the module version.
minimum_version (str): minimum required version.
is_required (Optional[bool]): True if the Python module is a required
dependency.
maximum_version (Optional[str]): maximum required version. Should only be
used if there is a later version that is not supported.
verbose_output (Optional[bool]): True if output should be verbose.
Returns:
bool: True if the Python module is available and conforms to
the minimum required version, False otherwise.
"""
module_object = _ImportPythonModule(module_name)
if not module_object:
if not is_required:
print(f"[OPTIONAL]\tmissing: {module_name:s}.")
return True
print(f"[FAILURE]\tmissing: {module_name:s}.")
return False
if not version_attribute_name or not minimum_version:
if verbose_output:
print(f"[OK]\t\t{module_name:s}")
return True
module_version = None
if not version_attribute_name.endswith("()"):
module_version = getattr(module_object, version_attribute_name, None)
else:
version_method = getattr(module_object, version_attribute_name[:-2], None)
if version_method:
module_version = version_method()
if not module_version:
if not is_required:
print(
f"[OPTIONAL]\tunable to determine version information "
f"for: {module_name:s}"
)
return True
print(
f"[FAILURE]\tunable to determine version information "
f"for: {module_name:s}"
)
return False
# Make sure the module version is a string.
module_version = f"{module_version!s}"
# Remove a version suffix, such as: 0.7.0~rc1
module_version_list = _VERSION_SPLIT_REGEX.split(module_version)
try:
int(module_version_list[-1], 10)
except (TypeError, ValueError):
module_version_list.pop()
# Split the version string and convert every digit into an integer.
# A string compare of both version strings will yield an incorrect result.
module_version_map = list(map(int, module_version_list))
minimum_version_map = list(map(int, _VERSION_SPLIT_REGEX.split(minimum_version)))
if module_version_map < minimum_version_map:
if not is_required:
print(
f"[OPTIONAL]\t{module_name:s} version: {module_version!s} is too "
f"old, {minimum_version!s} or later required."
)
return True
print(
f"[FAILURE]\t{module_name:s} version: {module_version!s} is too old, "
f"{minimum_version!s} or later required."
)
return False
if maximum_version:
maximum_version_map = list(
map(int, _VERSION_SPLIT_REGEX.split(maximum_version))
)
if module_version_map > maximum_version_map:
if not is_required:
print(
f"[OPTIONAL]\t{module_name:s} version: {module_version!s} is too "
f"recent, {minimum_version!s} or earlier required."
)
return True
print(
f"[FAILURE]\t{module_name:s} version: {module_version!s} is too "
f"recent, {maximum_version!s} or earlier required."
)
return False
if verbose_output:
print(f"[OK]\t\t{module_name:s} version: {module_version!s}")
return True
def _ImportPythonModule(module_name):
"""Imports a Python module.
Args:
module_name (str): name of the module.
Returns:
module: Python module or None if the module cannot be imported.
"""
try:
module_object = list(map(__import__, [module_name]))[0]
except ImportError:
return None
# If the module name contains dots get the upper most module object.
if "." in module_name:
for submodule_name in module_name.split(".")[1:]:
module_object = getattr(module_object, submodule_name, None)
return module_object
[docs]
def CheckDependencies(verbose_output=True):
"""Checks the availability of the dependencies.
Args:
verbose_output (Optional[bool]): True if output should be verbose.
Returns:
bool: True if the dependencies are available, False otherwise.
"""
print("Checking availability and versions of dependencies.")
check_result = True
for module_name, version_tuple in sorted(PYTHON_DEPENDENCIES.items()):
if not _CheckPythonModule(
module_name,
version_tuple[0],
version_tuple[1],
is_required=version_tuple[3],
maximum_version=version_tuple[2],
verbose_output=verbose_output,
):
check_result = False
if check_result and not verbose_output:
print("[OK]")
print("")
return check_result