Drop optional dependencies of Spack (#43081)
Remove dependency on `importlib_metadata` and `pkg_resources`, which can be problematic if the version in PYTHONPATH is incompatible with the interpreter Spack is running under.
This commit is contained in:
		@@ -12,7 +12,6 @@
 | 
			
		||||
import re
 | 
			
		||||
import sys
 | 
			
		||||
import traceback
 | 
			
		||||
import warnings
 | 
			
		||||
from datetime import datetime, timedelta
 | 
			
		||||
from typing import Any, Callable, Iterable, List, Tuple
 | 
			
		||||
 | 
			
		||||
@@ -847,43 +846,25 @@ def __repr__(self):
 | 
			
		||||
def get_entry_points(*, group: str):
 | 
			
		||||
    """Wrapper for ``importlib.metadata.entry_points``
 | 
			
		||||
 | 
			
		||||
    Adapted from https://github.com/HypothesisWorks/hypothesis/blob/0a90ed6edf56319149956c7321d4110078a5c228/hypothesis-python/src/hypothesis/entry_points.py
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        group (str): the group of entry points to select
 | 
			
		||||
        group: entry points to select
 | 
			
		||||
 | 
			
		||||
    Returns:
 | 
			
		||||
        EntryPoints for ``group``
 | 
			
		||||
 | 
			
		||||
        EntryPoints for ``group`` or empty list if unsupported
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        try:
 | 
			
		||||
            from importlib import metadata as importlib_metadata  # type: ignore  # novermin
 | 
			
		||||
        except ImportError:
 | 
			
		||||
            import importlib_metadata  # type: ignore  # mypy thinks this is a redefinition
 | 
			
		||||
        try:
 | 
			
		||||
            entry_points = importlib_metadata.entry_points(group=group)
 | 
			
		||||
        except TypeError:
 | 
			
		||||
            # Prior to Python 3.10, entry_points accepted no parameters and always
 | 
			
		||||
            # returned a dictionary of entry points, keyed by group.  See
 | 
			
		||||
            # https://docs.python.org/3/library/importlib.metadata.html#entry-points
 | 
			
		||||
            entry_points = importlib_metadata.entry_points().get(group, [])
 | 
			
		||||
        yield from entry_points
 | 
			
		||||
        import importlib.metadata  # type: ignore  # novermin
 | 
			
		||||
    except ImportError:
 | 
			
		||||
        # But if we're not on Python >= 3.8 and the importlib_metadata backport
 | 
			
		||||
        # is not installed, we fall back to pkg_resources anyway.
 | 
			
		||||
        try:
 | 
			
		||||
            import pkg_resources  # type: ignore
 | 
			
		||||
        except ImportError:
 | 
			
		||||
            warnings.warn(
 | 
			
		||||
                "Under Python <= 3.7, Spack requires either the importlib_metadata "
 | 
			
		||||
                "or setuptools package in order to load extensions via entrypoints.",
 | 
			
		||||
                ImportWarning,
 | 
			
		||||
            )
 | 
			
		||||
            yield from ()
 | 
			
		||||
        else:
 | 
			
		||||
            yield from pkg_resources.iter_entry_points(group)
 | 
			
		||||
        return []
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        return importlib.metadata.entry_points(group=group)
 | 
			
		||||
    except TypeError:
 | 
			
		||||
        # Prior to Python 3.10, entry_points accepted no parameters and always
 | 
			
		||||
        # returned a dictionary of entry points, keyed by group.  See
 | 
			
		||||
        # https://docs.python.org/3/library/importlib.metadata.html#entry-points
 | 
			
		||||
        return importlib.metadata.entry_points().get(group, [])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def load_module_from_file(module_name, module_path):
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,8 @@
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
 | 
			
		||||
import llnl.util.lang
 | 
			
		||||
 | 
			
		||||
import spack.config
 | 
			
		||||
import spack.extensions
 | 
			
		||||
 | 
			
		||||
@@ -64,24 +66,12 @@ def entry_points(group=None):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture()
 | 
			
		||||
def mock_entry_points(tmp_path, monkeypatch):
 | 
			
		||||
def mock_get_entry_points(tmp_path, monkeypatch):
 | 
			
		||||
    entry_points = entry_points_factory(tmp_path)
 | 
			
		||||
    try:
 | 
			
		||||
        try:
 | 
			
		||||
            import importlib.metadata as importlib_metadata  # type: ignore # novermin
 | 
			
		||||
        except ImportError:
 | 
			
		||||
            import importlib_metadata
 | 
			
		||||
        monkeypatch.setattr(importlib_metadata, "entry_points", entry_points)
 | 
			
		||||
    except ImportError:
 | 
			
		||||
        try:
 | 
			
		||||
            import pkg_resources  # type: ignore
 | 
			
		||||
        except ImportError:
 | 
			
		||||
            return
 | 
			
		||||
        monkeypatch.setattr(pkg_resources, "iter_entry_points", entry_points)
 | 
			
		||||
    monkeypatch.setattr(llnl.util.lang, "get_entry_points", entry_points)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.skipif(sys.version_info[:2] < (3, 8), reason="Python>=3.8 required")
 | 
			
		||||
def test_spack_entry_point_config(tmp_path, mock_entry_points):
 | 
			
		||||
def test_spack_entry_point_config(tmp_path, mock_get_entry_points):
 | 
			
		||||
    """Test config scope entry point"""
 | 
			
		||||
    config_paths = dict(spack.config.config_paths_from_entry_points())
 | 
			
		||||
    config_path = config_paths.get("plugin-mypackage_config")
 | 
			
		||||
@@ -94,8 +84,7 @@ def test_spack_entry_point_config(tmp_path, mock_entry_points):
 | 
			
		||||
    assert config.get("config:install_tree:root", scope="plugin-mypackage_config") == "/spam/opt"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.skipif(sys.version_info[:2] < (3, 8), reason="Python>=3.8 required")
 | 
			
		||||
def test_spack_entry_point_extension(tmp_path, mock_entry_points):
 | 
			
		||||
def test_spack_entry_point_extension(tmp_path, mock_get_entry_points):
 | 
			
		||||
    """Test config scope entry point"""
 | 
			
		||||
    my_ext = tmp_path / "spack/spack-myext"
 | 
			
		||||
    extensions = spack.extensions.get_extension_paths()
 | 
			
		||||
@@ -110,3 +99,16 @@ def test_spack_entry_point_extension(tmp_path, mock_entry_points):
 | 
			
		||||
    assert os.path.samefile(root, my_ext)
 | 
			
		||||
    module = spack.extensions.get_module("spam")
 | 
			
		||||
    assert module is not None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.skipif(sys.version_info[:2] < (3, 8), reason="Python>=3.8 required")
 | 
			
		||||
def test_llnl_util_lang_get_entry_points(tmp_path, monkeypatch):
 | 
			
		||||
    import importlib.metadata  # type: ignore # novermin
 | 
			
		||||
 | 
			
		||||
    monkeypatch.setattr(importlib.metadata, "entry_points", entry_points_factory(tmp_path))
 | 
			
		||||
 | 
			
		||||
    entry_points = list(llnl.util.lang.get_entry_points(group="spack.config"))
 | 
			
		||||
    assert isinstance(entry_points[0], MockConfigEntryPoint)
 | 
			
		||||
 | 
			
		||||
    entry_points = list(llnl.util.lang.get_entry_points(group="spack.extensions"))
 | 
			
		||||
    assert isinstance(entry_points[0], MockExtensionsEntryPoint)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user