Skip to content

Commit 12db9ec

Browse files
committed
TEST: Refactor no_scaling test to parametrize without looping
1 parent 0a8701a commit 12db9ec

File tree

2 files changed

+61
-43
lines changed

2 files changed

+61
-43
lines changed

nibabel/tests/conftest.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import pytest
2+
3+
from ..spatialimages import supported_np_types
4+
5+
6+
# Generate dynamic fixtures
7+
def pytest_generate_tests(metafunc):
8+
if 'supported_dtype' in metafunc.fixturenames:
9+
if metafunc.cls is None or not getattr(metafunc.cls, 'image_class'):
10+
raise pytest.UsageError(
11+
'Attempting to use supported_dtype fixture outside an image test case'
12+
)
13+
# xdist needs a consistent ordering, so sort by class name
14+
supported_dtypes = sorted(
15+
supported_np_types(metafunc.cls.image_class.header_class()),
16+
key=lambda x: x.__name__,
17+
)
18+
metafunc.parametrize('supported_dtype', supported_dtypes)

nibabel/tests/test_spm99analyze.py

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -306,57 +306,57 @@ def test_int_int_scaling(self):
306306
img_rt = bytesio_round_trip(img)
307307
assert_array_equal(img_rt.get_fdata(), np.clip(arr, 0, 255))
308308

309-
def test_no_scaling(self):
309+
# NOTE: Need to check complex scaling
310+
@pytest.mark.parametrize('in_dtype', FLOAT_TYPES + IUINT_TYPES)
311+
def test_no_scaling(self, in_dtype, supported_dtype):
310312
# Test writing image converting types when not calculating scaling
311313
img_class = self.image_class
312314
hdr_class = img_class.header_class
313315
hdr = hdr_class()
314-
supported_types = supported_np_types(hdr)
315316
# Any old non-default slope and intercept
316317
slope = 2
317318
inter = 10 if hdr.has_data_intercept else 0
318-
for in_dtype, out_dtype in itertools.product(FLOAT_TYPES + IUINT_TYPES, supported_types):
319-
# Need to check complex scaling
320-
mn_in, mx_in = _dt_min_max(in_dtype)
321-
arr = np.array([mn_in, -1, 0, 1, 10, mx_in], dtype=in_dtype)
322-
img = img_class(arr, np.eye(4), hdr)
323-
img.set_data_dtype(out_dtype)
324-
# Setting the scaling means we don't calculate it later
325-
img.header.set_slope_inter(slope, inter)
326-
with np.errstate(invalid='ignore'):
327-
rt_img = bytesio_round_trip(img)
328-
with suppress_warnings(): # invalid mult
329-
back_arr = np.asanyarray(rt_img.dataobj)
330-
exp_back = arr.copy()
331-
# If converting to floating point type, casting is direct.
332-
# Otherwise we will need to do float-(u)int casting at some point
333-
if out_dtype in IUINT_TYPES:
334-
if in_dtype in FLOAT_TYPES:
335-
# Working precision is (at least) float
336-
exp_back = exp_back.astype(float)
337-
# Float to iu conversion will always round, clip
338-
with np.errstate(invalid='ignore'):
339-
exp_back = np.round(exp_back)
340-
if in_dtype in FLOAT_TYPES:
341-
# Clip to shared range of working precision
342-
exp_back = np.clip(exp_back, *shared_range(float, out_dtype))
343-
else: # iu input and output type
344-
# No scaling, never gets converted to float.
345-
# Does get clipped to range of output type
346-
mn_out, mx_out = _dt_min_max(out_dtype)
347-
if (mn_in, mx_in) != (mn_out, mx_out):
348-
# Use smaller of input, output range to avoid np.clip
349-
# upcasting the array because of large clip limits.
350-
exp_back = np.clip(exp_back, max(mn_in, mn_out), min(mx_in, mx_out))
351-
if out_dtype in COMPLEX_TYPES:
352-
# always cast to real from complex
353-
exp_back = exp_back.astype(out_dtype)
354-
else:
355-
# Cast to working precision
319+
320+
mn_in, mx_in = _dt_min_max(in_dtype)
321+
arr = np.array([mn_in, -1, 0, 1, 10, mx_in], dtype=in_dtype)
322+
img = img_class(arr, np.eye(4), hdr)
323+
img.set_data_dtype(supported_dtype)
324+
# Setting the scaling means we don't calculate it later
325+
img.header.set_slope_inter(slope, inter)
326+
with np.errstate(invalid='ignore'):
327+
rt_img = bytesio_round_trip(img)
328+
with suppress_warnings(): # invalid mult
329+
back_arr = np.asanyarray(rt_img.dataobj)
330+
exp_back = arr.copy()
331+
# If converting to floating point type, casting is direct.
332+
# Otherwise we will need to do float-(u)int casting at some point
333+
if supported_dtype in IUINT_TYPES:
334+
if in_dtype in FLOAT_TYPES:
335+
# Working precision is (at least) float
356336
exp_back = exp_back.astype(float)
357-
# Allow for small differences in large numbers
358-
with suppress_warnings(): # invalid value
359-
assert_allclose_safely(back_arr, exp_back * slope + inter)
337+
# Float to iu conversion will always round, clip
338+
with np.errstate(invalid='ignore'):
339+
exp_back = np.round(exp_back)
340+
if in_dtype in FLOAT_TYPES:
341+
# Clip to shared range of working precision
342+
exp_back = np.clip(exp_back, *shared_range(float, supported_dtype))
343+
else: # iu input and output type
344+
# No scaling, never gets converted to float.
345+
# Does get clipped to range of output type
346+
mn_out, mx_out = _dt_min_max(supported_dtype)
347+
if (mn_in, mx_in) != (mn_out, mx_out):
348+
# Use smaller of input, output range to avoid np.clip
349+
# upcasting the array because of large clip limits.
350+
exp_back = np.clip(exp_back, max(mn_in, mn_out), min(mx_in, mx_out))
351+
if supported_dtype in COMPLEX_TYPES:
352+
# always cast to real from complex
353+
exp_back = exp_back.astype(supported_dtype)
354+
else:
355+
# Cast to working precision
356+
exp_back = exp_back.astype(float)
357+
# Allow for small differences in large numbers
358+
with suppress_warnings(): # invalid value
359+
assert_allclose_safely(back_arr, exp_back * slope + inter)
360360

361361
def test_write_scaling(self):
362362
# Check writes with scaling set

0 commit comments

Comments
 (0)