Skip to content

Commit e9b87f0

Browse files
committed
RF: Drop support for pyzstd - depend on compression.zstd, falling back to
optional backports.zstd. Accept level_or_option parameter, but emit a deprecation warning
1 parent 10aeeb5 commit e9b87f0

File tree

2 files changed

+48
-49
lines changed

2 files changed

+48
-49
lines changed

nibabel/_compression.py

Lines changed: 37 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,22 @@
1515
import io
1616
import typing as ty
1717

18+
try:
19+
from compression import zstd
20+
HAVE_ZSTD = True
21+
except ImportError: # PY313
22+
HAVE_ZSTD = False
23+
24+
from .deprecated import alert_future_error
1825
from .optpkg import optional_package
1926

2027
if ty.TYPE_CHECKING:
21-
import io
2228

2329
import indexed_gzip # type: ignore[import]
2430

25-
# >= py314
26-
try:
27-
from compression import zstd # type: ignore[import]
28-
# < py314
29-
except ImportError:
31+
if not HAVE_ZSTD: # PY313
3032
from backports import zstd # type: ignore[import]
33+
HAVE_ZSTD = True
3134

3235
HAVE_INDEXED_GZIP = True
3336
HAVE_ZSTD = True
@@ -42,8 +45,8 @@
4245

4346
else:
4447
indexed_gzip, HAVE_INDEXED_GZIP, _ = optional_package('indexed_gzip')
45-
zstd, HAVE_ZSTD, _ = optional_package(('compression.zstd',
46-
'backports.zstd', 'pyzstd'))
48+
if not HAVE_ZSTD: # PY313
49+
zstd, HAVE_ZSTD, _ = optional_package('backports.zstd')
4750

4851
# Collections of types for isinstance or exception matching
4952
COMPRESSED_FILE_LIKES: tuple[type[io.IOBase], ...] = (
@@ -151,19 +154,15 @@ def zstd_open(
151154
filename: str,
152155
mode: Mode = 'r',
153156
*,
154-
level_or_option: int | dict | None = None,
155-
zstd_dict: zstd.ZstdDict | None = None,
156157
level : int = None,
157158
options : dict = None,
159+
zstd_dict: zstd.ZstdDict | None = None,
160+
level_or_option: int | dict | None = None
158161
) -> zstd.ZstdFile:
159162
"""Open a zstd file for reading or writing.
160163
161-
The specific object type returned depends on which module out of
162-
``compression.zstd``, ``backports.zstd``, or ``pyzstd`` is available.
163-
164-
At most one of the ``level_or_options``, ``level``, or
165-
``options`` parameters may be provided - a ``ValueError`` will be raised
166-
if more than one is specified.
164+
The specific object returned will be a ``compression.zstd.ZstdFile`` or
165+
a ``backports.zstd.ZstdFile``.
167166
168167
Parameters
169168
----------
@@ -172,34 +171,34 @@ def zstd_open(
172171
Path of file to open.
173172
mode : str
174173
Opening mode.
175-
level_or_option: int or dict
176-
Compression level or dictionary containing options (see also the
177-
level and options parameters).
178174
zstd_dict : ZstdDict
179175
Dictionary used for compression/decompression.
180176
level : int
181177
Compression level when writing.
182178
options : dict
183179
Dictionary of compression/decompression options.
184180
"""
185-
level_or_option_provided = sum((level_or_option is not None,
186-
level is not None,
187-
options is not None))
188-
if level_or_option_provided > 1:
189-
raise ValueError(
190-
'Only one of level_or_option, level, or options may be specified')
191-
# pyzstd accepts level_or_option, but compression.zstd/backports.zstd
192-
# expects level or options
193-
level_or_option_kwarg = {}
194-
if level_or_option_provided == 1:
195-
level_or_option_value = [v for v in [level_or_option, level, options]
196-
if v is not None][0]
197-
if zstd.__name__ == 'pyzstd':
198-
level_or_option_kwarg['level_or_option'] = level_or_option_value
199-
else:
200-
if isinstance(level_or_option_value, int):
201-
level_or_option_kwarg['level'] = level_or_option_value
181+
if level_or_option is not None:
182+
alert_future_error(
183+
'The level_or_option parameter will be removed in a future '
184+
'version of nibabel',
185+
'7.0',
186+
warning_rec='This warning can be silenced by using the separate '
187+
'level/option parameters',
188+
error_rec='Future errors can be avoided by using the separate '
189+
'level/option parameters',
190+
error_class=TypeError)
191+
level_or_option_provided = sum((level_or_option is not None,
192+
level is not None,
193+
options is not None))
194+
if level_or_option_provided > 1:
195+
raise ValueError(
196+
'Only one of level_or_option, level or options may be '
197+
'specified')
198+
if level_or_option is not None:
199+
if isinstance(level_or_option, int):
200+
level = level_or_option
202201
else:
203-
level_or_option_kwarg['options'] = level_or_option_value
202+
options = level_or_option
204203
return zstd.ZstdFile(
205-
filename, mode, zstd_dict=zstd_dict, **level_or_option_kwarg)
204+
filename, mode, level=level, options=options, zstd_dict=zstd_dict)

