Skip to content

Commit 204a48c

Browse files
committed
ENH: Add ability for compression to be set explicitly in ImageOpener/ArrayProxy
1 parent 4703f4d commit 204a48c

File tree

2 files changed

+22
-9
lines changed

2 files changed

+22
-9
lines changed

nibabel/arrayproxy.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ class ArrayProxy(object):
8686
# Assume Fortran array memory layout
8787
order = 'F'
8888

89-
def __init__(self, file_like, spec, *, mmap=True, keep_file_open=None):
89+
def __init__(self, file_like, spec, *,
90+
mmap=True, keep_file_open=None, compression=None):
9091
"""Initialize array proxy instance
9192
9293
Parameters
@@ -125,6 +126,7 @@ def __init__(self, file_like, spec, *, mmap=True, keep_file_open=None):
125126
If ``file_like`` is an open file handle, this setting has no
126127
effect. The default value (``None``) will result in the value of
127128
``KEEP_FILE_OPEN_DEFAULT`` being used.
129+
compression : { None, "gz", "bz2", "zst" }, optional, keyworld only
128130
"""
129131
if mmap not in (True, False, 'c', 'r'):
130132
raise ValueError("mmap should be one of {True, False, 'c', 'r'}")
@@ -147,10 +149,11 @@ def __init__(self, file_like, spec, *, mmap=True, keep_file_open=None):
147149
# Permit any specifier that can be interpreted as a numpy dtype
148150
self._dtype = np.dtype(self._dtype)
149151
self._mmap = mmap
152+
self._compression = compression
150153
# Flags to keep track of whether a single ImageOpener is created, and
151154
# whether a single underlying file handle is created.
152155
self._keep_file_open, self._persist_opener = \
153-
self._should_keep_file_open(file_like, keep_file_open)
156+
self._should_keep_file_open(file_like, keep_file_open, compression)
154157
self._lock = RLock()
155158

156159
def __del__(self):
@@ -172,7 +175,7 @@ def __setstate__(self, state):
172175
self.__dict__.update(state)
173176
self._lock = RLock()
174177

175-
def _should_keep_file_open(self, file_like, keep_file_open):
178+
def _should_keep_file_open(self, file_like, keep_file_open, compression):
176179
"""Called by ``__init__``.
177180
178181
This method determines how to manage ``ImageOpener`` instances,
@@ -248,7 +251,8 @@ def _should_keep_file_open(self, file_like, keep_file_open):
248251
if hasattr(file_like, 'read') and hasattr(file_like, 'seek'):
249252
return False, False
250253
# if the file is a gzip file, and we have_indexed_gzip,
251-
have_igzip = openers.HAVE_INDEXED_GZIP and file_like.endswith('.gz')
254+
have_igzip = openers.HAVE_INDEXED_GZIP and (compression in ("gz", ".gz") or
255+
file_like.endswith('.gz'))
252256

253257
persist_opener = keep_file_open or have_igzip
254258
return keep_file_open, persist_opener
@@ -297,11 +301,15 @@ def _get_fileobj(self):
297301
if self._persist_opener:
298302
if not hasattr(self, '_opener'):
299303
self._opener = openers.ImageOpener(
300-
self.file_like, keep_open=self._keep_file_open)
304+
self.file_like,
305+
keep_open=self._keep_file_open,
306+
compression=self._compression)
301307
yield self._opener
302308
else:
303309
with openers.ImageOpener(
304-
self.file_like, keep_open=False) as opener:
310+
self.file_like,
311+
keep_open=False,
312+
compression=self._compression) as opener:
305313
yield opener
306314

307315
def _get_unscaled(self, slicer):

nibabel/openers.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ class Opener(object):
9696
specified, is `rb`. ``compresslevel``, if relevant, and not specified,
9797
is set from class variable ``default_compresslevel``. ``keep_open``, if
9898
relevant, and not specified, is ``False``.
99+
compression : { None, "gz", "bz2", "zst" }, optional, keyworld only
99100
\*\*kwargs : keyword arguments
100101
passed to opening method when `fileish` is str. Change of defaults as
101102
for \*args
@@ -119,13 +120,13 @@ class Opener(object):
119120
#: whether to ignore case looking for compression extensions
120121
compress_ext_icase = True
121122

122-
def __init__(self, fileish, *args, **kwargs):
123+
def __init__(self, fileish, *args, compression=None, **kwargs):
123124
if self._is_fileobj(fileish):
124125
self.fobj = fileish
125126
self.me_opened = False
126127
self._name = None
127128
return
128-
opener, arg_names = self._get_opener_argnames(fileish)
129+
opener, arg_names = self._get_opener_argnames(fileish, compression)
129130
# Get full arguments to check for mode and compresslevel
130131
full_kwargs = kwargs.copy()
131132
n_args = len(args)
@@ -151,7 +152,11 @@ def __init__(self, fileish, *args, **kwargs):
151152
self._name = fileish
152153
self.me_opened = True
153154

154-
def _get_opener_argnames(self, fileish):
155+
def _get_opener_argnames(self, fileish, compression):
156+
if compression is not None:
157+
if compression[0] != '.':
158+
compression = f'.{compression}'
159+
return self.compress_ext_map[compression]
155160
_, ext = splitext(fileish)
156161
if self.compress_ext_icase:
157162
ext = ext.lower()

0 commit comments

Comments
 (0)