Skip to content

Commit 13c2a38

Browse files
committed
TST: Add a fixture to create random PET data for tests
Add a fixture to create random PET data for tests. Adopt the fixture across PET tests. Take advantage of the commit to adopt `dataset` as the name of the created PET dataset variable across tests.
1 parent 3857e43 commit 13c2a38

File tree

5 files changed

+158
-62
lines changed

5 files changed

+158
-62
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ env = "PYTHONHASHSEED=0"
223223
markers = [
224224
"random_gtab_data: Custom marker for random gtab data tests",
225225
"random_dwi_data: Custom marker for random dwi data tests",
226+
"random_pet_data: Custom marker for random pet data tests",
226227
"random_uniform_ndim_data: Custom marker for random multi-dimensional data tests",
227228
"random_uniform_spatial_data: Custom marker for random spatial data tests",
228229
]

test/conftest.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,3 +297,31 @@ def setup_random_dwi_data(request, setup_random_gtab_data):
297297
gradients,
298298
b0_thres,
299299
)
300+
301+
302+
@pytest.fixture(autouse=True)
303+
def setup_random_pet_data(request):
304+
"""Automatically generate random PET data for tests."""
305+
marker = request.node.get_closest_marker("random_pet_data")
306+
307+
n_frames = 5
308+
vol_size = (4, 4, 4)
309+
midframe = np.arange(n_frames, dtype=np.float32) + 1
310+
total_duration = float(n_frames + 1)
311+
if marker:
312+
n_frames, vol_size, midframe, total_duration = marker.args
313+
314+
rng = request.node.rng
315+
316+
pet_dataobj, affine = _generate_random_uniform_spatial_data(
317+
request, (*vol_size, n_frames), 0.0, 1.0
318+
)
319+
brainmask_dataobj = rng.choice([True, False], size=vol_size).astype(np.uint8)
320+
321+
return (
322+
pet_dataobj,
323+
affine,
324+
brainmask_dataobj,
325+
midframe,
326+
total_duration,
327+
)

