diff --git a/.github/workflows/ismrmrd_python_conda.yml b/.github/workflows/ismrmrd_python_conda.yml
index c3117a4..1625717 100644
--- a/.github/workflows/ismrmrd_python_conda.yml
+++ b/.github/workflows/ismrmrd_python_conda.yml
@@ -1,10 +1,10 @@
on:
+ push:
+ branches: [master]
+ tags: ["v*.*.*"]
pull_request:
- branches:
- - master
- release:
- types:
- - created
+ branches: [master]
+ workflow_dispatch:
jobs:
build-conda-packages:
@@ -13,12 +13,13 @@ jobs:
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
- - uses: conda-incubator/setup-miniconda@e81abac10ce2c37423b54eae5af93aa3b4d3475c
+ - uses: actions/checkout@v5
+ - uses: conda-incubator/setup-miniconda@v3
with:
+ miniforge-version: latest
activate-environment: ismrmrd-python-build
environment-file: conda/environment.yml
- python-version: 3.9
+ python-version: 3.12
auto-activate-base: false
- name: Build conda package
shell: bash -l {0}
diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml
index a560f7d..c7f32a4 100644
--- a/.github/workflows/python-publish.yml
+++ b/.github/workflows/python-publish.yml
@@ -1,56 +1,53 @@
name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI
-on:
- release:
- types:
- - created
+on:
+ push:
+ branches: [master]
+ tags: ["v*.*.*"]
+ pull_request:
+ branches: [master]
workflow_dispatch:
jobs:
build:
name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@master
- - name: Set up Python 3.9
- uses: actions/setup-python@v1
+ - uses: actions/checkout@v5
+ - name: Set up Python 3.x
+ uses: actions/setup-python@v5
with:
- python-version: 3.9
+ python-version: 3.12
+ - name: Install runtime dependencies
+ run: python -m pip install -r requirements.txt --user
+ - name: Perform editable installation to generate the schema subpackage
+ run: python -m pip install -e .
+ - name: Run all tests
+ run: python -m pytest
- name: Install pypa/build
- run: >-
- python -m
- pip install
- build
- --user
+ run: python -m pip install build --user
- name: Build a binary wheel and a source tarball
- run: >-
- python -m
- build
- --sdist
- --wheel
- --outdir dist/
- .
+ run: python -m build --sdist --wheel --outdir dist/ .
- name: Store the distribution packages
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: python-package-distributions
path: dist/
publish-to-pypi:
- name: >-
- Publish Python 🐍 distribution 📦 to PyPI
- if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' # only publish to PyPI on tag pushes or manual trigger
+ name: Publish Python 🐍 distribution 📦 to PyPI
+ if: github.event_name == 'workflow_dispatch' || github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
needs:
- build
runs-on: ubuntu-latest
environment:
name: pypi
- url: https://pypi.org/p/ismrmrmd
+ url: https://pypi.org/p/ismrmrmd
permissions:
id-token: write
steps:
- name: Download all the dists
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v5
with:
name: python-package-distributions
path: dist/
diff --git a/README b/README.md
similarity index 100%
rename from README
rename to README.md
diff --git a/conda/conda_build_config.yaml b/conda/conda_build_config.yaml
index 65ea6b8..a042c9f 100644
--- a/conda/conda_build_config.yaml
+++ b/conda/conda_build_config.yaml
@@ -1,3 +1,3 @@
python:
- - 3.9
- - 3.10
\ No newline at end of file
+ - 3.10
+ - 3.12
\ No newline at end of file
diff --git a/conda/meta.yaml b/conda/meta.yaml
index e33d45b..dafc854 100644
--- a/conda/meta.yaml
+++ b/conda/meta.yaml
@@ -10,12 +10,10 @@ source:
requirements:
build:
- python {{ python }}
- - xsdata >=24.0
+ - xsdata>=24.0
- setuptools
- - wheel
- - jinja2 >=2.11.0
- pip
-
+
run:
- python
- numpy>=1.22.0
@@ -29,10 +27,10 @@ test:
- tests
commands:
- pip check
- - nosetests
+ - pytest
requires:
- pip
- - nose
+ - pytest
about:
home: https://github.com/ismrmrd/ismrmrd-python
diff --git a/conda/run_test.sh b/conda/run_test.sh
index 551d0e6..8bae610 100644
--- a/conda/run_test.sh
+++ b/conda/run_test.sh
@@ -2,6 +2,4 @@
set -euo pipefail
-cd tests
-nosetests
-
+pytest
diff --git a/ismrmrd/xsd/__init__.py b/ismrmrd/xsd/__init__.py
index c462532..ec08e78 100644
--- a/ismrmrd/xsd/__init__.py
+++ b/ismrmrd/xsd/__init__.py
@@ -1,2 +1,2 @@
-from .pyxb_compat import (CreateFromDocument, ToXML, ToDOM)
-from .ismrmrdschema import *
+from .pyxb_compat import CreateFromDocument, ToXML, ToDOM
+from .ismrmrdschema import *
diff --git a/pyproject.toml b/pyproject.toml
index bf5365b..34dbfcf 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,3 +1,29 @@
[build-system]
-requires = ["setuptools","wheel","xsdata[cli]","jinja2 >= 2.11.0"]
-build-backend = "setuptools.build_meta"
\ No newline at end of file
+requires = ["setuptools", "xsdata[cli]"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "ismrmrd"
+dynamic = ["version"]
+dependencies = ["h5py>=2.3", "numpy>=1.22.0", "xsdata>=22.12"]
+requires-python = ">=3.9"
+
+authors = [{name = "ISMRMRD Developers"}]
+
+description = "Python implementation of ISMRMRD"
+readme = "README.md"
+license-files = ["LICENSE"]
+license = "LicenseRef-IsmrmrdSoftwareLicense"
+keywords = ["ismrmrd"]
+classifiers = [
+ "Development Status :: 5 - Production/Stable",
+ "Programming Language :: Python :: 3",
+ "Operating System :: OS Independent",
+ "Intended Audience :: Science/Research",
+ "Topic :: Scientific/Engineering :: Medical Science Apps."
+]
+
+[project.urls]
+Homepage = "https://github.com/ismrmrd/ismrmrd-python"
+Documentation = "https://github.com/ismrmrd/ismrmrd-python"
+Repository = "https://github.com/ismrmrd/ismrmrd-python"
diff --git a/requirements.txt b/requirements.txt
index 311eac9..89b3e99 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,6 +1,4 @@
-h5py==2.9.0
-nose==1.3.7
-numpy==1.22.0
-PyXB==1.2.6
-six==1.12.0
-xsdata==24.4
\ No newline at end of file
+h5py==3.14.0
+pytest==8.4.1
+numpy==2.3.2
+xsdata==25.7
\ No newline at end of file
diff --git a/setup.py b/setup.py
index a7cd7d2..04ef977 100644
--- a/setup.py
+++ b/setup.py
@@ -1,81 +1,74 @@
import os
-from setuptools import setup, find_packages
-from distutils.command.build import build
-from distutils.command.build_py import build_py
+from setuptools import setup, find_packages, Command
-import logging
import shutil
from pathlib import Path
-import re
-
-logging.basicConfig()
-log_ = logging.getLogger(__name__)
+import re
schema_file = os.path.join('schema','ismrmrd.xsd')
config_file = os.path.join('schema','.xsdata.xml')
-class my_build_py(build_py):
- def run(self):
- # honor the --dry-run flag
- if not self.dry_run:
- outloc = self.build_lib
- outloc = os.path.join(outloc,'ismrmrd/xsd/ismrmrdschema')
-
- generate_schema(schema_file, config_file, outloc)
- # distutils uses old-style classes, so no super()
- build_py.run(self)
+import setuptools.command.build
+setuptools.command.build.build.sub_commands.append(("generate_schema", None))
+class GenerateSchemaCommand(Command):
+ description = "Generate Python code from ISMRMRD XML schema using xsdata"
+ user_options = []
-def fix_init_file(package_name,filepath):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.build_lib = None
+ self.editable_mode = False
- with open(filepath,'r+') as f:
- text = f.read()
- text = re.sub(f'from {package_name}.ismrmrd', 'from .ismrmrd',text)
- f.seek(0)
- f.write(text)
- f.truncate()
+ def initialize_options(self):
+ pass
+ def finalize_options(self):
+ # Set build_lib for non-editable installs
+ self.set_undefined_options("build_py", ("build_lib", "build_lib"))
+ def run(self):
+ # Use editable_mode if present (PEP 660)
+ if self.editable_mode:
+ outdir = 'ismrmrd/xsd/'
+ else:
+ outdir = os.path.join(self.build_lib, 'ismrmrd/xsd/')
+ self.announce(f'Generating schema to {outdir} (editable_mode={self.editable_mode})', level=3)
+ self.generate_schema(schema_file, config_file, 'ismrmrdschema', outdir)
+ def get_source_files(self):
+ return [schema_file, config_file]
-def generate_schema(schema_filename, config_filename, outloc ):
- def to_uri(filename):
- return Path(filename).absolute().as_uri()
+ def get_outputs(self):
+ return [
+ "{build_lib}/ismrmrd/xsd/ismrmrdschema/__init__.py",
+ "{build_lib}/ismrmrd/xsd/ismrmrdschema/ismrmrd.py"
+ ]
- import sys
- import subprocess
-
- subpackage_name = 'ismrmrdschema'
- args = [sys.executable,'-m','xsdata', str(schema_filename), '--config',str(config_filename), '--package',subpackage_name]
- subprocess.run(args)
- fix_init_file(subpackage_name,f"{subpackage_name}/__init__.py")
- shutil.rmtree(os.path.join(outloc,subpackage_name),ignore_errors=True)
- shutil.move(subpackage_name,outloc)
+ def fix_init_file(self, package_name,filepath):
+ with open(filepath,'r+') as f:
+ text = f.read()
+ text = re.sub(f'from {package_name}.ismrmrd', 'from .ismrmrd',text)
+ f.seek(0)
+ f.write(text)
+ f.truncate()
-this_directory = Path(__file__).parent
-long_description = (this_directory / "README").read_text()
+ def generate_schema(self, schema_filename, config_filename, subpackage_name, outdir):
+ import sys
+ import subprocess
+ # subpackage_name = 'ismrmrdschema'
+ args = [sys.executable, '-m', 'xsdata', str(schema_filename), '--config', str(config_filename), '--package', subpackage_name]
+ subprocess.run(args)
+ self.fix_init_file(subpackage_name, f"{subpackage_name}/__init__.py")
+ destination = os.path.join(outdir, subpackage_name)
+ shutil.rmtree(destination, ignore_errors=True)
+ shutil.move(subpackage_name, destination)
setup(
- name='ismrmrd',
version='1.14.1',
- author='ISMRMRD Developers',
- description='Python implementation of the ISMRMRD',
- license='Public Domain',
- keywords='ismrmrd',
- url='https://ismrmrd.github.io',
- long_description = long_description,
- long_description_content_type='text/markdown',
packages=find_packages(),
- classifiers=[
- 'Development Status :: 5 - Production/Stable',
- 'Intended Audience :: Science/Research',
- 'License :: Public Domain',
- 'Operating System :: OS Independent',
- 'Topic :: Scientific/Engineering :: Medical Science Apps.'
- ],
- install_requires=['xsdata>=22.12', 'numpy>=1.22.0', 'h5py>=2.3'],
- setup_requires=['nose>=1.0', 'xsdata[cli]>=22.12', 'jinja2 >= 2.11'],
- test_suite='nose.collector',
- cmdclass={'build_py':my_build_py}
+ cmdclass={
+ 'generate_schema': GenerateSchemaCommand
+ }
)
diff --git a/tests/test_acquisition.py b/tests/test_acquisition.py
index 988b67f..f1b7512 100644
--- a/tests/test_acquisition.py
+++ b/tests/test_acquisition.py
@@ -1,56 +1,49 @@
import ismrmrd
import ctypes
import numpy as np
-
import io
-import nose.tools
-
-from nose.tools import eq_
+import pytest
import test_common as common
def test_encoding_counters():
idx = ismrmrd.EncodingCounters()
- eq_(ctypes.sizeof(idx), 34)
+ assert ctypes.sizeof(idx) == 34
def test_header():
head = ismrmrd.AcquisitionHeader()
- eq_(ctypes.sizeof(head), 340)
+ assert ctypes.sizeof(head) == 340
def test_new_instance():
acq = ismrmrd.Acquisition()
- eq_(type(acq.getHead()), ismrmrd.AcquisitionHeader)
- eq_(type(acq.data), np.ndarray)
- eq_(acq.data.dtype, np.complex64)
- eq_(type(acq.traj), np.ndarray)
- eq_(acq.traj.dtype, np.float32)
+ assert type(acq.getHead()) == ismrmrd.AcquisitionHeader
+ assert type(acq.data) == np.ndarray
+ assert acq.data.dtype == np.complex64
+ assert type(acq.traj) == np.ndarray
+ assert acq.traj.dtype == np.float32
def test_read_only_fields():
acq = ismrmrd.Acquisition()
for field in ['number_of_samples', 'active_channels', 'trajectory_dimensions']:
- try:
+ with pytest.raises(AttributeError):
setattr(acq, field, None)
- except AttributeError:
- pass
- else:
- assert False, "assigned to read-only field of Acquisition"
def test_resize():
acq = ismrmrd.Acquisition()
nsamples, nchannels, ntrajdims = 128, 8, 3
acq.resize(nsamples, nchannels, ntrajdims)
- eq_(acq.data.shape, (nchannels, nsamples))
- eq_(acq.traj.shape, (nsamples, ntrajdims))
+ assert acq.data.shape == (nchannels, nsamples)
+ assert acq.traj.shape == (nsamples, ntrajdims)
head = acq.getHead()
- eq_(head.number_of_samples, nsamples)
- eq_(head.active_channels, nchannels)
- eq_(head.trajectory_dimensions, ntrajdims)
+ assert head.number_of_samples == nsamples
+ assert head.active_channels == nchannels
+ assert head.trajectory_dimensions == ntrajdims
def test_set_head():
@@ -63,28 +56,25 @@ def test_set_head():
acq.setHead(head)
- eq_(acq.data.shape, (nchannels, nsamples))
- eq_(acq.traj.shape, (nsamples, ntrajdims))
+ assert acq.data.shape == (nchannels, nsamples)
+ assert acq.traj.shape == (nsamples, ntrajdims)
def test_flags():
acq = ismrmrd.Acquisition()
for i in range(1, 65):
- assert not acq.is_flag_set(i), \
- "Expected flag {} to not be set.".format(i)
+ assert not acq.is_flag_set(i)
for i in range(1, 65):
acq.set_flag(i)
- assert acq.is_flag_set(i), \
- "Expected flag {} to be set.".format(i)
+ assert acq.is_flag_set(i)
for i in range(1, 65):
acq.clear_flag(i)
- assert not acq.is_flag_set(i), \
- "Expected flag {} to not be set.".format(i)
+ assert not acq.is_flag_set(i)
- eq_(acq.flags, 0)
+ assert acq.flags == 0
for i in range(1, 65):
acq.set_flag(i)
@@ -92,8 +82,7 @@ def test_flags():
acq.clear_all_flags()
for i in range(1, 65):
- assert not acq.is_flag_set(i), \
- "Expected flag {} to not be set.".format(i)
+ assert not acq.is_flag_set(i)
def test_clearing_unset_flag_does_not_set_other_flags():
@@ -108,7 +97,6 @@ def test_clearing_unset_flag_does_not_set_other_flags():
"Clearing an unset flag sets other flags."
-@nose.tools.with_setup()
def test_acquisition_equality_test_header_field():
a = common.create_random_acquisition(42)
b = common.create_random_acquisition(42)
@@ -120,7 +108,6 @@ def test_acquisition_equality_test_header_field():
assert a != b
-@nose.tools.with_setup()
def test_acquisition_equality_test_header_array():
a = common.create_random_acquisition(42)
b = common.create_random_acquisition(42)
@@ -132,22 +119,17 @@ def test_acquisition_equality_test_header_array():
assert a != b
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_initialization_from_array():
-
nchannels = 32
nsamples = 256
data = common.create_random_data((nchannels, nsamples))
acquisition = ismrmrd.Acquisition.from_array(data)
- assert np.array_equal(acquisition.data, data), \
- "Acquisition data does not match data used to initialize acquisition."
+ assert np.array_equal(acquisition.data, data)
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_initialization_from_arrays():
-
nchannels = 32
nsamples = 256
trajectory_dimensions = 2
@@ -157,25 +139,18 @@ def test_initialization_from_arrays():
acquisition = ismrmrd.Acquisition.from_array(data, trajectory)
- assert np.array_equal(acquisition.data, data), \
- "Acquisition data does not match data used to initialize acquisition."
-
- assert np.array_equal(acquisition.traj, trajectory), \
- "Acquisition trajectory does not match trajectory used to initialize acquisition."
+ assert np.array_equal(acquisition.data, data)
+ assert np.array_equal(acquisition.traj, trajectory)
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_initialization_sets_nonzero_version():
-
acquisition = ismrmrd.Acquisition.from_array(common.create_random_data())
assert acquisition.version != 0, \
"Default acquisition version should not be zero."
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_initialization_with_header_fields():
-
fields = {
'version': 2,
'measurement_uid': 123456789,
@@ -192,14 +167,12 @@ def test_initialization_with_header_fields():
getattr(acquisition, field))
-@nose.tools.raises(TypeError)
def test_initialization_with_illegal_header_value():
- ismrmrd.Acquisition.from_array(common.create_random_data(), version='Bad version')
+ with pytest.raises(TypeError):
+ ismrmrd.Acquisition.from_array(common.create_random_data(), version='Bad version')
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_serialize_and_deserialize():
-
acquisition = ismrmrd.Acquisition.from_array(common.create_random_data())
with io.BytesIO() as stream:
@@ -213,9 +186,7 @@ def test_serialize_and_deserialize():
assert acquisition == deserialized_acquisition
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_to_and_from_bytes():
-
acquisition = ismrmrd.Acquisition.from_array(common.create_random_data())
deserialized_acquisition = ismrmrd.Acquisition.from_bytes(acquisition.to_bytes())
@@ -223,9 +194,7 @@ def test_to_and_from_bytes():
assert acquisition == deserialized_acquisition
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_serialization_with_header_fields():
-
properties = common.create_random_acquisition_properties()
data = common.create_random_data()
trajectory = common.create_random_trajectory()
@@ -236,8 +205,6 @@ def test_serialization_with_header_fields():
assert acquisition == deserialized_acquisition
-@nose.tools.raises(ValueError)
def test_deserialization_from_too_few_bytes():
- ismrmrd.Acquisition.from_bytes(b'')
-
-
+ with pytest.raises(ValueError):
+ ismrmrd.Acquisition.from_bytes(b'')
diff --git a/tests/test_common.py b/tests/test_common.py
index 2112572..aa95764 100644
--- a/tests/test_common.py
+++ b/tests/test_common.py
@@ -1,4 +1,3 @@
-
import ismrmrd
import numpy as np
@@ -7,15 +6,6 @@
import random
-def random_32bit_float():
- return numpy.random.rand(1).astype(np.float32)
-
-
-def seed_random_generators(seed=42):
- numpy.random.seed(seed)
- random.seed(seed)
-
-
def random_tuple(size, random_fn):
return tuple([random_fn() for _ in range(0, size)])
@@ -33,15 +23,15 @@ def create_random_acquisition_properties():
'discard_post': random.randint(0, 1 << 16),
'center_sample': random.randint(0, 1 << 16),
'encoding_space_ref': random.randint(0, 1 << 16),
- 'sample_time_us': random_32bit_float(),
- 'position': random_tuple(3, random_32bit_float),
- 'read_dir': random_tuple(3, random_32bit_float),
- 'phase_dir': random_tuple(3, random_32bit_float),
- 'slice_dir': random_tuple(3, random_32bit_float),
- 'patient_table_position': random_tuple(3, random_32bit_float),
+ 'sample_time_us': random.random(),
+ 'position': random_tuple(3, random.random),
+ 'read_dir': random_tuple(3, random.random),
+ 'phase_dir': random_tuple(3, random.random),
+ 'slice_dir': random_tuple(3, random.random),
+ 'patient_table_position': random_tuple(3, random.random),
'idx': ismrmrd.EncodingCounters(),
'user_int': random_tuple(8, lambda: random.randint(0, 1 << 31)),
- 'user_float': random_tuple(8, random_32bit_float)
+ 'user_float': random_tuple(8, random.random)
}
@@ -49,12 +39,12 @@ def create_random_image_properties():
return {
'flags': random.randint(0, 1 << 64),
'measurement_uid': random.randint(0, 1 << 32),
- 'field_of_view': random_tuple(3, random_32bit_float),
- 'position': random_tuple(3, random_32bit_float),
- 'read_dir': random_tuple(3, random_32bit_float),
- 'phase_dir': random_tuple(3, random_32bit_float),
- 'slice_dir': random_tuple(3, random_32bit_float),
- 'patient_table_position': random_tuple(3, random_32bit_float),
+ 'field_of_view': random_tuple(3, random.random),
+ 'position': random_tuple(3, random.random),
+ 'read_dir': random_tuple(3, random.random),
+ 'phase_dir': random_tuple(3, random.random),
+ 'slice_dir': random_tuple(3, random.random),
+ 'patient_table_position': random_tuple(3, random.random),
'average': random.randint(0, 1 << 16),
'slice': random.randint(0, 1 << 16),
'contrast': random.randint(0, 1 << 16),
@@ -66,7 +56,7 @@ def create_random_image_properties():
'image_index': random.randint(0, 1 << 16),
'image_series_index': random.randint(0, 1 << 16),
'user_int': random_tuple(8, lambda: random.randint(0, 1 << 31)),
- 'user_float': random_tuple(8, random_32bit_float),
+ 'user_float': random_tuple(8, random.random),
}
@@ -77,7 +67,7 @@ def create_random_waveform_properties():
'waveform_id': random.randint(0, 1 << 16),
'scan_counter': random.randint(0, 1 << 32),
'time_stamp': random.randint(0, 1 << 32),
- 'sample_time_us': random_32bit_float()
+ 'sample_time_us': random.random()
}
@@ -120,7 +110,7 @@ def create_random_image(seed=42):
header = create_random_image_properties()
image = ismrmrd.Image.from_array(data, **header)
- image.meta = {"Random attribute": random.randint(0,1000)}
+ image.meta = {"Random attribute": str(random.randint(0,1000))}
return image
@@ -135,3 +125,47 @@ def create_random_waveform(seed=42):
header = create_random_waveform_properties()
return ismrmrd.Waveform.from_array(data, **header)
+
+
+def compare_acquisitions(a, b):
+ assert type(a) == type(b)
+ assert a.data.shape == b.data.shape
+ assert np.allclose(a.data, b.data)
+ assert a.traj.shape == b.traj.shape
+ assert np.allclose(a.traj, b.traj)
+ for key in a.__dict__:
+ if key not in ['data', 'traj']:
+ aval = getattr(a, key)
+ bval = getattr(b, key)
+ if isinstance(aval, np.ndarray) and isinstance(bval, np.ndarray):
+ assert np.array_equal(aval, bval), f"Field '{key}' does not match: {aval} != {bval}"
+ else:
+ assert aval == bval, f"Field '{key}' does not match: {aval} != {bval}"
+
+
+def compare_images(a, b):
+ assert type(a) == type(b)
+ assert a.data.shape == b.data.shape
+ assert np.allclose(a.data, b.data)
+ for key in a.__dict__:
+ if key != 'data':
+ aval = getattr(a, key)
+ bval = getattr(b, key)
+ if isinstance(aval, np.ndarray) and isinstance(bval, np.ndarray):
+ assert np.array_equal(aval, bval), f"Field '{key}' does not match: {aval} != {bval}"
+ else:
+ assert aval == bval, f"Field '{key}' does not match: {aval} != {bval}"
+
+
+def compare_waveforms(a, b):
+ assert type(a) == type(b)
+ assert a.data.shape == b.data.shape
+ assert np.array_equal(a.data, b.data)
+ for key in a.__dict__:
+ if key != 'data':
+ aval = getattr(a, key)
+ bval = getattr(b, key)
+ if isinstance(aval, np.ndarray) and isinstance(bval, np.ndarray):
+ assert np.array_equal(aval, bval), f"Field '{key}' does not match: {aval} != {bval}"
+ else:
+ assert aval == bval, f"Field '{key}' does not match: {aval} != {bval}"
diff --git a/tests/test_file.py b/tests/test_file.py
index 9bbc8d4..c92f45f 100644
--- a/tests/test_file.py
+++ b/tests/test_file.py
@@ -1,392 +1,264 @@
import ismrmrd
-
-import nose.tools
-
import shutil
import os.path
import tempfile
-
import numpy
-
+import pytest
from test_common import *
-temp_dir = None
-
-
-def create_temp_dir():
+@pytest.fixture(autouse=True)
+def temp_dir_fixture():
global temp_dir
temp_dir = tempfile.mkdtemp(prefix='ismrmrd-python-', suffix='-test')
-
-
-def delete_temp_dir():
+ yield
shutil.rmtree(temp_dir, ignore_errors=True)
-
def random_acquisitions(n):
yield from (create_random_acquisition(i) for i in range(n))
-
def random_waveforms(n):
yield from (create_random_waveform(i) for i in range(n))
-
def random_images(n):
yield from (create_random_image(i) for i in range(n))
-
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_returns_none_when_no_acquisitions_present():
-
filename = os.path.join(temp_dir, "acquisitions.h5")
acquisitions = list(random_acquisitions(10))
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
-
assert not dataset.has_acquisitions()
assert dataset.acquisitions is None
-
dataset.acquisitions = acquisitions
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
-
assert dataset.has_acquisitions()
assert not (dataset.acquisitions is None)
-
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_can_read_and_write_acquisitions():
-
filename = os.path.join(temp_dir, "acquisitions.h5")
acquisitions = list(random_acquisitions(10))
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
dataset.acquisitions = acquisitions
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
for a, b in zip(acquisitions, dataset.acquisitions):
assert a == b
-
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_can_delete_acquisitions():
-
filename = os.path.join(temp_dir, "acquisitions.h5")
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
-
assert dataset.acquisitions is None
del dataset.acquisitions
assert dataset.acquisitions is None
-
dataset.acquisitions = random_acquisitions(10)
-
assert not (dataset.acquisitions is None)
del dataset.acquisitions
assert dataset.acquisitions is None
-
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_can_access_random_acquisition():
-
filename = os.path.join(temp_dir, "acquisitions.h5")
acquisitions = list(random_acquisitions(256))
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
dataset.acquisitions = acquisitions
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
assert acquisitions[255] == dataset.acquisitions[255]
-
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_can_access_random_acquisition_slice():
-
filename = os.path.join(temp_dir, "acquisitions.h5")
acquisitions = list(random_acquisitions(256))
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
dataset.acquisitions = acquisitions
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
-
for a, b in zip(acquisitions[250:255], dataset.acquisitions[250:255]):
assert a == b
-
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_can_write_random_acquisition():
-
filename = os.path.join(temp_dir, "acquisitions.h5")
acquisitions = list(random_acquisitions(256))
acquisition = create_random_acquisition()
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
dataset.acquisitions = acquisitions
dataset.acquisitions[200] = acquisition
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
assert acquisition == dataset.acquisitions[200]
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_can_append_acquisitions():
-
filename = os.path.join(temp_dir, "acquisitions.h5")
acquisitions = list(random_acquisitions(10))
acquisitions2 = list(random_acquisitions(10))
acquisition3 = next(random_acquisitions(1))
-
combined = acquisitions + acquisitions2 + [acquisition3]
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
dataset.acquisitions = acquisitions
dataset.acquisitions.extend(acquisitions2)
dataset.acquisitions.append(acquisition3)
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
for a, b in zip(combined, dataset.acquisitions):
assert a == b
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_can_write_random_acquisition_slice():
-
filename = os.path.join(temp_dir, "acquisitions.h5")
acquisitions = list(random_acquisitions(256))
slice = list(random_acquisitions(3))
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
dataset.acquisitions = acquisitions
dataset.acquisitions[150:153] = slice
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
-
for a, b in zip(slice, dataset.acquisitions[150:153]):
assert a == b
-
-@nose.tools.raises(TypeError)
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_cannot_write_mismatched_slice():
-
filename = os.path.join(temp_dir, "acquisitions.h5")
acquisitions = list(random_acquisitions(256))
slice = list(random_acquisitions(3))
+ with pytest.raises(TypeError):
+ with ismrmrd.File(filename) as file:
+ dataset = file['dataset']
+ dataset.acquisitions = acquisitions
+ dataset.acquisitions[150:155] = slice
- with ismrmrd.File(filename) as file:
- dataset = file['dataset']
- dataset.acquisitions = acquisitions
- dataset.acquisitions[150:155] = slice
-
-
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_can_read_and_write_waveforms():
-
filename = os.path.join(temp_dir, "waveforms.h5")
waveforms = list(random_waveforms(10))
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
dataset.waveforms = waveforms
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
for a, b in zip(waveforms, dataset.waveforms):
assert a == b
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_can_append_waveforms():
-
filename = os.path.join(temp_dir, "waveforms.h5")
waveforms = list(random_waveforms(10))
waveforms2 = list(random_waveforms(10))
waveform3 = next(random_waveforms(1))
-
combined = waveforms + waveforms2 + [waveform3]
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
dataset.waveforms = waveforms
dataset.waveforms.extend(waveforms2)
dataset.waveforms.append(waveform3)
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
for a, b in zip(combined, dataset.waveforms):
assert a == b
-
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_can_read_and_write_images():
-
filename = os.path.join(temp_dir, "images.h5")
images = list(random_images(10))
-
with ismrmrd.File(filename) as file:
imageset = file['dataset/image_1']
imageset.images = images
-
with ismrmrd.File(filename) as file:
imageset = file['dataset/image_1']
for a, b in zip(images, imageset.images):
assert a == b
-
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_can_read_random_image():
-
filename = os.path.join(temp_dir, "images.h5")
images = list(random_images(10))
-
with ismrmrd.File(filename) as file:
imageset = file['dataset/image_1']
imageset.images = images
-
with ismrmrd.File(filename) as file:
imageset = file['dataset/image_1']
-
assert images[8] == imageset.images[8]
-
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_can_write_random_image():
-
filename = os.path.join(temp_dir, "images.h5")
image = create_random_image()
-
with ismrmrd.File(filename) as file:
imageset = file['dataset/image_1']
imageset.images = random_images(10)
imageset.images[6] = image
-
with ismrmrd.File(filename) as file:
imageset = file['dataset/image_1']
-
assert image == imageset.images[6]
-
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_can_read_image_slice():
-
filename = os.path.join(temp_dir, "images.h5")
images = list(random_images(10))
-
with ismrmrd.File(filename) as file:
imageset = file['dataset/image_1']
imageset.images = images
-
with ismrmrd.File(filename) as file:
imageset = file['dataset/image_1']
for a, b in zip(images[5:10], imageset.images[5:10]):
assert a == b
-
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_can_write_image_slice():
-
filename = os.path.join(temp_dir, "images.h5")
images = list(random_images(10))
-
with ismrmrd.File(filename) as file:
imageset = file['dataset/image_1']
imageset.images = random_images(32)
imageset.images[5:15] = images
-
with ismrmrd.File(filename) as file:
imageset = file['dataset/image_1']
-
for a, b in zip(images, imageset.images[5:15]):
assert a == b
-
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_can_list_contained_images():
-
filename = os.path.join(temp_dir, "find_file.h5")
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
dataset.acquisitions = random_acquisitions(10)
-
imageset = file['dataset/image_1']
imageset.images = random_images(1)
-
imageset = file['dataset/image_2']
imageset.images = random_images(2)
-
imageset = file['dataset/nested/image_3']
imageset.images = [create_random_image(3)]
-
with ismrmrd.File(filename) as file:
assert(file.find_images() == {'dataset/image_1', 'dataset/image_2', 'dataset/nested/image_3'})
assert(file.find_data() == {'dataset'})
-
-
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_can_list_keys():
-
filename = os.path.join(temp_dir, "keys.h5")
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
dataset.acquisitions = random_acquisitions(10)
-
-
dataset2 = file['dataset2']
dataset2.acquisitions = random_acquisitions(10)
-
with ismrmrd.File(filename) as file:
assert(file.keys() == {'dataset', 'dataset2' })
-@nose.tools.raises(TypeError)
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_cannot_write_image_on_data():
-
filename = os.path.join(temp_dir, "file.h5")
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
dataset.acquisitions = random_acquisitions(10)
+ with pytest.raises(TypeError):
+ with ismrmrd.File(filename) as file:
+ dataset = file['dataset']
+ dataset.images = random_images(1)
- with ismrmrd.File(filename) as file:
- dataset = file['dataset']
- dataset.images = random_images(1)
-
-
-@nose.tools.raises(TypeError)
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_cannot_write_data_on_image():
-
filename = os.path.join(temp_dir, "file.h5")
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
dataset.images = random_images(1)
+ with pytest.raises(TypeError):
+ with ismrmrd.File(filename) as file:
+ dataset = file['dataset']
+ dataset.acquisitions = random_acquisitions(10)
- with ismrmrd.File(filename) as file:
- dataset = file['dataset']
- dataset.acquisitions = random_acquisitions(10)
-
-
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_can_rewrite_data_and_images():
-
filename = os.path.join(temp_dir, "file.h5")
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
dataset.acquisitions = random_acquisitions(20)
@@ -394,14 +266,12 @@ def test_file_can_rewrite_data_and_images():
dataset.waveforms = random_waveforms(10)
dataset.waveforms = random_waveforms(5)
dataset.acquisitions = random_acquisitions(5)
-
with ismrmrd.File(filename) as file:
imageset = file['dataset/images']
imageset.images = random_images(1)
imageset.images = random_images(2)
imageset.images = random_images(3)
-
example_header = """
@@ -439,17 +309,12 @@ def test_file_can_rewrite_data_and_images():
"""
-
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_file_can_read_and_write_headers():
-
filename = os.path.join(temp_dir, "file.h5")
header = ismrmrd.xsd.CreateFromDocument(example_header)
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
dataset.header = header
-
with ismrmrd.File(filename) as file:
dataset = file['dataset']
assert ismrmrd.xsd.ToXML(header) == ismrmrd.xsd.ToXML(dataset.header)
diff --git a/tests/test_hdf5.py b/tests/test_hdf5.py
index 8117fdc..ed96fa9 100644
--- a/tests/test_hdf5.py
+++ b/tests/test_hdf5.py
@@ -1,8 +1,5 @@
-
-
import ismrmrd
-
-import nose.tools
+import pytest
import random
import numpy.random
@@ -16,24 +13,19 @@
from test_common import *
-temp_dir = None
-
-
-def create_temp_dir():
+@pytest.fixture(autouse=True)
+def temp_dir_fixture():
global temp_dir
temp_dir = tempfile.mkdtemp(prefix='ismrmrd-python-', suffix='-test')
-
-
-def delete_temp_dir():
+ yield
shutil.rmtree(temp_dir, ignore_errors=True)
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_open_fresh_hdf5():
filename = os.path.join(temp_dir, 'open_fresh.h5')
ismrmrd.Dataset(filename)
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
+
def test_hdf5_fileinfo():
filename = os.path.join(temp_dir, 'stuff.h5')
@@ -43,10 +35,9 @@ def test_hdf5_fileinfo():
other_dataset = ismrmrd.Dataset(filename, 'other_dataset')
other_dataset.append_acquisition(create_random_acquisition())
- assert(ismrmrd.hdf5.fileinfo(filename) == ['dataset', 'other_dataset'])
+ assert ismrmrd.hdf5.fileinfo(filename) == ['dataset', 'other_dataset']
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_read_and_write_acquisitions_to_hdf5():
filename = os.path.join(temp_dir, 'read_write_acquisitions.h5')
@@ -64,10 +55,10 @@ def test_read_and_write_acquisitions_to_hdf5():
read_acquisitions = [dataset.read_acquisition(i) for i in range(0, nacquisitions)]
- map(lambda acq_a, acq_b: compare_acquisitions(acq_a, acq_b), acquisitions, read_acquisitions)
+ for acq_a, acq_b in zip(acquisitions, read_acquisitions):
+ compare_acquisitions(acq_a, acq_b)
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_read_and_write_images_to_hdf5():
filename = os.path.join(temp_dir, 'read_write_images.h5')
@@ -85,10 +76,10 @@ def test_read_and_write_images_to_hdf5():
read_images = [dataset.read_image('images', i) for i in range(0, nimages)]
- map(lambda img_a, img_b: compare_images(img_a, img_b), images, read_images)
+ for img_a, img_b in zip(images, read_images):
+ compare_images(img_a, img_b)
-@nose.tools.with_setup(create_temp_dir, delete_temp_dir)
def test_read_and_write_waveforms_to_hdf5():
filename = os.path.join(temp_dir, 'read_write_waveforms.h5')
@@ -106,7 +97,9 @@ def test_read_and_write_waveforms_to_hdf5():
read_waveforms = [dataset.read_waveform(i) for i in range(0, nwaveforms)]
- map(lambda wav_a, wav_b: compare_waveforms(wav_a, wav_b), waveforms, read_waveforms)
+ for wav_a, wav_b in zip(waveforms, read_waveforms):
+ compare_waveforms(wav_a, wav_b)
+
def test_waveform_hdf5_size():
assert ismrmrd.hdf5.waveform_header_dtype.itemsize == 40
diff --git a/tests/test_image.py b/tests/test_image.py
index c16f5fa..17ae87e 100644
--- a/tests/test_image.py
+++ b/tests/test_image.py
@@ -4,9 +4,7 @@
import ctypes
import numpy as np
import io
-
-import nose.tools
-from nose.tools import eq_
+import pytest
import test_common as common
@@ -17,10 +15,10 @@ def test_header():
def test_new_instance():
img = ismrmrd.Image()
- eq_(type(img.getHead()), ismrmrd.ImageHeader)
- eq_(img.getHead().data_type, ismrmrd.DATATYPE_CXFLOAT)
- eq_(type(img.data), np.ndarray)
- eq_(img.data.dtype, np.complex64)
+ assert type(img.getHead()) == ismrmrd.ImageHeader
+ assert img.getHead().data_type == ismrmrd.DATATYPE_CXFLOAT
+ assert type(img.data) == np.ndarray
+ assert img.data.dtype == np.complex64
attr = "\nrandoblah"
@@ -28,17 +26,13 @@ def test_new_instance():
head.attribute_string_len = len(attr) # must set attribute_string_len
head.data_type = ismrmrd.DATATYPE_CXFLOAT # must set data_type
img = ismrmrd.Image(head, attribute_string=attr)
- eq_(img.attribute_string, attr)
+ assert img.attribute_string == attr
def test_read_only_fields():
img = ismrmrd.Image()
for field in ['data_type', 'matrix_size', 'channels', 'attribute_string_len']:
- try:
+ with pytest.raises(AttributeError):
setattr(img, field, None)
- except AttributeError:
- pass
- else:
- raise Exception("Setting read-only attribute did not raise exception.")
def test_set_head():
@@ -53,164 +47,92 @@ def test_set_head():
img.setHead(head)
- eq_(img.data.shape, (nchan, nz, ny, nx))
- eq_(img.data_type, ismrmrd.DATATYPE_CXDOUBLE)
- eq_(img.data.dtype, np.complex128)
+ assert img.data.shape == (nchan, nz, ny, nx)
+ assert img.data_type == ismrmrd.DATATYPE_CXDOUBLE
+ assert img.data.dtype == np.complex128
def test_resize():
pass
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_initialization_sets_nonzero_version():
-
image = ismrmrd.Image.from_array(common.create_random_array((128, 128), dtype=np.float32))
+ assert image.version != 0
- assert image.version != 0, \
- "Default image version should not be zero."
-
-
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_initialization_with_array():
-
image_data = common.create_random_array((256, 128), dtype=np.float32)
image = ismrmrd.Image.from_array(image_data)
+ assert np.array_equal(image_data.transpose(), image.data.squeeze())
- assert np.array_equal(image_data.transpose(), image.data.squeeze()), \
- "Image data does not match data used to initialize image."
-
-
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_initialization_with_array_and_acquisition():
-
acquisition = common.create_random_acquisition()
-
image_data = common.create_random_array((256, 128), dtype=np.float32)
image = ismrmrd.Image.from_array(image_data, acquisition=acquisition)
+ assert np.array_equal(image_data.transpose(), image.data.squeeze())
+ for field in ['version', 'measurement_uid', 'position', 'read_dir', 'phase_dir', 'slice_dir', 'patient_table_position', 'acquisition_time_stamp', 'physiology_time_stamp']:
+ assert bytes(getattr(acquisition, field)) == bytes(getattr(image, field))
- assert np.array_equal(image_data.transpose(), image.data.squeeze()), \
- "Image data does not match data used to initialize image."
-
- for field in ['version',
- 'measurement_uid',
- 'position',
- 'read_dir',
- 'phase_dir',
- 'slice_dir',
- 'patient_table_position',
- 'acquisition_time_stamp',
- 'physiology_time_stamp']:
-
- assert bytes(getattr(acquisition, field)) == bytes(getattr(image, field)), \
- "Acquisition header field not copied to image."
-
-
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_initialization_with_array_and_header_properties():
-
properties = common.create_random_image_properties()
image_data = common.create_random_array((256, 512), dtype=np.float32)
-
image = ismrmrd.Image.from_array(image_data, **properties)
-
for field in properties:
- try:
- assert all(map(lambda a, b: a == b,
- properties.get(field),
- getattr(image, field))), \
- "Image property doesn't match initialization value: " + field
- except TypeError:
- assert properties.get(field) == getattr(image, field), \
- "Image property doesn't match initialization value: " + field
-
+ expected = properties.get(field)
+ actual = getattr(image, field)
+ # If both are sequences and contain floats, use np.allclose
+ if isinstance(expected, (tuple, list)) and hasattr(actual, '__len__') and len(expected) == len(actual):
+ try:
+ expected_arr = np.array(expected, dtype=float)
+ actual_arr = np.array(actual, dtype=float)
+ assert np.allclose(expected_arr, actual_arr), f"Field '{field}' does not match: {expected_arr} != {actual_arr}"
+ except Exception:
+ for i, (a, b) in enumerate(zip(expected, actual)):
+ assert a == b, f"Field '{field}' index {i} does not match: {a} != {b}"
+ else:
+ assert expected == actual, f"Field '{field}' does not match: {expected} != {actual}"
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_initialization_with_2d_image():
-
image_data = common.create_random_array((128, 64), dtype=np.float32)
image = ismrmrd.Image.from_array(image_data)
+ assert np.array_equal(image_data.transpose(), image.data.squeeze())
+ assert image.channels == 1
+ assert image.matrix_size == (1, 64, 128)
- assert np.array_equal(image_data.transpose(), image.data.squeeze()), \
- "Image data does not match data used to initialize image."
-
- assert image.channels == 1, \
- "Unexpected number of channels: {}".format(image.channels)
-
- assert image.matrix_size == (1, 64, 128), \
- "Unexpected matrix size: {}".format(image.matrix_size)
-
-
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_initialization_with_3d_image():
-
image_data = common.create_random_array((128, 64, 32), dtype=np.float32)
image = ismrmrd.Image.from_array(image_data)
+ assert np.array_equal(image_data.transpose(), image.data.squeeze())
+ assert image.channels == 1
+ assert image.matrix_size == (32, 64, 128)
- assert np.array_equal(image_data.transpose(), image.data.squeeze()), \
- "Image data does not match data used to initialize image."
-
- assert image.channels == 1, \
- "Unexpected number of channels: {}".format(image.channels)
-
- assert image.matrix_size == (32, 64, 128), \
- "Unexpected matrix size: {}".format(image.matrix_size)
-
-
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_initialization_with_3d_image_and_channels():
-
image_data = common.create_random_array((128, 64, 32, 16), dtype=np.float32)
image = ismrmrd.Image.from_array(image_data)
+ assert np.array_equal(image_data.transpose(), image.data.squeeze())
+ assert image.channels == 16
+ assert image.matrix_size == (32, 64, 128)
- assert np.array_equal(image_data.transpose(), image.data.squeeze()), \
- "Image data does not match data used to initialize image."
-
- assert image.channels == 16, \
- "Unexpected number of channels: {}".format(image.channels)
-
- assert image.matrix_size == (32, 64, 128), \
- "Unexpected matrix size: {}".format(image.matrix_size)
-
-
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_serialize_and_deserialize():
-
image_data = common.create_random_array((128, 128), dtype=np.float32)
image = ismrmrd.Image.from_array(image_data)
-
with io.BytesIO(b'') as stream:
image.serialize_into(stream.write)
-
stream.seek(0)
-
read_image = ismrmrd.Image.deserialize_from(stream.read)
-
assert image == read_image
-
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_to_and_from_bytes():
-
image_data = common.create_random_array((128, 128), dtype=np.float32)
image = ismrmrd.Image.from_array(image_data)
-
read_image = ismrmrd.Image.from_bytes(image.to_bytes())
-
assert image == read_image
-
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_serialization_with_header_fields():
-
image_data = common.create_random_array((128, 128), dtype=np.float32)
image = ismrmrd.Image.from_array(image_data, **common.create_random_image_properties())
-
read_image = ismrmrd.Image.from_bytes(image.to_bytes())
-
assert image == read_image
-
-@nose.tools.raises(ValueError)
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_serialization_from_too_few_bytes():
- ismrmrd.Image.from_bytes(b'')
+ with pytest.raises(ValueError):
+ ismrmrd.Image.from_bytes(b'')
diff --git a/tests/test_waveform.py b/tests/test_waveform.py
index 9e25234..b0a04d0 100644
--- a/tests/test_waveform.py
+++ b/tests/test_waveform.py
@@ -1,19 +1,14 @@
-
import ismrmrd
import ctypes
-
import numpy as np
import numpy.random
-
import io
-
-import nose.tools
+import pytest
import test_common as common
-@nose.tools.with_setup(setup=common.seed_random_generators)
-def test_initialization_from_array():
+def test_initialization_from_array():
nchannels = 32
nsamples = 256
@@ -25,38 +20,38 @@ def test_initialization_from_array():
"Waveform data does not match data used to initialize waveform."
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_initialization_sets_nonzero_version():
-
waveform = common.create_random_waveform()
assert waveform.version != 0, \
"Default acquisition version should not be zero."
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_initialization_with_header_fields():
-
fields = common.create_random_waveform_properties()
waveform = ismrmrd.Waveform.from_array(common.create_random_waveform_data(), **fields)
for field in fields:
- assert fields.get(field) == getattr(waveform, field), \
- "Field {} not preserved by waveform. ({} != {})".format(field,
- fields.get(field),
- getattr(waveform, field))
+ expected = fields.get(field)
+ actual = getattr(waveform, field)
+ # Use np.isclose for scalar float comparison
+ if isinstance(expected, float) or isinstance(actual, float):
+ assert np.isclose(float(expected), float(actual)), f"Field '{field}' does not match: {expected} != {actual}"
+ elif isinstance(expected, (tuple, list)) and hasattr(actual, '__len__') and len(expected) == len(actual):
+ for i, (a, b) in enumerate(zip(expected, actual)):
+ assert a == b, f"Field '{field}' index {i} does not match: {a} != {b}"
+ else:
+ assert expected == actual, f"Field '{field}' does not match: {expected} != {actual}"
-@nose.tools.raises(TypeError)
def test_initialization_with_illegal_header_value():
- ismrmrd.Waveform.from_array(common.create_random_waveform_data(), version='Bad version')
+ with pytest.raises(TypeError):
+ ismrmrd.Waveform.from_array(common.create_random_waveform_data(), version='Bad version')
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_serialize_and_deserialize():
-
waveform = common.create_random_waveform()
with io.BytesIO() as stream:
@@ -70,9 +65,7 @@ def test_serialize_and_deserialize():
assert waveform == deserialized_waveform
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_to_and_from_bytes():
-
waveform = common.create_random_waveform()
deserialized_waveform = ismrmrd.Waveform.from_bytes(waveform.to_bytes())
@@ -80,9 +73,7 @@ def test_to_and_from_bytes():
assert waveform == deserialized_waveform
-@nose.tools.with_setup(setup=common.seed_random_generators)
def test_serialization_with_header_fields():
-
properties = common.create_random_waveform_properties()
data = common.create_random_waveform_data()
@@ -92,9 +83,9 @@ def test_serialization_with_header_fields():
assert waveform == deserialized_waveform
-@nose.tools.raises(ValueError)
def test_deserialization_from_too_few_bytes():
- ismrmrd.Acquisition.from_bytes(b'')
+ with pytest.raises(ValueError):
+ ismrmrd.Acquisition.from_bytes(b'')
def test_waveformheader_size():