Skip to content

Commit a8e5b82

Browse files
committed
NF: add "caching" flag to get_data
Caching flag can take values 'fill' and 'unchanged'.
1 parent 932f237 commit a8e5b82

File tree

2 files changed

+62
-19
lines changed

2 files changed

+62
-19
lines changed

nibabel/spatialimages.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -448,21 +448,39 @@ def __str__(self):
448448
'metadata:',
449449
'%s' % self._header))
450450

451-
def get_data(self):
451+
def get_data(self, caching='fill'):
452452
""" Return image data from image with any necessary scalng applied
453453
454454
If the image data is a array proxy (data not yet read from disk) then
455-
read the data, and store in an internal cache. Future calls to
456-
``get_data`` will return the cached copy.
455+
the default behavior (`caching` == "fill") is to read the data, and
456+
store in an internal cache. Future calls to ``get_data`` will return
457+
the cached copy.
458+
459+
Parameters
460+
----------
461+
caching : {'fill', 'unchanged'}, optional
462+
This argument has no effect in the case where the image data is an
463+
array, or the image data has already been cached. If the image data
464+
is an array proxy, and the image data has not yet been cached, then
465+
'fill' (the default) will read the data from the array proxy, and
466+
store in an internal cache, so that future calls to ``get_data``
467+
will return the cached copy. If 'unchanged' then leave the cache
468+
unchanged; return the cached copy if it exists, if not, load the
469+
data from disk and return that, but without filling the cache.
457470
458471
Returns
459472
-------
460473
data : array
461474
array of image data
462475
"""
463-
if self._data_cache is None:
464-
self._data_cache = np.asanyarray(self._dataobj)
465-
return self._data_cache
476+
if not caching in ('fill', 'unchanged'):
477+
raise ValueError('caching value should be "fill" or "unchanged"')
478+
if self._data_cache is not None:
479+
return self._data_cache
480+
data = np.asanyarray(self._dataobj)
481+
if caching == 'fill':
482+
self._data_cache = data
483+
return data
466484

467485
@property
468486
def in_memory(self):

nibabel/tests/test_image_api.py

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from __future__ import division, print_function, absolute_import
2424

2525
import warnings
26+
from functools import partial
2627

2728
import numpy as np
2829

@@ -176,10 +177,21 @@ def validate_data(self, imaker, params):
176177
proxy_copy = proxy_data.copy()
177178
# Not yet cached, proxy image: in_memory is False
178179
assert_false(img.in_memory)
180+
# Load with caching='unchanged'
181+
data = img.get_data(caching='unchanged')
182+
# Still not cached
183+
assert_false(img.in_memory)
184+
# Default load, does caching
179185
data = img.get_data()
180186
# Data now cached
181187
assert_true(img.in_memory)
182188
assert_false(proxy_data is data)
189+
# Now caching='unchanged' does nothing, returns cached version
190+
data_again = img.get_data(caching='unchanged')
191+
assert_true(data is data_again)
192+
# caching='fill' does nothing because the cache is already full
193+
data_yet_again = img.get_data(caching='fill')
194+
assert_true(data is data_yet_again)
183195
# changing array data does not change proxy data, or reloaded data
184196
data[:] = 42
185197
assert_array_equal(proxy_data, proxy_copy)
@@ -191,25 +203,38 @@ def validate_data(self, imaker, params):
191203
# Which unsets in_memory
192204
assert_false(img.in_memory)
193205
assert_array_equal(img.get_data(), proxy_copy)
194-
else: # not proxy
195-
assert_true(isinstance(img.dataobj, np.ndarray))
206+
# Check caching='fill' does cache data
207+
img = imaker()
208+
assert_false(img.in_memory)
209+
data = img.get_data(caching='fill')
196210
assert_true(img.in_memory)
197-
non_proxy_data = np.asarray(img.dataobj)
198-
data = img.get_data()
199-
assert_true(non_proxy_data is data)
200-
# changing array data does change proxy data, and reloaded data
201-
data[:] = 42
202-
assert_array_equal(np.asarray(img.dataobj), 42)
203-
# It does change the result of get_data
204-
assert_array_equal(img.get_data(), 42)
205-
# Unache has no effect
206-
img.uncache()
207-
assert_array_equal(img.get_data(), 42)
211+
data_again = img.get_data()
212+
assert_true(data is data_again)
213+
else: # not proxy
214+
for caching in (None, 'fill', 'unchanged'):
215+
img = imaker()
216+
get_data_func = (img.get_data if caching is None else
217+
partial(img.get_data, caching=caching))
218+
assert_true(isinstance(img.dataobj, np.ndarray))
219+
assert_true(img.in_memory)
220+
data = get_data_func()
221+
assert_true(data is img.dataobj)
222+
# changing array data does change proxy data, and reloaded data
223+
data[:] = 42
224+
assert_array_equal(np.asarray(img.dataobj), 42)
225+
# It does change the result of get_data
226+
assert_array_equal(get_data_func(), 42)
227+
# Unache has no effect
228+
img.uncache()
229+
assert_array_equal(get_data_func(), 42)
230+
assert_true(img.in_memory)
208231
# dataobj is read only
209232
fake_data = np.zeros(img.shape).astype(img.get_data_dtype())
210233
assert_raises(AttributeError, setattr, img, 'dataobj', fake_data)
211234
# So is in_memory
212235
assert_raises(AttributeError, setattr, img, 'in_memory', False)
236+
# Values to get_data caching parameter must be 'fill' or 'unchanged'
237+
assert_raises(ValueError, img.get_data, caching='something')
213238

214239
def validate_data_deprecated(self, imaker, params):
215240
# Check _data property still exists, but raises warning

0 commit comments

Comments
 (0)