diff --git a/requirements.txt b/requirements.txt index 319160fc76..3392d79445 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,6 +5,9 @@ setuptools>=21 # The setuptools package is required to install source distributions and on some systems is not installed by default. # Please keep it as the first item of this list. Version 21 is required to handle PEP 508 environment markers. # +# importlib_metadata: is part of python3.8 and newer as importlib.metadata +importlib_metadata; python_version < "3.8" +packaging click>=7.0 pyserial>=3.0 future>=0.15.2 diff --git a/tools/check_python_dependencies.py b/tools/check_python_dependencies.py index ea7f2088b8..28a4280fe1 100755 --- a/tools/check_python_dependencies.py +++ b/tools/check_python_dependencies.py @@ -20,13 +20,21 @@ import re import sys try: - import pkg_resources -except Exception: - print('pkg_resources cannot be imported probably because the pip package is not installed and/or using a ' - 'legacy Python interpreter. Please refer to the Get Started section of the ESP-IDF Programming Guide for ' - 'setting up the required packages.') + from packaging.requirements import Requirement + from packaging.version import Version +except ImportError: + print('packaging cannot be imported. ' + 'If you\'ve installed a custom Python then this package is provided separately and have to be installed as well. ' + 'Please refer to the Get Started section of the ESP-IDF Programming Guide for setting up the required packages.') sys.exit(1) +try: + from importlib.metadata import requires + from importlib.metadata import version as get_version +except ImportError: + from importlib_metadata import requires # type: ignore + from importlib_metadata import version as get_version # type: ignore + def escape_backslash(path): if sys.platform == 'win32': @@ -46,19 +54,40 @@ if __name__ == '__main__': help='Path to the requirements file', default=default_requirements_path) args = parser.parse_args() - not_satisfied = [] + + def version_check(requirement): # type(Requirement) -> None + # compare installed version with required + version = Version(get_version(requirement.name)) + if version.base_version not in requirement.specifier: + not_satisfied.append("Requirement '{}' was not met. Installed version: {}".format(requirement, version)) + with open(args.requirements) as f: for line in f: line = line.strip() - # pkg_resources.require() cannot handle the full requirements file syntax so we need to make + # requires() cannot handle the full requirements file syntax so we need to make # adjustments for options which we use. if line.startswith('file://'): line = os.path.basename(line) + if line.startswith('--only-binary') or line.startswith('#') or len(line) == 0: + continue if line.startswith('-e') and '#egg=' in line: # version control URLs, take the egg= part at the end only - line = re.search(r'#egg=([^\s]+)', line).group(1) + line = re.search(r'#egg=([^\s]+)', line).group(1) # type: ignore + # remove comments + line = line.partition(' #')[0] try: - pkg_resources.require(line) + requirement = Requirement(line) + extras = requirement.extras + if requirement.marker and not requirement.marker.evaluate(): + continue + version_check(requirement) + for name in requires(requirement.name) or []: + sub_req = Requirement(name) + # check extras e.g. esptool[hsm] + for extra in extras: + # evaluate markers if present + if not sub_req.marker or sub_req.marker.evaluate(environment={'extra': extra}): + version_check(sub_req) except Exception: not_satisfied.append(line)