diff --git a/doc/tools/apigen.py b/doc/tools/apigen.py index 336c81d8d..23fb6ff07 100644 --- a/doc/tools/apigen.py +++ b/doc/tools/apigen.py @@ -32,7 +32,7 @@ class ApiDocWriter: to Sphinx-parsable reST format""" # only separating first two levels - rst_section_levels = ['*', '=', '-', '~', '^'] + rst_section_levels = ('*', '=', '-', '~', '^') def __init__( self, diff --git a/nibabel/analyze.py b/nibabel/analyze.py index d02363c79..77ddbe30c 100644 --- a/nibabel/analyze.py +++ b/nibabel/analyze.py @@ -84,6 +84,8 @@ from __future__ import annotations +import typing as ty + import numpy as np from .arrayproxy import ArrayProxy @@ -92,6 +94,7 @@ from .fileholders import copy_file_map from .spatialimages import HeaderDataError, HeaderTypeError, SpatialHeader, SpatialImage from .volumeutils import ( + Recoder, apply_read_scaling, array_from_file, make_dt_codes, @@ -185,7 +188,7 @@ class AnalyzeHeader(LabeledWrapStruct, SpatialHeader): template_dtype = header_dtype _data_type_codes = data_type_codes # fields with recoders for their values - _field_recoders = {'datatype': data_type_codes} + _field_recoders: ty.ClassVar[dict[str, Recoder]] = {'datatype': data_type_codes} # default x flip default_x_flip = True diff --git a/nibabel/cifti2/cifti2.py b/nibabel/cifti2/cifti2.py index b2b67978b..3f3439ea4 100644 --- a/nibabel/cifti2/cifti2.py +++ b/nibabel/cifti2/cifti2.py @@ -1045,14 +1045,6 @@ class Cifti2MatrixIndicesMap(xml.XmlSerializable, MutableSequence): If it is a series, units """ - _valid_type_mappings_ = { - Cifti2BrainModel: ('CIFTI_INDEX_TYPE_BRAIN_MODELS',), - Cifti2Parcel: ('CIFTI_INDEX_TYPE_PARCELS',), - Cifti2NamedMap: ('CIFTI_INDEX_TYPE_LABELS',), - Cifti2Volume: ('CIFTI_INDEX_TYPE_SCALARS', 'CIFTI_INDEX_TYPE_SERIES'), - Cifti2Surface: ('CIFTI_INDEX_TYPE_SCALARS', 'CIFTI_INDEX_TYPE_SERIES'), - } - def __init__( self, applies_to_matrix_dimension, diff --git a/nibabel/cifti2/cifti2_axes.py b/nibabel/cifti2/cifti2_axes.py index 32914be1b..0ee6dc055 100644 --- a/nibabel/cifti2/cifti2_axes.py +++ b/nibabel/cifti2/cifti2_axes.py @@ -634,8 +634,8 @@ def __eq__(self, other): return ( ( self.affine is None - or np.allclose(self.affine, other.affine) - and self.volume_shape == other.volume_shape + or (np.allclose(self.affine, other.affine) + and self.volume_shape == other.volume_shape) ) and self.nvertices == other.nvertices and np.array_equal(self.name, other.name) diff --git a/nibabel/cmdline/dicomfs.py b/nibabel/cmdline/dicomfs.py index 07aa51e2d..ae81940a1 100644 --- a/nibabel/cmdline/dicomfs.py +++ b/nibabel/cmdline/dicomfs.py @@ -231,7 +231,7 @@ def main(args=None): if opts.verbose: logger.addHandler(logging.StreamHandler(sys.stdout)) - logger.setLevel(opts.verbose > 1 and logging.DEBUG or logging.INFO) + logger.setLevel(logging.DEBUG if opts.verbose > 1 else logging.INFO) if len(files) != 2: sys.stderr.write(f'Please provide two arguments:\n{parser.usage}\n') diff --git a/nibabel/minc1.py b/nibabel/minc1.py index d0b9fd537..2d44736a2 100644 --- a/nibabel/minc1.py +++ b/nibabel/minc1.py @@ -80,7 +80,7 @@ def get_data_dtype(self): dtt = np.dtype(np.float64) else: signtype = self._image.signtype.decode('latin-1') - dtt = _dt_dict[(typecode, signtype)] + dtt = _dt_dict[typecode, signtype] return np.dtype(dtt).newbyteorder('>') def get_data_shape(self): diff --git a/nibabel/nicom/csareader.py b/nibabel/nicom/csareader.py index b98dae740..4982be834 100644 --- a/nibabel/nicom/csareader.py +++ b/nibabel/nicom/csareader.py @@ -63,7 +63,7 @@ def get_csa_header(dcm_data, csa_type='image'): return None element_no = section_start + element_offset try: - tag = dcm_data[(0x29, element_no)] + tag = dcm_data[0x29, element_no] except KeyError: # The element could be missing due to anonymization return None diff --git a/nibabel/nicom/tests/test_csareader.py b/nibabel/nicom/tests/test_csareader.py index f31f4a393..f43bf4ba2 100644 --- a/nibabel/nicom/tests/test_csareader.py +++ b/nibabel/nicom/tests/test_csareader.py @@ -35,7 +35,7 @@ def test_csa_header_read(): data2.add(element) assert csa.get_csa_header(data2, 'image') is None # Add back the marker - CSA works again - data2[(0x29, 0x10)] = DATA[(0x29, 0x10)] + data2[0x29, 0x10] = DATA[0x29, 0x10] assert csa.is_mosaic(csa.get_csa_header(data2, 'image')) diff --git a/nibabel/nifti1.py b/nibabel/nifti1.py index f0bd91fc4..7cbe91d92 100644 --- a/nibabel/nifti1.py +++ b/nibabel/nifti1.py @@ -811,7 +811,7 @@ class Nifti1Header(SpmAnalyzeHeader): _data_type_codes = data_type_codes # fields with recoders for their values - _field_recoders = { + _field_recoders: ty.ClassVar[dict[str, Recoder]] = { 'datatype': data_type_codes, 'qform_code': xform_codes, 'sform_code': xform_codes, diff --git a/nibabel/openers.py b/nibabel/openers.py index 35b10c20a..e3217e189 100644 --- a/nibabel/openers.py +++ b/nibabel/openers.py @@ -131,7 +131,7 @@ class Opener: gz_def = (_gzip_open, ('mode', 'compresslevel', 'mtime', 'keep_open')) bz2_def = (BZ2File, ('mode', 'buffering', 'compresslevel')) zstd_def = (_zstd_open, ('mode', 'level_or_option', 'zstd_dict')) - compress_ext_map: dict[str | None, OpenerDef] = { + compress_ext_map: ty.ClassVar[dict[str | None, OpenerDef]] = { '.gz': gz_def, '.bz2': bz2_def, '.zst': zstd_def, @@ -141,7 +141,7 @@ class Opener: default_compresslevel = 1 #: default option for zst files default_zst_compresslevel = 3 - default_level_or_option = { + default_level_or_option: ty.ClassVar[dict[str, int | None]] = { 'rb': None, 'r': None, 'wb': default_zst_compresslevel, diff --git a/nibabel/pointset.py b/nibabel/pointset.py index 889a8c70c..759a0b15e 100644 --- a/nibabel/pointset.py +++ b/nibabel/pointset.py @@ -178,7 +178,7 @@ def to_mask(self, shape=None) -> SpatialImage: class GridIndices: """Class for generating indices just-in-time""" - __slots__ = ('gridshape', 'dtype', 'shape') + __slots__ = ('dtype', 'gridshape', 'shape') ndim = 2 def __init__(self, shape, dtype=None): diff --git a/nibabel/tests/test_nifti1.py b/nibabel/tests/test_nifti1.py index f0029681b..b54a336ea 100644 --- a/nibabel/tests/test_nifti1.py +++ b/nibabel/tests/test_nifti1.py @@ -538,8 +538,7 @@ def test_slice_times(self): hdr.set_slice_duration(0.1) # We need a function to print out the Nones and floating point # values in a predictable way, for the tests below. - _stringer = lambda val: val is not None and f'{val:2.1f}' or None - _print_me = lambda s: list(map(_stringer, s)) + _print_me = lambda s: [val if val is None else f'{val:2.1f}' for val in s] # The following examples are from the nifti1.h documentation. hdr['slice_code'] = slice_order_codes['sequential increasing'] assert _print_me(hdr.get_slice_times()) == [ diff --git a/nibabel/tests/test_volumeutils.py b/nibabel/tests/test_volumeutils.py index 1bd44cbd0..86923cc9f 100644 --- a/nibabel/tests/test_volumeutils.py +++ b/nibabel/tests/test_volumeutils.py @@ -607,7 +607,7 @@ def test_a2f_nanpos(): def test_a2f_bad_scaling(): # Test that pathological scalers raise an error - NUMERICAL_TYPES = sum((sctypes[key] for key in ['int', 'uint', 'float', 'complex']), []) + NUMERICAL_TYPES = [tp for kind in ('int', 'uint', 'float', 'complex') for tp in sctypes[kind]] for in_type, out_type, slope, inter in itertools.product( NUMERICAL_TYPES, NUMERICAL_TYPES, diff --git a/nibabel/volumeutils.py b/nibabel/volumeutils.py index d0ebb46a7..992c16924 100644 --- a/nibabel/volumeutils.py +++ b/nibabel/volumeutils.py @@ -35,8 +35,7 @@ DT = ty.TypeVar('DT', bound=np.generic) sys_is_le = sys.byteorder == 'little' -native_code = sys_is_le and '<' or '>' -swapped_code = sys_is_le and '>' or '<' +native_code, swapped_code = ('<', '>') if sys_is_le else ('>', '<') _endian_codes = ( # numpy code, aliases ('<', 'little', 'l', 'le', 'L', 'LE'), diff --git a/nibabel/wrapstruct.py b/nibabel/wrapstruct.py index 5ffe04bc7..77e1a5249 100644 --- a/nibabel/wrapstruct.py +++ b/nibabel/wrapstruct.py @@ -112,6 +112,8 @@ from __future__ import annotations +from typing import ClassVar + import numpy as np from . import imageglobals as imageglobals @@ -485,7 +487,7 @@ def _get_checks(klass): class LabeledWrapStruct(WrapStruct): """A WrapStruct with some fields having value labels for printing etc""" - _field_recoders: dict[str, Recoder] = {} # for recoding values for str + _field_recoders: ClassVar[dict[str, Recoder]] = {} # for recoding values for str def get_value_label(self, fieldname): """Returns label for coded field diff --git a/nibabel/xmlutils.py b/nibabel/xmlutils.py index 12fd30f22..878290399 100644 --- a/nibabel/xmlutils.py +++ b/nibabel/xmlutils.py @@ -49,7 +49,7 @@ class XmlParser: CharacterDataHandler """ - HANDLER_NAMES = ['StartElementHandler', 'EndElementHandler', 'CharacterDataHandler'] + HANDLER_NAMES = ('StartElementHandler', 'EndElementHandler', 'CharacterDataHandler') def __init__(self, encoding='utf-8', buffer_size=35000000, verbose=0): """ diff --git a/pyproject.toml b/pyproject.toml index b62c0048a..32dd4199e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -162,7 +162,6 @@ ignore = [ "RUF005", "RUF012", # TODO: enable "RUF015", - "RUF017", # TODO: enable "UP027", # deprecated "UP038", # https://github.com/astral-sh/ruff/issues/7871 # https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules