diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index b3e73ac8c8..a872f9dce0 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -30,7 +30,7 @@ implementation of methods, on finding technical solutions, establishing best pra otherwise. We are accepting of all who wish to take part in our activities, fostering an environment where anyone can participate and everyone can make a difference. -#### Be collaborative! +#### Collaborative Our work will be used by other people, and in turn we will depend on the work of others. When we make something for the benefit of others, we are willing to explain to others how it works, so that @@ -38,7 +38,7 @@ they can build on the work to make it even better. We are willing to provide con on the work of others and accept criticism of our own work, as the experiences and skill sets of other members contribute to the whole of our efforts. -#### Be inquisitive! +#### Inquisitive Nobody knows everything! Asking questions early avoids many problems later, so questions are encouraged, though they may be directed to the appropriate forum. Those who are asked should be @@ -51,7 +51,7 @@ efforts of others, keeping in mind that often-times the labor was completed simp the community. We are attentive in our communications, whether in person or online, and we are tactful when approaching differing views. -#### Be careful in the words that you choose: +#### Careful in the words we choose We value courtesy, kindness and inclusiveness in all our interactions. Therefore, we take responsibility for our own speech. In particular, we avoid: @@ -66,7 +66,7 @@ responsibility for our own speech. In particular, we avoid: * Repeated harassment of others. In general, if someone asks you to stop, then stop. * Advocating for, or encouraging, any of the above behaviour. -#### Try to be concise in communication +#### Concise Keep in mind that what you write once will be read by many others. Writing a short email means people can understand the conversation as efficiently as possible. Even short emails should always diff --git a/.mailmap b/.mailmap index d7f7b6f4f3..f1a7753360 100644 --- a/.mailmap +++ b/.mailmap @@ -26,7 +26,8 @@ Christopher J. Markiewicz Christopher J. Markiewicz CindeeM Cindee Madison cindeem Demian Wassermann Demian Wassermann -Dimitri Papadopoulos Orfanos Dimitri Papadopoulos +Dimitri Papadopoulos Orfanos +Dimitri Papadopoulos Orfanos <3234522+DimitriPapadopoulos@users.noreply.github.com> Eric Larson Eric89GXL Eric Larson larsoner Fernando Pérez-García Fernando diff --git a/.zenodo.json b/.zenodo.json index a53025928c..572f05d12e 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -141,10 +141,10 @@ "orcid": "0000-0001-9791-4404" }, { - "name": "Lepp\u00e4kangas, Jaakko" + "name": "S\u00f3lon, Anibal" }, { - "name": "S\u00f3lon, Anibal" + "name": "Lepp\u00e4kangas, Jaakko" }, { "name": "van den Bosch, Jasper J.F." @@ -228,6 +228,11 @@ { "name": "St-Jean, Samuel" }, + { + "affiliation": "CEA", + "name": "Papadopoulos Orfanos, Dimitri", + "orcid": "0000-0002-1242-8990" + }, { "name": "Panfilov, Egor", "orcid": "0000-0002-2500-6375" @@ -286,6 +291,9 @@ { "name": "Baratz, Zvi" }, + { + "name": "Van, Andrew" + }, { "affiliation": "Hospital for Sick Children", "name": "Darwin, Benjamin C" @@ -298,11 +306,6 @@ { "name": "Gauthier, Carl" }, - { - "affiliation": "CEA", - "name": "Papadopoulos Orfanos, Dimitri", - "orcid": "0000-0002-1242-8990" - }, { "name": "Solovey, Igor" }, @@ -326,6 +329,11 @@ "affiliation": "National Technical University of Athens, Greece", "name": "Raktivan, Konstantinos" }, + { + "affiliation": "Charite Universitatsmedizin Berlin, Germany", + "name": "Waller, Lea", + "orcid": "0000-0002-3239-6957" + }, { "name": "Cal\u00e1bkov\u00e1, Mark\u00e9ta" }, @@ -346,6 +354,9 @@ { "name": "Roos, Thomas" }, + { + "name": "Hrn\u010diar, Tom\u00e1\u0161" + }, { "affiliation": "National Institute of Mental Health and Neuro-Sciences, India", "name": "Reddam, Venkateswara Reddy", diff --git a/Changelog b/Changelog index e352b52b44..3bcbb46a98 100644 --- a/Changelog +++ b/Changelog @@ -25,6 +25,36 @@ Eric Larson (EL), Demian Wassermann, Stephan Gerhard and Ross Markello (RM). References like "pr/298" refer to github pull request numbers. +3.2.2 (Monday 7 February 2022) +================================= + +Bug fix release in the 3.2.x series. + +Bug fixes +--------- +* Reshape CIFTI-2 affines to 4x4 when encoded as row-major sequence (pr/1059) + (Andrew Van, reviewed by CM) +* Suggest nibabel.save() on calls to deprecated giftiio.write() (pr/1055) + (Anibal Solon, reviewed by CM) +* Various bugs and style issues detected by LGTM (pr/1043, pr/1048) + (Dimitri Papadopoulos, reviewed by CM) +* Resolve unclosed file warning in GiftiImage (pr/1038) (Lea Waller, reviewed by CM) +* Fix typos preventing deprecation warnings from being raised (pr/991) + (Jonathan Daniel, reviewed by MB) +* Work around numpy SystemError to maintain expected error types (pr/1051) (CM) +* Use more constrained mock when testing optpkg (pr/983) (CM, reviewed by YOH) + +Maintenance +----------- +* Add setuptools requirement to match usage (pr/1009) + (Tomáš Hrnčiar, reviewed by CM) +* Fix grammar of headings in CoC (pr/996) (MB, reviewed by CM, Ariel Rokem) +* Set minimum pydicom to 1.0.0 (pr/1050) (CM) +* Submit coverage to codecov via pinned PyPI package (pr/1008) (CM) +* Upgrade versioneer to 0.19 (pr/967) (CM) +* Migrate to GitHub actions (pr/972) (CM, reviewed by Serge Koudoro) + + 3.2.1 (Saturday 28 November 2020) ================================= diff --git a/doc/source/conf.py b/doc/source/conf.py index 1fe335f63f..6155d0bc3b 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -92,7 +92,7 @@ # General information about the project. project = u'NiBabel' -copyright = f"2006-2020, {metadata['maintainer']} <{metadata['author_email']}>" +copyright = f"2006-2022, {metadata['maintainer']} <{metadata['author_email']}>" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/doc/source/index.rst b/doc/source/index.rst index 1bbc0baf15..4e1821cae8 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -114,6 +114,9 @@ contributed code and discussion (in rough order of appearance): * Markéta Calábková * Carl Gauthier * Julian Klug +* Lea Waller +* Tomáš Hrnčiar +* Andrew Van License reprise =============== diff --git a/min-requirements.txt b/min-requirements.txt index 811270d582..a78a74b00e 100644 --- a/min-requirements.txt +++ b/min-requirements.txt @@ -1,3 +1,4 @@ # Auto-generated by tools/update_requirements.py numpy ==1.14 packaging ==14.3 +setuptools diff --git a/nibabel/cifti2/cifti2.py b/nibabel/cifti2/cifti2.py index 0b2b7f2a9a..948fe0d0d0 100644 --- a/nibabel/cifti2/cifti2.py +++ b/nibabel/cifti2/cifti2.py @@ -1156,8 +1156,7 @@ def get_index_map(self, index): a2md = self._get_indices_from_mim(v) if index in a2md: return v - else: - raise Cifti2HeaderError("Index not mapped") + raise Cifti2HeaderError("Index not mapped") def _validate_new_mim(self, value): if value.applies_to_matrix_dimension is None: diff --git a/nibabel/cifti2/parse_cifti2.py b/nibabel/cifti2/parse_cifti2.py index 3257000856..4421632cea 100644 --- a/nibabel/cifti2/parse_cifti2.py +++ b/nibabel/cifti2/parse_cifti2.py @@ -538,7 +538,8 @@ def flush_chardata(self): # conversion to numpy array c = BytesIO(data.strip().encode('utf-8')) transform = self.struct_state[-1] - transform.matrix = np.loadtxt(c, dtype=np.float64) + matrix = np.loadtxt(c, dtype=np.float64) + transform.matrix = matrix.reshape(4, 4) c.close() elif self.write_to == 'Label': diff --git a/nibabel/cifti2/tests/test_cifti2io_header.py b/nibabel/cifti2/tests/test_cifti2io_header.py index df4fe10fcd..6d59dfd75b 100644 --- a/nibabel/cifti2/tests/test_cifti2io_header.py +++ b/nibabel/cifti2/tests/test_cifti2io_header.py @@ -41,6 +41,11 @@ datafiles = [DATA_FILE2, DATA_FILE3, DATA_FILE4, DATA_FILE5, DATA_FILE6] +def test_space_separated_affine(): + img = ci.Cifti2Image.from_filename( + pjoin(NIBABEL_TEST_DATA, "row_major.dconn.nii")) + + def test_read_nifti2(): # Error trying to read a CIFTI-2 image from a NIfTI2-only image. filemap = ci.Cifti2Image.make_file_map() diff --git a/nibabel/cmdline/dicomfs.py b/nibabel/cmdline/dicomfs.py index 6e53be103b..d4c9d8ff1f 100644 --- a/nibabel/cmdline/dicomfs.py +++ b/nibabel/cmdline/dicomfs.py @@ -71,7 +71,7 @@ def get_paths(self): for study in dft.get_studies(self.dicom_path, self.followlinks): pd = paths.setdefault(study.patient_name_or_uid(), {}) patient_info = 'patient information\n' - patient_info = f'name: {study.patient_name}\n' + patient_info += f'name: {study.patient_name}\n' patient_info += f'ID: {study.patient_id}\n' patient_info += f'birth date: {study.patient_birth_date}\n' patient_info += f'sex: {study.patient_sex}\n' @@ -172,9 +172,9 @@ def open(self, path, flags): elif isinstance(matched_path, tuple): self.fhs[i] = matched_path[1]() else: - raise -errno.EFTYPE + return -errno.EFTYPE return FileHandle(i) - raise -errno.ENFILE + return -errno.ENFILE # not done def read(self, path, size, offset, fh): diff --git a/nibabel/filebasedimages.py b/nibabel/filebasedimages.py index 006b70d615..4af36cb04f 100644 --- a/nibabel/filebasedimages.py +++ b/nibabel/filebasedimages.py @@ -202,7 +202,7 @@ def __init__(self, header=None, extra=None, file_map=None): def header(self): return self._header - def __getitem__(self): + def __getitem__(self, key): """ No slicing or dictionary interface for images """ raise TypeError("Cannot slice image objects.") diff --git a/nibabel/gifti/gifti.py b/nibabel/gifti/gifti.py index 0f509eaa9d..370e76e8f7 100644 --- a/nibabel/gifti/gifti.py +++ b/nibabel/gifti/gifti.py @@ -43,7 +43,7 @@ def from_dict(klass, data_dict): @deprecate_with_version( 'get_metadata method deprecated. ' - "Use the metadata property instead." + "Use the metadata property instead.", '2.1', '4.0') def get_metadata(self): return self.metadata @@ -155,7 +155,7 @@ def __init__(self, key=0, red=None, green=None, blue=None, alpha=None): @deprecate_with_version( 'get_rgba method deprecated. ' - "Use the rgba property instead." + "Use the rgba property instead.", '2.1', '4.0') def get_rgba(self): return self.rgba @@ -523,7 +523,7 @@ def print_summary(self): @deprecate_with_version( 'get_metadata method deprecated. ' - "Use the metadata property instead." + "Use the metadata property instead.", '2.1', '4.0') def get_metadata(self): return self.meta.metadata @@ -877,8 +877,8 @@ def to_file_map(self, file_map=None): """ if file_map is None: file_map = self.file_map - f = file_map['image'].get_prepare_fileobj('wb') - f.write(self.to_xml()) + with file_map['image'].get_prepare_fileobj('wb') as f: + f.write(self.to_xml()) @classmethod def from_file_map(klass, file_map, buffer_size=35000000): diff --git a/nibabel/gifti/giftiio.py b/nibabel/gifti/giftiio.py index 73c19450ad..46219e8c1d 100644 --- a/nibabel/gifti/giftiio.py +++ b/nibabel/gifti/giftiio.py @@ -34,7 +34,7 @@ def read(filename): @deprecate_with_version('giftiio.write function deprecated. ' - "Use nibabel.load() instead.", + "Use nibabel.save() instead.", '2.1', '4.0') def write(image, filename): """ Save the current image to a new file diff --git a/nibabel/gifti/tests/test_gifti.py b/nibabel/gifti/tests/test_gifti.py index 2d60482c59..ffdb113cf3 100644 --- a/nibabel/gifti/tests/test_gifti.py +++ b/nibabel/gifti/tests/test_gifti.py @@ -6,6 +6,8 @@ import numpy as np +from nibabel.tmpdirs import InTemporaryDirectory + from ... import load from .. import (GiftiImage, GiftiDataArray, GiftiLabel, GiftiLabelTable, GiftiMetaData, GiftiNVPairs, @@ -40,7 +42,7 @@ def test_agg_data(): assert_array_equal(surf_gii_img.agg_data('pointset'), point_data) assert_array_equal(surf_gii_img.agg_data('triangle'), triangle_data) - assert_array_equal(func_gii_img.agg_data('time series'), func_data) + assert_array_equal(func_gii_img.agg_data('time series'), func_data) assert_array_equal(shape_gii_img.agg_data('shape'), shape_data) assert surf_gii_img.agg_data('time series') == () @@ -443,3 +445,11 @@ def test_darray_dtype_coercion_failures(): da_copy = gii_copy.darrays[0] assert np.dtype(da_copy.data.dtype) == np.dtype(darray_dtype) assert_array_equal(da_copy.data, da.data) + + +def test_gifti_file_close(): + gii = load(test_data('gifti', 'ascii.gii')) + with pytest.WarningsRecorder() as record: + with InTemporaryDirectory(): + gii.to_filename('test.gii') + assert not any(isinstance(r.message, ResourceWarning) for r in record.list) diff --git a/nibabel/pydicom_compat.py b/nibabel/pydicom_compat.py index c0b2f57532..5f827e2bbf 100644 --- a/nibabel/pydicom_compat.py +++ b/nibabel/pydicom_compat.py @@ -23,7 +23,6 @@ # Module has (apparently) unused imports; stop flake8 complaining # flake8: noqa -import numpy as np from .deprecated import deprecate_with_version have_dicom = True diff --git a/nibabel/tests/data/row_major.dconn.nii b/nibabel/tests/data/row_major.dconn.nii new file mode 100644 index 0000000000..a2aa2afd1e Binary files /dev/null and b/nibabel/tests/data/row_major.dconn.nii differ diff --git a/nibabel/volumeutils.py b/nibabel/volumeutils.py index 7547a12b31..327706b626 100644 --- a/nibabel/volumeutils.py +++ b/nibabel/volumeutils.py @@ -1551,7 +1551,7 @@ class BinOpener(Opener): __doc__ = Opener.__doc__ @deprecate_with_version('BinOpener class deprecated. ' - "Please use Opener class instead." + "Please use Opener class instead.", '2.1', '4.0') def __init__(self, *args, **kwargs): return super(BinOpener, self).__init__(*args, **kwargs) diff --git a/nisext/py3builder.py b/nisext/py3builder.py index 4f82a8cfb2..7bcaf2348c 100644 --- a/nisext/py3builder.py +++ b/nisext/py3builder.py @@ -1,9 +1,6 @@ """ distutils utilities for porting to python 3 within 2-compatible tree """ -import sys -import re - try: from distutils.command.build_py import build_py_2to3 except ImportError: diff --git a/requirements.txt b/requirements.txt index 06e3bf4989..6d8b066ad2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ # Auto-generated by tools/update_requirements.py numpy >=1.14 packaging >=14.3 +setuptools diff --git a/setup.cfg b/setup.cfg index a8bb725a6f..b88ca8702a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -32,6 +32,7 @@ python_requires = >=3.6 install_requires = numpy >=1.14 packaging >=14.3 + setuptools zip_safe = False packages = find: @@ -58,6 +59,7 @@ style = test = coverage pytest !=5.3.4 + pytest <7 ; python_version == "3.6" pytest-cov pytest-doctestplus !=0.9.0 all = diff --git a/setup.py b/setup.py index 9c281a032c..29fb3642da 100755 --- a/setup.py +++ b/setup.py @@ -10,7 +10,6 @@ """Build helper.""" import sys -import os from setuptools import setup import versioneer diff --git a/tools/make_tarball.py b/tools/make_tarball.py index 149837aaf5..afbde3d48d 100755 --- a/tools/make_tarball.py +++ b/tools/make_tarball.py @@ -4,8 +4,6 @@ import commands import os -import sys -import shutil from toollib import * diff --git a/tools/mpkg_wrapper.py b/tools/mpkg_wrapper.py index ad956696c8..17f39041dc 100644 --- a/tools/mpkg_wrapper.py +++ b/tools/mpkg_wrapper.py @@ -16,8 +16,6 @@ __docformat__ = 'restructuredtext' import sys -import setuptools -import bdist_mpkg def main(): del sys.argv[0]