diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 66c835e87cfb1d58748b00290b3151f2ca4d53f1..911b6fe9e46bb872e0b90bde9696fc2a00f27b76 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,16 @@ ===================== +0.14.1 (Friday 31st January 2025) +--------------------------------- + +* Fixed a few bugs introduced in the previous release. +* Adjusted the ``evalHeader`` routine - now it compares ``dim`` and ``pixdim`` + for all valid dimensions by default. The ``alldims`` parameter has been + replaced with a ``ndims`` parameter, allowing the number of dimensions to + be set (e.g. when you only want to compare the first three dimensions). + + 0.14.0 (Friday 31st January 2025) --------------------------------- diff --git a/pyfeeds/__init__.py b/pyfeeds/__init__.py index 5f1fb6a2daa90cfc00842fb239e4cefd75635a2a..3171118da15e1bca8eb57632c0f67d37f1f59909 100644 --- a/pyfeeds/__init__.py +++ b/pyfeeds/__init__.py @@ -5,7 +5,7 @@ # Author: Paul McCarthy <pauldmccarthy@gmail.com> # -__version__ = '0.14.0' +__version__ = '0.14.1' """The pyfeeds version number. """ diff --git a/pyfeeds/common.py b/pyfeeds/common.py index 33a49f7d807a8d7954cd783993e00d8b9e08f440..3f02e7512bd58bf5b580540109ab25925212413f 100644 --- a/pyfeeds/common.py +++ b/pyfeeds/common.py @@ -45,10 +45,10 @@ def tempdir(): prevdir = os.getcwd() - with tempfile.TemporaryDirectory(delete=True) as td: + with tempfile.TemporaryDirectory() as td: try: - os.chdir(testdir) - yield td.name + os.chdir(td) + yield td finally: os.chdir(prevdir) diff --git a/pyfeeds/evaluate.py b/pyfeeds/evaluate.py index 3f9bc3c19837ebfc79c6586d9b9d998020cc1578..d7d8e6dc10b153f38999a815c809a1f97be145e9 100644 --- a/pyfeeds/evaluate.py +++ b/pyfeeds/evaluate.py @@ -413,22 +413,24 @@ def loadImage(pyf, filename): return pyf.imageCache[filename] else: img = nib.load(filename) - if isinstance(image, nib.Nifti1Image): - data = np.asanyarray(image.dataobj) + if isinstance(img, nib.Nifti1Image): + data = np.asanyarray(img.dataobj) else: data = None return img, data -def evalHeader(testfile, benchmark, alldims=True, pyf=None): +def evalHeader(testfile, benchmark, ndims=None, pyf=None): """Evaluation routine which compares the header fields of two NIFTI - images. + images. By default the dim/pixdim values for every dimension are compared, + but the ``ndims`` argument can be used if you only want to compare the + first three dimensions for instance. Returns 0 if they all match, 1 otherwise. """ - img1 = loadImage(testfile)[0] - img2 = loadImage(benchmark)[0] + img1 = loadImage(pyf, testfile)[0] + img2 = loadImage(pyf, benchmark)[0] hdr1 = img1.header hdr2 = img2.header fields = ['dim', 'pixdim', 'intent_code', @@ -437,14 +439,17 @@ def evalHeader(testfile, benchmark, alldims=True, pyf=None): 'qoffset_x', 'qoffset_y', 'qoffset_z', 'srow_x', 'srow_y', 'srow_z'] + if ndims is None: + ndims = max(img1.header['dim'][0], + img2.header['dim'][0]) + for f in fields: f1 = hdr1[f] f2 = hdr2[f] - if (not alldims) and (f in ('dim', 'pixdim')): - ndim = img1.header['dim'][0] - f1 = f1[:ndim + 1] - f2 = f2[:ndim + 1] + if f in ('dim', 'pixdim'): + f1 = f1[:ndims + 1] + f2 = f2[:ndims + 1] if not np.all(np.isclose(f1, f2)): return 1 @@ -453,14 +458,8 @@ def evalHeader(testfile, benchmark, alldims=True, pyf=None): def evalHeaderRestrictDims(testfile, benchmark, pyf=None): - """Evaluation routine which compares the header fields of two NIFTI - images. For the `dim` and `pixdim` fields, only the entries which - are expected to be valid (e.g. `dim1`, `dim2`, and `dim3` for a 3D image) - are compared. - - Returns 0 if they all match, 1 otherwise. - """ - return evalHeader(testfile, benchmark, alldims=False, pyf=pyf) + """Legacy alias for ``evalHeader``. """ + return evalHeader(testfile, benchmark, pyf=pyf) def evalImage(testfile, benchmark, pyf=None): diff --git a/pyfeeds/imagecache.py b/pyfeeds/imagecache.py index aefca31b1b4cf479d1170892676466dd2d89aae8..c101fc0431409c8aba9fbcf0c4516a2e995f7453 100644 --- a/pyfeeds/imagecache.py +++ b/pyfeeds/imagecache.py @@ -77,7 +77,7 @@ class ImageCache: returned value will be ``None``. """ - imagefile = op.realpath(op.abspath(imagefile)) + imagefile = str(op.realpath(op.abspath(imagefile))) image = self.__images.get(imagefile, None) if image is not None: @@ -108,7 +108,7 @@ class ImageCache: # it in this way because all keys # passed to __getitem__ get # transformed in the same way. - imagefile = op.realpath(op.abspath(imagefile)) + imagefile = str(op.realpath(op.abspath(imagefile))) imagesize = size(image) self.__images[ imagefile] = image, data self.__imagesizes[imagefile] = imagesize diff --git a/pyfeeds/tests/__init__.py b/pyfeeds/tests/__init__.py index 7feda3307a62c5d69ea0a8dbe7b06bfd32cd5bd6..a3ec65ba2896a33cda076df112c4337553fd4954 100644 --- a/pyfeeds/tests/__init__.py +++ b/pyfeeds/tests/__init__.py @@ -9,8 +9,6 @@ import os import sys import os.path as op -import contextlib -import tempfile from io import StringIO @@ -61,17 +59,6 @@ class CaptureStdout(object): return self.__mock_stderr.read() -@contextlib.contextmanager -def tempdir(): - prevdir = os.getcwd() - with tempfile.TemporaryDirectory() as td: - try: - os.chdir(td) - yield td - finally: - os.chdir(prevdir) - - def makepaths(paths): for path in paths: dirname = op.dirname(path) diff --git a/pyfeeds/tests/test_config.py b/pyfeeds/tests/test_config.py index 647201f4588920104e632034987bbd269b503dcc..02811dc87d5fa16906c0f42db7d2bdf35bb452ef 100644 --- a/pyfeeds/tests/test_config.py +++ b/pyfeeds/tests/test_config.py @@ -13,7 +13,7 @@ from unittest import mock import pyfeeds.main as main -from pyfeeds.tests import tempdir +from pyfeeds.common import tempdir def test_loadPyfeedsConfig(): diff --git a/pyfeeds/tests/test_evaluate.py b/pyfeeds/tests/test_evaluate.py index 4c9b4a0b82c1c52fcc0ef77b4439f8b29e61aa8a..98ebaf97ffe42675d676dc0a3b632d5328b1d1c2 100644 --- a/pyfeeds/tests/test_evaluate.py +++ b/pyfeeds/tests/test_evaluate.py @@ -11,9 +11,10 @@ import os.path as op import numpy as np import nibabel as nib -from . import tempdir, makepaths, maketest, makepyfeeds, CaptureStdout +from . import makepaths, maketest, makepyfeeds, CaptureStdout from pyfeeds import testing, evaluate +from pyfeeds.common import tempdir def test_evaluateTestAgainstBenchmark(): @@ -79,6 +80,9 @@ def test_evalVectorImage(): assert evaluate.evalVectorImage(fname1, fname1, pyf=pyf) == 0 assert evaluate.evalVectorImage(fname2, fname2, pyf=pyf) == 0 assert evaluate.evalVectorImage(fname1, fname2, pyf=pyf) != 0 + assert evaluate.evalVectorImage(fname1, fname1) == 0 + assert evaluate.evalVectorImage(fname2, fname2) == 0 + assert evaluate.evalVectorImage(fname1, fname2) != 0 def test_evalImage(): @@ -98,3 +102,102 @@ def test_evalImage(): assert evaluate.evalImage(fname1, fname1, pyf=pyf) == 0 assert evaluate.evalImage(fname2, fname2, pyf=pyf) == 0 assert evaluate.evalImage(fname1, fname2, pyf=pyf) != 0 + assert evaluate.evalImage(fname1, fname1) == 0 + assert evaluate.evalImage(fname2, fname2) == 0 + assert evaluate.evalImage(fname1, fname2) != 0 + + +def test_evalHeader(): + + arr1 = -1 + 2 * np.random.random((10, 10, 10, 10)) + arr2 = -1 + 2 * np.random.random((10, 10, 10, 10)) + arr3 = -1 + 2 * np.random.random((10, 10, 10, 20)) + arr4 = -1 + 2 * np.random.random(( 5, 5, 5, 20)) + + with tempdir(): + + pyf = makepyfeeds() + fname1 = 'image1.nii.gz' + fname2 = 'image2.nii.gz' + fname3 = 'image3.nii.gz' + fname4 = 'image4.nii.gz' + + nib.Nifti1Image(arr1, np.eye(4)).to_filename(fname1) + nib.Nifti1Image(arr2, np.eye(4)).to_filename(fname2) + nib.Nifti1Image(arr3, np.eye(4)).to_filename(fname3) + nib.Nifti1Image(arr4, np.eye(4)).to_filename(fname4) + + assert evaluate.evalHeader(fname1, fname1, pyf=pyf) == 0 + assert evaluate.evalHeader(fname2, fname2, pyf=pyf) == 0 + assert evaluate.evalHeader(fname3, fname3, pyf=pyf) == 0 + assert evaluate.evalHeader(fname4, fname4, pyf=pyf) == 0 + assert evaluate.evalHeader(fname1, fname1) == 0 + assert evaluate.evalHeader(fname2, fname2) == 0 + assert evaluate.evalHeader(fname3, fname3) == 0 + assert evaluate.evalHeader(fname4, fname4) == 0 + + assert evaluate.evalHeader(fname1, fname2) == 0 + assert evaluate.evalHeader(fname1, fname3) != 0 + assert evaluate.evalHeader(fname1, fname4) != 0 + assert evaluate.evalHeader(fname1, fname3, ndims=3) == 0 + assert evaluate.evalHeader(fname3, fname4) != 0 + assert evaluate.evalHeader(fname3, fname4, ndims=3) != 0 + + assert evaluate.evalHeaderRestrictDims(fname1, fname2, pyf=pyf) == 0 + assert evaluate.evalHeaderRestrictDims(fname1, fname3, pyf=pyf) != 0 + assert evaluate.evalHeaderRestrictDims(fname1, fname2) == 0 + assert evaluate.evalHeaderRestrictDims(fname1, fname3) != 0 + + +def test_evalImageMaxDiff(): + + arr1 = np.zeros((10, 10, 10)) + arr2 = np.zeros((10, 10, 10)) + + arr1[0, 0, 0] = 100 + + with tempdir(): + + pyf = makepyfeeds() + fname1 = 'image1.nii.gz' + fname2 = 'image2.nii.gz' + nib.Nifti1Image(arr1, np.eye(4)).to_filename(fname1) + nib.Nifti1Image(arr2, np.eye(4)).to_filename(fname2) + + assert evaluate.evalImageMaxDiff(fname1, fname1, pyf=pyf) == 0 + assert evaluate.evalImageMaxDiff(fname1, fname1) == 0 + assert evaluate.evalImageMaxDiff(fname1, fname2) == 100 + +def test_evalNumericalText(): + + arr1 = np.random.random(100) + arr2 = np.random.random(100) * 4 + + with tempdir(): + + pyf = makepyfeeds() + fname1 = 'data1.txt' + fname2 = 'data2.txt' + np.savetxt(fname1, arr1) + np.savetxt(fname2, arr2) + + assert evaluate.evalNumericalText(fname1, fname1, pyf=pyf) == 0 + assert evaluate.evalNumericalText(fname1, fname1) == 0 + assert evaluate.evalNumericalText(fname1, fname2) != 0 + +def test_evalMD5(): + + arr1 = np.random.random(100) + arr2 = np.random.random(100) * 4 + + with tempdir(): + + pyf = makepyfeeds() + fname1 = 'data1.txt' + fname2 = 'data2.txt' + np.savetxt(fname1, arr1) + np.savetxt(fname2, arr2) + + assert evaluate.evalMD5(fname1, fname1, pyf=pyf) == 0 + assert evaluate.evalMD5(fname1, fname1) == 0 + assert evaluate.evalMD5(fname1, fname2) != 0 diff --git a/pyfeeds/tests/test_hashing.py b/pyfeeds/tests/test_hashing.py index bb303a706d8ab87068fd45e6270166529b95893f..808cab884b4612e9dab2b67f81e6bfa3941c817f 100644 --- a/pyfeeds/tests/test_hashing.py +++ b/pyfeeds/tests/test_hashing.py @@ -13,8 +13,9 @@ import os.path as op import time from pyfeeds import hashing, testing +from pyfeeds.common import tempdir -from . import CaptureStdout, makepyfeeds, maketest, makepaths, tempdir +from . import CaptureStdout, makepyfeeds, maketest, makepaths def test_genHashes(): diff --git a/pyfeeds/tests/test_testing.py b/pyfeeds/tests/test_testing.py index 3dcadbb17188e8f1f1cc20b41264701ff40c64a8..2761aa07409efdd574b371b62d2d2b3d4388c550 100644 --- a/pyfeeds/tests/test_testing.py +++ b/pyfeeds/tests/test_testing.py @@ -10,9 +10,10 @@ import os import datetime import os.path as op -from . import tempdir, makepaths, maketest, makepyfeeds, CaptureStdout +from . import makepaths, maketest, makepyfeeds, CaptureStdout from pyfeeds import testing +from pyfeeds.common import tempdir def test_findTestDirs():