diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 877f823c..59dfcc38 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -10,6 +10,7 @@ jobs: uses: neongeckocom/.github/.github/workflows/python_build_tests.yml@master skill_object_tests: strategy: + max-parallel: 2 matrix: python-version: [ 3.9, '3.10', '3.11', '3.12' ] runs-on: ubuntu-latest diff --git a/neon_utils/packaging_utils.py b/neon_utils/packaging_utils.py index a8d7ea42..cde4d034 100644 --- a/neon_utils/packaging_utils.py +++ b/neon_utils/packaging_utils.py @@ -33,7 +33,6 @@ from typing import Tuple, Optional, List from tempfile import mkstemp -import pkg_resources import sysconfig from os.path import exists, join, isfile @@ -63,13 +62,16 @@ def get_package_version_spec(pkg: str): """ Locate an installed package and return its reported version :param pkg: string package name to locate - :returns: Version string as reported by pkg_resources - :raises: ModuleNotFoundError if requested package isn't installed + :returns: Version string as reported by importlib.metadata + :raises: PackageNotFoundError if requested package isn't installed """ try: - return pkg_resources.get_distribution(pkg).version - except pkg_resources.DistributionNotFound: - raise ModuleNotFoundError(f"{pkg} not found") + from importlib.metadata import version + except ImportError: + # Fallback for Python < 3.8 + from importlib_metadata import version + + return version(pkg) def get_package_dependencies(pkg: str): @@ -77,15 +79,20 @@ def get_package_dependencies(pkg: str): Get the dependencies for an installed package :param pkg: string package name to evaluate :returns: list of string dependencies (equivalent to requirements.txt) - :raises ModuleNotFoundError if requested package isn't installed + :raises PackageNotFoundError if requested package isn't installed """ try: - constraints = pkg_resources.working_set.by_key[pkg].requires() - constraints_spec = [str(c).split('[', 1)[0] for c in constraints] - LOG.debug(constraints_spec) - return constraints_spec - except KeyError: - raise ModuleNotFoundError(f"{pkg} not found") + from importlib.metadata import requires + except ImportError: + # Fallback for Python < 3.8 + from importlib_metadata import requires + + requirements = requires(pkg) + if requirements is None: + return [] + constraints_spec = [req.split('[', 1)[0].split(';', 1)[0] for req in requirements] + LOG.debug(constraints_spec) + return constraints_spec @deprecated("Reference `neon_core.version.__version__` directly", "2.0.0") diff --git a/tests/packaging_util_tests.py b/tests/packaging_util_tests.py index 8a8c2077..6a7e67a5 100644 --- a/tests/packaging_util_tests.py +++ b/tests/packaging_util_tests.py @@ -114,13 +114,18 @@ def test_get_packaged_core_version(self): def test_get_package_dependencies(self): self_deps = get_package_dependencies("neon-utils") - requirements_file = join(os.path.dirname(os.path.dirname(__file__)), - "requirements", "requirements.txt") - with open(requirements_file) as f: - spec_requirements = f.read().split('\n') + requirements_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), "requirements") + spec_requirements = [] + for _, _, files in os.walk(requirements_dir): + for file in files: + with open(os.path.join(requirements_dir, file)) as f: + spec_requirements += f.read().split('\n') + spec_requirements = [r for r in spec_requirements if r and not r.startswith('#')] + # Version specs aren't order-dependent, so they can't be compared + # Also, constraints are normalized so elements cannot be compared self.assertEqual(len(self_deps), len(spec_requirements)) with self.assertRaises(ModuleNotFoundError): get_package_dependencies("fakeneongeckopackage")