Skip to content

RF: Replace OneTimeProperty/auto_attr with cached_property #1341

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion doc/tools/build_modref_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import sys

# version comparison
from distutils.version import LooseVersion as V
from packaging.version import Version as V
from os.path import join as pjoin

# local imports
Expand Down Expand Up @@ -73,6 +73,8 @@ def abort(error):
if re.match('^_version_(major|minor|micro|extra)', v)
]
)

source_version = V(source_version)
print('***', source_version)

if source_version != installed_version:
Expand Down
46 changes: 23 additions & 23 deletions nibabel/nicom/dicomwrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@

import operator
import warnings
from functools import cached_property

import numpy as np

from nibabel.optpkg import optional_package

from ..onetime import auto_attr as one_time
from ..openers import ImageOpener
from . import csareader as csar
from .dwiparams import B2q, nearest_pos_semi_def, q2bg
Expand Down Expand Up @@ -140,15 +140,15 @@ def __init__(self, dcm_data):
"""
self.dcm_data = dcm_data

@one_time
@cached_property
def image_shape(self):
"""The array shape as it will be returned by ``get_data()``"""
shape = (self.get('Rows'), self.get('Columns'))
if None in shape:
return None
return shape

@one_time
@cached_property
def image_orient_patient(self):
"""Note that this is _not_ LR flipped"""
iop = self.get('ImageOrientationPatient')
Expand All @@ -158,15 +158,15 @@ def image_orient_patient(self):
iop = np.array(list(map(float, iop)))
return np.array(iop).reshape(2, 3).T

@one_time
@cached_property
def slice_normal(self):
iop = self.image_orient_patient
if iop is None:
return None
# iop[:, 0] is column index cosine, iop[:, 1] is row index cosine
return np.cross(iop[:, 1], iop[:, 0])

@one_time
@cached_property
def rotation_matrix(self):
"""Return rotation matrix between array indices and mm

Expand All @@ -193,7 +193,7 @@ def rotation_matrix(self):
raise WrapperPrecisionError('Rotation matrix not nearly orthogonal')
return R

@one_time
@cached_property
def voxel_sizes(self):
"""voxel sizes for array as returned by ``get_data()``"""
# pix space gives (row_spacing, column_spacing). That is, the
Expand All @@ -212,7 +212,7 @@ def voxel_sizes(self):
pix_space = list(map(float, pix_space))
return tuple(pix_space + [zs])

@one_time
@cached_property
def image_position(self):
"""Return position of first voxel in data block

Expand All @@ -231,7 +231,7 @@ def image_position(self):
# Values are python Decimals in pydicom 0.9.7
return np.array(list(map(float, ipp)))

@one_time
@cached_property
def slice_indicator(self):
"""A number that is higher for higher slices in Z

Expand All @@ -246,12 +246,12 @@ def slice_indicator(self):
return None
return np.inner(ipp, s_norm)

@one_time
@cached_property
def instance_number(self):
"""Just because we use this a lot for sorting"""
return self.get('InstanceNumber')

@one_time
@cached_property
def series_signature(self):
"""Signature for matching slices into series

Expand Down Expand Up @@ -390,15 +390,15 @@ def _apply_scale_offset(self, data, scale, offset):
return data + offset
return data

@one_time
@cached_property
def b_value(self):
"""Return b value for diffusion or None if not available"""
q_vec = self.q_vector
if q_vec is None:
return None
return q2bg(q_vec)[0]

@one_time
@cached_property
def b_vector(self):
"""Return b vector for diffusion or None if not available"""
q_vec = self.q_vector
Expand Down Expand Up @@ -469,7 +469,7 @@ def __init__(self, dcm_data):
raise WrapperError('SharedFunctionalGroupsSequence is empty.')
self._shape = None

@one_time
@cached_property
def image_shape(self):
"""The array shape as it will be returned by ``get_data()``

Expand Down Expand Up @@ -573,7 +573,7 @@ def image_shape(self):
)
return tuple(shape)

@one_time
@cached_property
def image_orient_patient(self):
"""
Note that this is _not_ LR flipped
Expand All @@ -590,7 +590,7 @@ def image_orient_patient(self):
iop = np.array(list(map(float, iop)))
return np.array(iop).reshape(2, 3).T

@one_time
@cached_property
def voxel_sizes(self):
"""Get i, j, k voxel sizes"""
try:
Expand All @@ -610,7 +610,7 @@ def voxel_sizes(self):
# Ensure values are float rather than Decimal
return tuple(map(float, list(pix_space) + [zs]))

@one_time
@cached_property
def image_position(self):
try:
ipp = self.shared.PlanePositionSequence[0].ImagePositionPatient
Expand All @@ -623,7 +623,7 @@ def image_position(self):
return None
return np.array(list(map(float, ipp)))

@one_time
@cached_property
def series_signature(self):
signature = {}
eq = operator.eq
Expand Down Expand Up @@ -696,7 +696,7 @@ def __init__(self, dcm_data, csa_header=None):
csa_header = {}
self.csa_header = csa_header

@one_time
@cached_property
def slice_normal(self):
# The std_slice_normal comes from the cross product of the directions
# in the ImageOrientationPatient
Expand All @@ -720,7 +720,7 @@ def slice_normal(self):
else:
return std_slice_normal

@one_time
@cached_property
def series_signature(self):
"""Add ICE dims from CSA header to signature"""
signature = super().series_signature
Expand All @@ -730,7 +730,7 @@ def series_signature(self):
signature['ICE_Dims'] = (ice, operator.eq)
return signature

@one_time
@cached_property
def b_matrix(self):
"""Get DWI B matrix referring to voxel space

Expand Down Expand Up @@ -767,7 +767,7 @@ def b_matrix(self):
# semi-definite.
return nearest_pos_semi_def(B_vox)

@one_time
@cached_property
def q_vector(self):
"""Get DWI q vector referring to voxel space

Expand Down Expand Up @@ -840,7 +840,7 @@ def __init__(self, dcm_data, csa_header=None, n_mosaic=None):
self.n_mosaic = n_mosaic
self.mosaic_size = int(np.ceil(np.sqrt(n_mosaic)))

@one_time
@cached_property
def image_shape(self):
"""Return image shape as returned by ``get_data()``"""
# reshape pixel slice array back from mosaic
Expand All @@ -850,7 +850,7 @@ def image_shape(self):
return None
return (rows // self.mosaic_size, cols // self.mosaic_size, self.n_mosaic)

@one_time
@cached_property
def image_position(self):
"""Return position of first voxel in data block

Expand Down
Loading
Loading