Skip to content

Commit

Permalink
Error at runtime if zfpy isn't present
Browse files Browse the repository at this point in the history
  • Loading branch information
dstansby committed Dec 3, 2024
1 parent 9bdbaf0 commit 57cddff
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 105 deletions.
5 changes: 2 additions & 3 deletions numcodecs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,9 @@
register_codec(Fletcher32)

# Optional depenedencies
with suppress(ImportError):
from numcodecs.zfpy import ZFPY
from numcodecs.zfpy import ZFPY

register_codec(ZFPY)
register_codec(ZFPY)

with suppress(ImportError):
from numcodecs.msgpacks import MsgPack
Expand Down
204 changes: 102 additions & 102 deletions numcodecs/zfpy.py
Original file line number Diff line number Diff line change
@@ -1,113 +1,113 @@
import warnings
from contextlib import suppress
from importlib.metadata import PackageNotFoundError, version
import importlib.util
from importlib.metadata import version
from types import ModuleType
from typing import Optional

_zfpy: Optional[ModuleType] = None
import numpy as np

_zfpy_version: tuple = ()
with suppress(PackageNotFoundError):
_zfpy_version = tuple(map(int, version("zfpy").split(".")))
from .abc import Codec
from .compat import ensure_bytes, ensure_contiguous_ndarray, ndarray_copy

_zfpy: Optional[ModuleType]
_zfpy_spec = importlib.util.find_spec("zfpy")

if _zfpy_spec is None:
_zfpy = None

Check warning on line 15 in numcodecs/zfpy.py

View check run for this annotation

Codecov / codecov/patch

numcodecs/zfpy.py#L15

Added line #L15 was not covered by tests
else:
import zfpy as _zfpy # type: ignore[no-redef]

if _zfpy_version:
# Check NumPy version
_numpy_version: tuple = tuple(map(int, version("numpy").split('.')))

def _check_compatible_numpy() -> None:
_numpy_version = tuple(map(int, version("numpy").split('.')))
_zfpy_version = tuple(map(int, version("zfpy").split(".")))
if _numpy_version >= (2, 0, 0) and _zfpy_version <= (1, 0, 1): # pragma: no cover
_zfpy_version = ()
warnings.warn(
raise RuntimeError(
"NumPy version >= 2.0.0 detected. The zfpy library is incompatible with this version of NumPy. "
"Please downgrade to NumPy < 2.0.0 or wait for an update from zfpy.",
UserWarning,
stacklevel=2,
)
else:
with suppress(ImportError):
import zfpy as _zfpy # type: ignore[no-redef]

if _zfpy:
import numpy as np

from .abc import Codec
from .compat import ensure_bytes, ensure_contiguous_ndarray, ndarray_copy

# noinspection PyShadowingBuiltins
class ZFPY(Codec):
"""Codec providing compression using zfpy via the Python standard
library.
Parameters
----------
mode : integer
One of the zfpy mode choice, e.g., ``zfpy.mode_fixed_accuracy``.
tolerance : double, optional
A double-precision number, specifying the compression accuracy needed.
rate : double, optional
A double-precision number, specifying the compression rate needed.
precision : int, optional
A integer number, specifying the compression precision needed.
"""

codec_id = "zfpy"

def __init__(
self,
mode=_zfpy.mode_fixed_accuracy,
tolerance=-1,
rate=-1,
precision=-1,
compression_kwargs=None,
):
self.mode = mode
if mode == _zfpy.mode_fixed_accuracy:
self.compression_kwargs = {"tolerance": tolerance}
elif mode == _zfpy.mode_fixed_rate:
self.compression_kwargs = {"rate": rate}
elif mode == _zfpy.mode_fixed_precision:
self.compression_kwargs = {"precision": precision}

self.tolerance = tolerance
self.rate = rate
self.precision = precision

def encode(self, buf):
# not flatten c-order array and raise exception for f-order array
if not isinstance(buf, np.ndarray):
raise TypeError(
"The zfp codec does not support none numpy arrays."
f" Your buffers were {type(buf)}."
)
if buf.flags.c_contiguous:
flatten = False
else:
raise ValueError(
"The zfp codec does not support F order arrays. "
f"Your arrays flags were {buf.flags}."
)
buf = ensure_contiguous_ndarray(buf, flatten=flatten)

# do compression
return _zfpy.compress_numpy(buf, write_header=True, **self.compression_kwargs)

def decode(self, buf, out=None):
# normalise inputs
buf = ensure_bytes(buf)
if out is not None:
out = ensure_contiguous_ndarray(out)

# do decompression
dec = _zfpy.decompress_numpy(buf)

# handle destination
if out is not None:
return ndarray_copy(dec, out)
else:
return dec

def __repr__(self):
return (
f"{type(self).__name__}(mode={self.mode!r}, "
f"tolerance={self.tolerance}, rate={self.rate}, "
f"precision={self.precision})"


class ZFPY(Codec):
"""Codec providing compression using zfpy via the Python standard
library.
Parameters
----------
mode : integer
One of the zfpy mode choice, e.g., ``zfpy.mode_fixed_accuracy``.
tolerance : double, optional
A double-precision number, specifying the compression accuracy needed.
rate : double, optional
A double-precision number, specifying the compression rate needed.
precision : int, optional
A integer number, specifying the compression precision needed.
"""

codec_id = "zfpy"

def __init__(
self,
mode=_zfpy.mode_fixed_accuracy,
tolerance=-1,
rate=-1,
precision=-1,
compression_kwargs=None,
):
if _zfpy is None:
raise RuntimeError("The ZFPY codec requires the 'zfpy' package to be installed.")

Check warning on line 59 in numcodecs/zfpy.py

View check run for this annotation

Codecov / codecov/patch

numcodecs/zfpy.py#L59

Added line #L59 was not covered by tests
_check_compatible_numpy()

self.mode = mode
if mode == _zfpy.mode_fixed_accuracy:
self.compression_kwargs = {"tolerance": tolerance}
elif mode == _zfpy.mode_fixed_rate:
self.compression_kwargs = {"rate": rate}
elif mode == _zfpy.mode_fixed_precision:
self.compression_kwargs = {"precision": precision}

self.tolerance = tolerance
self.rate = rate
self.precision = precision

def encode(self, buf):
# not flatten c-order array and raise exception for f-order array
if not isinstance(buf, np.ndarray):
raise TypeError(
"The zfp codec does not support none numpy arrays."
f" Your buffers were {type(buf)}."
)
if buf.flags.c_contiguous:
flatten = False
else:
raise ValueError(
"The zfp codec does not support F order arrays. "
f"Your arrays flags were {buf.flags}."
)
buf = ensure_contiguous_ndarray(buf, flatten=flatten)

# do compression
return _zfpy.compress_numpy(buf, write_header=True, **self.compression_kwargs)

def decode(self, buf, out=None):
# normalise inputs
buf = ensure_bytes(buf)
if out is not None:
out = ensure_contiguous_ndarray(out)

# do decompression
dec = _zfpy.decompress_numpy(buf)

# handle destination
if out is not None:
return ndarray_copy(dec, out)
else:
return dec

def __repr__(self):
return (
f"{type(self).__name__}(mode={self.mode!r}, "
f"tolerance={self.tolerance}, rate={self.rate}, "
f"precision={self.precision})"
)

0 comments on commit 57cddff

Please sign in to comment.