From a3f7774443862b1ee8822778a2f813b90cea24ef Mon Sep 17 00:00:00 2001 From: Mark Harfouche Date: Wed, 13 Mar 2024 13:54:02 -0400 Subject: [PATCH] Make list_chunkmanagers more resilient to broken entrypoints (#8736) * Make list_chunkmanagers more resilient to broken entrypoints As I'm a developing my custom chunk manager, I'm often checking out between my development branch and production branch breaking the entrypoint. This made xarray impossible to import unless I re-ran `pip install -e . -vv` which is somewhat tiring. * Type hint untyped test function to appease mypy * Try to return something to help mypy --------- Co-authored-by: Tom Nicholas Co-authored-by: Illviljan <14371165+Illviljan@users.noreply.github.com> --- xarray/core/utils.py | 4 ++-- xarray/namedarray/parallelcompat.py | 13 ++++++++++--- xarray/tests/test_parallelcompat.py | 12 ++++++++++++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index 9b527622e40..5cb52cbd25c 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -1106,10 +1106,10 @@ def find_stack_level(test_mode=False) -> int: return n -def emit_user_level_warning(message, category=None): +def emit_user_level_warning(message, category=None) -> None: """Emit a warning at the user level by inspecting the stack trace.""" stacklevel = find_stack_level() - warnings.warn(message, category=category, stacklevel=stacklevel) + return warnings.warn(message, category=category, stacklevel=stacklevel) def consolidate_dask_from_array_kwargs( diff --git a/xarray/namedarray/parallelcompat.py b/xarray/namedarray/parallelcompat.py index c6263bff4ff..dd555fe200a 100644 --- a/xarray/namedarray/parallelcompat.py +++ b/xarray/namedarray/parallelcompat.py @@ -15,6 +15,7 @@ import numpy as np +from xarray.core.utils import emit_user_level_warning from xarray.namedarray.pycompat import is_chunked_array if TYPE_CHECKING: @@ -73,9 +74,15 @@ def load_chunkmanagers( ) -> dict[str, ChunkManagerEntrypoint[Any]]: """Load entrypoints and instantiate chunkmanagers only once.""" - loaded_entrypoints = { - entrypoint.name: entrypoint.load() for entrypoint in entrypoints - } + loaded_entrypoints = {} + for entrypoint in entrypoints: + try: + loaded_entrypoints[entrypoint.name] = entrypoint.load() + except ModuleNotFoundError as e: + emit_user_level_warning( + f"Failed to load chunk manager entrypoint {entrypoint.name} due to {e}. Skipping.", + ) + pass available_chunkmanagers = { name: chunkmanager() diff --git a/xarray/tests/test_parallelcompat.py b/xarray/tests/test_parallelcompat.py index d4a4e273bc0..dbe40be710c 100644 --- a/xarray/tests/test_parallelcompat.py +++ b/xarray/tests/test_parallelcompat.py @@ -1,5 +1,6 @@ from __future__ import annotations +from importlib.metadata import EntryPoint from typing import Any import numpy as np @@ -13,6 +14,7 @@ get_chunked_array_type, guess_chunkmanager, list_chunkmanagers, + load_chunkmanagers, ) from xarray.tests import has_dask, requires_dask @@ -218,3 +220,13 @@ def test_raise_on_mixed_array_types(self, register_dummy_chunkmanager) -> None: with pytest.raises(TypeError, match="received multiple types"): get_chunked_array_type(*[dask_arr, dummy_arr]) + + +def test_bogus_entrypoint() -> None: + # Create a bogus entry-point as if the user broke their setup.cfg + # or is actively developing their new chunk manager + entry_point = EntryPoint( + "bogus", "xarray.bogus.doesnotwork", "xarray.chunkmanagers" + ) + with pytest.warns(UserWarning, match="Failed to load chunk manager"): + assert len(load_chunkmanagers([entry_point])) == 0