nibabel/openers.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,7 @@ class Opener:
6262

6363
gz_def = (gzip_open, ('mode', 'compresslevel', 'mtime', 'keep_open'))
6464
bz2_def = (BZ2File, ('mode', 'buffering', 'compresslevel'))
65-
zstd_def = (zstd_open, ('mode', 'level_or_option', 'zstd_dict', 'level',
66-
'option'))
65+
zstd_def = (zstd_open, ('mode', 'level', 'option', 'zstd_dict'))
6766
compress_ext_map: dict[str | None, OpenerDef] = {
6867
'.gz': gz_def,
6968
'.bz2': bz2_def,
@@ -72,13 +71,12 @@ class Opener:
7271
}
7372
#: default compression level when writing gz and bz2 files
7473
default_compresslevel = 1
75-
#: default option for zst files
76-
default_zst_compresslevel = 3
77-
default_level_or_option = {
74+
#: default compression level for zst files
75+
default_zst_level = {
7876
'rb': None,
7977
'r': None,
80-
'wb': default_zst_compresslevel,
81-
'w': default_zst_compresslevel,
78+
'wb': 3,
79+
'w': 3,
8280
}
8381
#: whether to ignore case looking for compression extensions
8482
compress_ext_icase: bool = True
@@ -92,19 +90,21 @@ def __init__(self, fileish: str | io.IOBase, *args, **kwargs):
9290
self._name = getattr(fileish, 'name', None)
9391
return
9492
opener, arg_names = self._get_opener_argnames(fileish)
95-
# Get full arguments to check for mode and compresslevel
93+
# Get full arguments to check for optional parameters
9694
full_kwargs = {**kwargs, **dict(zip(arg_names, args))}
9795
# Set default mode
9896
if 'mode' not in full_kwargs:
9997
mode = 'rb'
10098
kwargs['mode'] = mode
10199
else:
102100
mode = full_kwargs['mode']
103-
# Default compression level
101+
# Default gz/bz2 compression level
104102
if 'compresslevel' in arg_names and 'compresslevel' not in kwargs:
105103
kwargs['compresslevel'] = self.default_compresslevel
106-
if 'level_or_option' in arg_names and 'level_or_option' not in kwargs:
107-
kwargs['level_or_option'] = self.default_level_or_option[mode]
104+
# Default zstd compression level
105+
if ('level' in arg_names and 'level' not in kwargs and
106+
'option' not in kwargs):
107+
kwargs['level'] = self.default_zst_level[mode]
108108
# Default keep_open hint
109109
if 'keep_open' in arg_names:
110110
kwargs.setdefault('keep_open', False)

0 commit comments

Comments
 (0)