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 re | ||||||
| import sys | import sys | ||||||
| import traceback | import traceback | ||||||
| import warnings |  | ||||||
| from datetime import datetime, timedelta | from datetime import datetime, timedelta | ||||||
| from typing import Any, Callable, Iterable, List, Tuple | from typing import Any, Callable, Iterable, List, Tuple | ||||||
| 
 | 
 | ||||||
| @@ -847,43 +846,25 @@ def __repr__(self): | |||||||
| def get_entry_points(*, group: str): | def get_entry_points(*, group: str): | ||||||
|     """Wrapper for ``importlib.metadata.entry_points`` |     """Wrapper for ``importlib.metadata.entry_points`` | ||||||
| 
 | 
 | ||||||
|     Adapted from https://github.com/HypothesisWorks/hypothesis/blob/0a90ed6edf56319149956c7321d4110078a5c228/hypothesis-python/src/hypothesis/entry_points.py |  | ||||||
| 
 |  | ||||||
|     Args: |     Args: | ||||||
|         group (str): the group of entry points to select |         group: entry points to select | ||||||
| 
 | 
 | ||||||
|     Returns: |     Returns: | ||||||
|         EntryPoints for ``group`` |         EntryPoints for ``group`` or empty list if unsupported | ||||||
| 
 |  | ||||||
|     """ |     """ | ||||||
| 
 | 
 | ||||||
|     try: |     try: | ||||||
|         try: |         import importlib.metadata  # type: ignore  # novermin | ||||||
|             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 |  | ||||||
|     except ImportError: |     except ImportError: | ||||||
|         # But if we're not on Python >= 3.8 and the importlib_metadata backport |         return [] | ||||||
|         # is not installed, we fall back to pkg_resources anyway. | 
 | ||||||
|         try: |     try: | ||||||
|             import pkg_resources  # type: ignore |         return importlib.metadata.entry_points(group=group) | ||||||
|         except ImportError: |     except TypeError: | ||||||
|             warnings.warn( |         # Prior to Python 3.10, entry_points accepted no parameters and always | ||||||
|                 "Under Python <= 3.7, Spack requires either the importlib_metadata " |         # returned a dictionary of entry points, keyed by group.  See | ||||||
|                 "or setuptools package in order to load extensions via entrypoints.", |         # https://docs.python.org/3/library/importlib.metadata.html#entry-points | ||||||
|                 ImportWarning, |         return importlib.metadata.entry_points().get(group, []) | ||||||
|             ) |  | ||||||
|             yield from () |  | ||||||
|         else: |  | ||||||
|             yield from pkg_resources.iter_entry_points(group) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def load_module_from_file(module_name, module_path): | def load_module_from_file(module_name, module_path): | ||||||
|   | |||||||
| @@ -8,6 +8,8 @@ | |||||||
| 
 | 
 | ||||||
| import pytest | import pytest | ||||||
| 
 | 
 | ||||||
|  | import llnl.util.lang | ||||||
|  | 
 | ||||||
| import spack.config | import spack.config | ||||||
| import spack.extensions | import spack.extensions | ||||||
| 
 | 
 | ||||||
| @@ -64,24 +66,12 @@ def entry_points(group=None): | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @pytest.fixture() | @pytest.fixture() | ||||||
| def mock_entry_points(tmp_path, monkeypatch): | def mock_get_entry_points(tmp_path, monkeypatch): | ||||||
|     entry_points = entry_points_factory(tmp_path) |     entry_points = entry_points_factory(tmp_path) | ||||||
|     try: |     monkeypatch.setattr(llnl.util.lang, "get_entry_points", entry_points) | ||||||
|         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) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @pytest.mark.skipif(sys.version_info[:2] < (3, 8), reason="Python>=3.8 required") | def test_spack_entry_point_config(tmp_path, mock_get_entry_points): | ||||||
| def test_spack_entry_point_config(tmp_path, mock_entry_points): |  | ||||||
|     """Test config scope entry point""" |     """Test config scope entry point""" | ||||||
|     config_paths = dict(spack.config.config_paths_from_entry_points()) |     config_paths = dict(spack.config.config_paths_from_entry_points()) | ||||||
|     config_path = config_paths.get("plugin-mypackage_config") |     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" |     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_get_entry_points): | ||||||
| def test_spack_entry_point_extension(tmp_path, mock_entry_points): |  | ||||||
|     """Test config scope entry point""" |     """Test config scope entry point""" | ||||||
|     my_ext = tmp_path / "spack/spack-myext" |     my_ext = tmp_path / "spack/spack-myext" | ||||||
|     extensions = spack.extensions.get_extension_paths() |     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) |     assert os.path.samefile(root, my_ext) | ||||||
|     module = spack.extensions.get_module("spam") |     module = spack.extensions.get_module("spam") | ||||||
|     assert module is not None |     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
	 Tim Fuller
					Tim Fuller