diff --git a/virtualizarr/readers/hdf/filters.py b/virtualizarr/readers/hdf/filters.py index 1fb2cc30..ed459ab4 100644 --- a/virtualizarr/readers/hdf/filters.py +++ b/virtualizarr/readers/hdf/filters.py @@ -1,24 +1,18 @@ import dataclasses -import warnings from typing import List, Tuple, TypedDict, Union -import h5py # type: ignore import numcodecs.registry as registry import numpy as np from numcodecs.abc import Codec from numcodecs.fixedscaleoffset import FixedScaleOffset from xarray.coding.variables import _choose_float_dtype -try: - import hdf5plugin # type: ignore -except ModuleNotFoundError: - hdf5plugin = None # type: ignore - warnings.warn("hdf5plugin is required for HDF reader") +from virtualizarr.utils import soft_import + +h5py = soft_import("h5py", "For reading hdf files") +hdf5plugin = soft_import("hdf5plugin", "For reading hdf files with filters") +imagecodecs = soft_import("imagecodecs", "For reading hdf files with filters") -try: - import imagecodecs # noqa -except ModuleNotFoundError: - warnings.warn("imagecodecs is required for HDF reader") _non_standard_filters = { "gzip": "zlib", diff --git a/virtualizarr/readers/hdf/hdf.py b/virtualizarr/readers/hdf/hdf.py index dc9b888d..df354f1c 100644 --- a/virtualizarr/readers/hdf/hdf.py +++ b/virtualizarr/readers/hdf/hdf.py @@ -1,7 +1,6 @@ import math from typing import Dict, Iterable, List, Mapping, Optional, Union -import h5py # type: ignore import numpy as np from xarray import Dataset, Index, Variable @@ -13,9 +12,11 @@ ) from virtualizarr.readers.hdf.filters import cfcodec_from_dataset, codecs_from_dataset from virtualizarr.types import ChunkKey -from virtualizarr.utils import _FsspecFSFromFilepath, check_for_collisions +from virtualizarr.utils import _FsspecFSFromFilepath, check_for_collisions, soft_import from virtualizarr.zarr import ZArray +h5py = soft_import("h5py", "For reading hdf files") + class HDFVirtualBackend(VirtualBackend): @staticmethod diff --git a/virtualizarr/utils.py b/virtualizarr/utils.py index c9260aa6..b5ae3447 100644 --- a/virtualizarr/utils.py +++ b/virtualizarr/utils.py @@ -1,5 +1,6 @@ from __future__ import annotations +import importlib import io from typing import TYPE_CHECKING, Iterable, Optional, Union @@ -86,3 +87,16 @@ def check_for_collisions( raise ValueError(f"Cannot both load and drop variables {common}") return drop_variables, loadable_variables + + +def soft_import(name: str, reason: str, strict: Optional[bool] = True): + try: + return importlib.import_module(name) + except (ImportError, ModuleNotFoundError): + if strict: + raise ImportError( + f"for {reason}, the {name} package is required. " + f"Please install it via pip or conda." + ) + else: + return None