test/test_pet_data.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,24 @@ def test_from_nii_requires_frame_time(setup_random_uniform_spatial_data, tmp_pat
2424
from_nii(fname)
2525

2626

27-
def _create_dataset():
28-
rng = np.random.default_rng(12345)
29-
data = rng.random((4, 4, 4, 5), dtype=np.float32)
30-
affine = np.eye(4, dtype=np.float32)
31-
mask = np.ones((4, 4, 4), dtype=bool)
32-
midframe = np.array([10, 20, 30, 40, 50], dtype=np.float32)
33-
return PET(
34-
dataobj=data,
27+
@pytest.mark.random_pet_data(5, (4, 4, 4), (10, 20, 30, 40, 50), 60.0)
28+
def test_pet_set_transform_updates_motion_affines(setup_random_pet_data):
29+
(
30+
pet_dataobj,
31+
affine,
32+
brainmask_dataobj,
33+
midframe,
34+
total_duration,
35+
) = setup_random_pet_data
36+
37+
dataset = PET(
38+
dataobj=pet_dataobj,
3539
affine=affine,
36-
brainmask=mask,
40+
brainmask=brainmask_dataobj,
3741
midframe=midframe,
38-
total_duration=60.0,
42+
total_duration=total_duration,
3943
)
4044

41-
42-
def test_pet_set_transform_updates_motion_affines():
43-
dataset = _create_dataset()
4445
idx = 2
4546
data_before = np.copy(dataset.dataobj[..., idx])
4647

test/test_pet_model.py

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,24 @@
55
from nifreeze.model.pet import PETModel
66

77

8-
def _create_dataset():
9-
rng = np.random.default_rng(12345)
10-
data = rng.random((4, 4, 4, 5), dtype=np.float32)
11-
affine = np.eye(4, dtype=np.float32)
12-
mask = np.ones((4, 4, 4), dtype=bool)
13-
midframe = np.array([10, 20, 30, 40, 50], dtype=np.float32)
14-
return PET(
15-
dataobj=data,
8+
@pytest.mark.random_pet_data(5, (4, 4, 4), (10, 20, 30, 40, 50), 60.0)
9+
def test_petmodel_fit_predict(setup_random_pet_data):
10+
(
11+
pet_dataobj,
12+
affine,
13+
brainmask_dataobj,
14+
midframe,
15+
total_duration,
16+
) = setup_random_pet_data
17+
18+
dataset = PET(
19+
dataobj=pet_dataobj,
1620
affine=affine,
17-
brainmask=mask,
21+
brainmask=brainmask_dataobj,
1822
midframe=midframe,
19-
total_duration=60.0,
23+
total_duration=total_duration,
2024
)
2125

22-
23-
def test_petmodel_fit_predict():
24-
dataset = _create_dataset()
2526
model = PETModel(
2627
dataset=dataset,
2728
timepoints=dataset.midframe,
@@ -40,14 +41,46 @@ def test_petmodel_fit_predict():
4041
assert vol.dtype == dataset.dataobj.dtype
4142

4243

43-
def test_petmodel_invalid_init():
44-
dataset = _create_dataset()
44+
@pytest.mark.random_pet_data(5, (4, 4, 4), (10, 20, 30, 40, 50), 60.0)
45+
def test_petmodel_invalid_init(setup_random_pet_data):
46+
(
47+
pet_dataobj,
48+
affine,
49+
brainmask_dataobj,
50+
midframe,
51+
total_duration,
52+
) = setup_random_pet_data
53+
54+
dataset = PET(
55+
dataobj=pet_dataobj,
56+
affine=affine,
57+
brainmask=brainmask_dataobj,
58+
midframe=midframe,
59+
total_duration=total_duration,
60+
)
61+
4562
with pytest.raises(TypeError):
4663
PETModel(dataset=dataset)
4764

4865

49-
def test_petmodel_time_check():
50-
dataset = _create_dataset()
66+
@pytest.mark.random_pet_data(5, (4, 4, 4), (10, 20, 30, 40, 50), 60.0)
67+
def test_petmodel_time_check(setup_random_pet_data):
68+
(
69+
pet_dataobj,
70+
affine,
71+
brainmask_dataobj,
72+
midframe,
73+
total_duration,
74+
) = setup_random_pet_data
75+
76+
dataset = PET(
77+
dataobj=pet_dataobj,
78+
affine=affine,
79+
brainmask=brainmask_dataobj,
80+
midframe=midframe,
81+
total_duration=total_duration,
82+
)
83+
5184
bad_times = np.array([0, 10, 20, 30, 50], dtype=np.float32)
5285
with pytest.raises(ValueError):
5386
PETModel(dataset=dataset, timepoints=bad_times, xlim=60.0)

test/test_pet_workflow.py

Lines changed: 65 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,83 @@
11
import types
22

33
import numpy as np
4+
import pytest
45

56
from nifreeze.data.pet import PET
67
from nifreeze.estimator import PETMotionEstimator
78

89

9-
def _pet_dataset(n_frames=3):
10-
rng = np.random.default_rng(42)
11-
data = rng.random((2, 2, 2, n_frames), dtype=np.float32)
12-
affine = np.eye(4, dtype=np.float32)
13-
mask = np.ones((2, 2, 2), dtype=bool)
14-
midframe = np.arange(n_frames, dtype=np.float32) + 1
15-
return PET(
16-
dataobj=data,
10+
@pytest.mark.random_pet_data(4, (2, 2, 2), (1.0, 2.0, 3.0, 4.0), 5.0)
11+
def test_lofo_split_shapes(setup_random_pet_data, tmp_path):
12+
(
13+
pet_dataobj,
14+
affine,
15+
brainmask_dataobj,
16+
midframe,
17+
total_duration,
18+
) = setup_random_pet_data
19+
20+
dataset = PET(
21+
dataobj=pet_dataobj,
1722
affine=affine,
18-
brainmask=mask,
23+
brainmask=brainmask_dataobj,
1924
midframe=midframe,
20-
total_duration=float(n_frames + 1),
25+
total_duration=total_duration,
2126
)
2227

23-
24-
def test_lofo_split_shapes(tmp_path):
25-
ds = _pet_dataset(4)
2628
idx = 2
27-
(train_data, train_times), (test_data, test_time) = ds.lofo_split(idx)
28-
assert train_data.shape[-1] == ds.dataobj.shape[-1] - 1
29-
np.testing.assert_array_equal(test_data, ds.dataobj[..., idx])
30-
np.testing.assert_array_equal(train_times, np.delete(ds.midframe, idx))
31-
assert test_time == ds.midframe[idx]
32-
29+
(train_data, train_times), (test_data, test_time) = dataset.lofo_split(idx)
30+
assert train_data.shape[-1] == dataset.dataobj.shape[-1] - 1
31+
np.testing.assert_array_equal(test_data, dataset.dataobj[..., idx])
32+
np.testing.assert_array_equal(train_times, np.delete(dataset.midframe, idx))
33+
assert test_time == dataset.midframe[idx]
34+
35+
36+
@pytest.mark.random_pet_data(3, (2, 2, 2), (1.0, 2.0, 3.0), 4.0)
37+
def test_to_from_filename_roundtrip(setup_random_pet_data):
38+
(
39+
pet_dataobj,
40+
affine,
41+
brainmask_dataobj,
42+
midframe,
43+
total_duration,
44+
) = setup_random_pet_data
45+
46+
dataset = PET(
47+
dataobj=pet_dataobj,
48+
affine=affine,
49+
brainmask=brainmask_dataobj,
50+
midframe=midframe,
51+
total_duration=total_duration,
52+
)
3353

34-
def test_to_from_filename_roundtrip(tmp_path):
35-
ds = _pet_dataset(3)
3654
out_file = tmp_path / "petdata"
37-
ds.to_filename(out_file)
55+
dataset.to_filename(out_file)
3856
assert (tmp_path / "petdata.h5").exists()
3957
loaded = PET.from_filename(tmp_path / "petdata.h5")
40-
np.testing.assert_allclose(loaded.dataobj, ds.dataobj)
41-
np.testing.assert_allclose(loaded.affine, ds.affine)
42-
np.testing.assert_allclose(loaded.midframe, ds.midframe)
43-
assert loaded.total_duration == ds.total_duration
44-
45-
46-
def test_pet_motion_estimator_run(monkeypatch):
47-
ds = _pet_dataset(3)
58+
np.testing.assert_allclose(loaded.dataobj, dataset.dataobj)
59+
np.testing.assert_allclose(loaded.affine, dataset.affine)
60+
np.testing.assert_allclose(loaded.midframe, dataset.midframe)
61+
assert loaded.total_duration == dataset.total_duration
62+
63+
64+
@pytest.mark.random_pet_data(3, (2, 2, 2), (1.0, 2.0, 3.0), 4.0)
65+
def test_pet_motion_estimator_run(setup_random_pet_data, monkeypatch):
66+
(
67+
pet_dataobj,
68+
affine,
69+
brainmask_dataobj,
70+
midframe,
71+
total_duration,
72+
) = setup_random_pet_data
73+
74+
dataset = PET(
75+
dataobj=pet_dataobj,
76+
affine=affine,
77+
brainmask=brainmask_dataobj,
78+
midframe=midframe,
79+
total_duration=total_duration,
80+
)
4881

4982
class DummyModel:
5083
def __init__(self, _dataset):
@@ -67,7 +100,7 @@ def run(self, cwd=None):
67100
monkeypatch.setattr("nifreeze.estimator.Registration", DummyRegistration)
68101

69102
estimator = PETMotionEstimator(None)
70-
affines = estimator.run(ds)
71-
assert len(affines) == len(ds)
103+
affines = estimator.run(dataset)
104+
assert len(affines) == len(dataset)
72105
for mat in affines:
73106
np.testing.assert_array_equal(mat, np.eye(4))

0 commit comments

Comments
 (0)