Skip to content

Commit 02c7a34

Browse files
authored
Merge pull request #1173 from effigies/mnt/int64_error
ENH: Schedule int64 warning to convert to error at 5.0
2 parents e662e55 + 0aeecbc commit 02c7a34

File tree

4 files changed

+89
-10
lines changed

4 files changed

+89
-10
lines changed

nibabel/deprecated.py

+39
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
"""Module to help with deprecating objects and classes
22
"""
3+
from __future__ import annotations
34

45
import warnings
6+
from typing import Type
57

68
from .deprecator import Deprecator
79
from .pkg_info import cmp_pkg_version
@@ -77,3 +79,40 @@ class VisibleDeprecationWarning(UserWarning):
7779

7880

7981
deprecate_with_version = Deprecator(cmp_pkg_version)
82+
83+
84+
def alert_future_error(
85+
msg: str,
86+
version: str,
87+
*,
88+
warning_class: Type[Warning] = FutureWarning,
89+
error_class: Type[Exception] = RuntimeError,
90+
warning_rec: str = '',
91+
error_rec: str = '',
92+
stacklevel: int = 2,
93+
):
94+
"""Warn or error with appropriate messages for changing functionality.
95+
96+
Parameters
97+
----------
98+
msg : str
99+
Description of the condition that led to the alert
100+
version : str
101+
NiBabel version at which the warning will become an error
102+
warning_class : subclass of Warning, optional
103+
Warning class to emit before version
104+
error_class : subclass of Exception, optional
105+
Error class to emit after version
106+
warning_rec : str, optional
107+
Guidance for suppressing the warning and avoiding the future error
108+
error_rec: str, optional
109+
Guidance for resolving the error
110+
stacklevel: int, optional
111+
Warnings stacklevel to provide; note that this will be incremented by
112+
1, so provide the stacklevel you would provide directly to warnings.warn()
113+
"""
114+
if cmp_pkg_version(version) >= 0:
115+
msg = f'{msg} This will error in NiBabel {version}. {warning_rec}'
116+
warnings.warn(msg.strip(), warning_class, stacklevel=stacklevel + 1)
117+
else:
118+
raise error_class(f'{msg} {error_rec}'.strip())

nibabel/nifti1.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from .arrayproxy import get_obj_dtype
2222
from .batteryrunners import Report
2323
from .casting import have_binary128
24+
from .deprecated import alert_future_error
2425
from .filebasedimages import SerializableImage
2526
from .optpkg import optional_package
2627
from .quaternions import fillpositive, mat2quat, quat2mat
@@ -1831,13 +1832,16 @@ def __init__(self, dataobj, affine, header=None, extra=None, file_map=None, dtyp
18311832
# already fail.
18321833
danger_dts = (np.dtype('int64'), np.dtype('uint64'))
18331834
if header is None and dtype is None and get_obj_dtype(dataobj) in danger_dts:
1834-
msg = (
1835+
alert_future_error(
18351836
f'Image data has type {dataobj.dtype}, which may cause '
1836-
'incompatibilities with other tools. This will error in '
1837-
'NiBabel 5.0. This warning can be silenced '
1838-
f'by passing the dtype argument to {self.__class__.__name__}().'
1837+
'incompatibilities with other tools.',
1838+
'5.0',
1839+
warning_rec='This warning can be silenced by passing the dtype argument'
1840+
f' to {self.__class__.__name__}().',
1841+
error_rec='To use this type, pass an explicit header or dtype argument'
1842+
f' to {self.__class__.__name__}().',
1843+
error_class=ValueError,
18391844
)
1840-
warnings.warn(msg, FutureWarning, stacklevel=2)
18411845
super().__init__(dataobj, affine, header, extra, file_map, dtype)
18421846
# Force set of s/q form when header is None unless affine is also None
18431847
if header is None and affine is not None:

nibabel/tests/test_deprecated.py

+31-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@
66
import pytest
77

88
from nibabel import pkg_info
9-
from nibabel.deprecated import FutureWarningMixin, ModuleProxy, deprecate_with_version
9+
from nibabel.deprecated import (
10+
FutureWarningMixin,
11+
ModuleProxy,
12+
alert_future_error,
13+
deprecate_with_version,
14+
)
1015
from nibabel.tests.test_deprecator import TestDeprecatorFunc as _TestDF
1116

1217

@@ -79,3 +84,28 @@ def func():
7984
assert func() == 99
8085
finally:
8186
pkg_info.cmp_pkg_version.__defaults__ = ('2.0',)
87+
88+
89+
def test_alert_future_error():
90+
with pytest.warns(FutureWarning):
91+
alert_future_error(
92+
'Message',
93+
'9999.9.9',
94+
warning_rec='Silence this warning by doing XYZ.',
95+
error_rec='Fix this issue by doing XYZ.',
96+
)
97+
with pytest.raises(RuntimeError):
98+
alert_future_error(
99+
'Message',
100+
'1.0.0',
101+
warning_rec='Silence this warning by doing XYZ.',
102+
error_rec='Fix this issue by doing XYZ.',
103+
)
104+
with pytest.raises(ValueError):
105+
alert_future_error(
106+
'Message',
107+
'1.0.0',
108+
warning_rec='Silence this warning by doing XYZ.',
109+
error_rec='Fix this issue by doing XYZ.',
110+
error_class=ValueError,
111+
)

nibabel/tests/test_nifti1.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
slice_order_codes,
3636
)
3737
from nibabel.optpkg import optional_package
38+
from nibabel.pkg_info import cmp_pkg_version
3839
from nibabel.spatialimages import HeaderDataError
3940
from nibabel.tmpdirs import InTemporaryDirectory
4041

@@ -766,16 +767,21 @@ class TestNifti1Pair(tana.TestAnalyzeImage, tspm.ImageScalingMixin):
766767
image_class = Nifti1Pair
767768
supported_np_types = TestNifti1PairHeader.supported_np_types
768769

769-
def test_int64_warning(self):
770+
def test_int64_warning_or_error(self):
770771
# Verify that initializing with (u)int64 data and no
771-
# header/dtype info produces a warning
772+
# header/dtype info produces a warning/error
772773
img_klass = self.image_class
773774
hdr_klass = img_klass.header_class
774775
for dtype in (np.int64, np.uint64):
775776
data = np.arange(24, dtype=dtype).reshape((2, 3, 4))
776-
with pytest.warns(FutureWarning):
777+
# Starts as a warning, transitions to error at 5.0
778+
if cmp_pkg_version('5.0') < 0:
779+
cm = pytest.raises(ValueError)
780+
else:
781+
cm = pytest.warns(FutureWarning)
782+
with cm:
777783
img_klass(data, np.eye(4))
778-
# No warnings if we're explicit, though
784+
# No problems if we're explicit, though
779785
with clear_and_catch_warnings():
780786
warnings.simplefilter('error')
781787
img_klass(data, np.eye(4), dtype=dtype)

0 commit comments

Comments
 (0)