diff --git a/nibabel/__init__.py b/nibabel/__init__.py index fca22ccc99..d293b65482 100644 --- a/nibabel/__init__.py +++ b/nibabel/__init__.py @@ -76,7 +76,7 @@ def setup_test(): flip_axis, OrientationError, apply_orientation, aff2axcodes) from .imageclasses import class_map, ext_map, all_image_classes -from . import trackvis +trackvis = _ModuleProxy('nibabel.trackvis') from . import mriutils from . import streamlines from . import viewers diff --git a/nibabel/checkwarns.py b/nibabel/checkwarns.py index 01ef8fd10c..deb3f6f009 100644 --- a/nibabel/checkwarns.py +++ b/nibabel/checkwarns.py @@ -13,25 +13,20 @@ import warnings from .testing import (error_warnings, suppress_warnings) +from .deprecated import deprecate_with_version warnings.warn('The checkwarns module is deprecated and will be removed ' - 'in nibabel v3.0', FutureWarning) + 'in nibabel v3.0', DeprecationWarning) +@deprecate_with_version('ErrorWarnings is deprecated; use nibabel.testing.error_warnings.', + since='2.1.0', until='3.0.0') class ErrorWarnings(error_warnings): - - def __init__(self, *args, **kwargs): - warnings.warn('ErrorWarnings is deprecated and will be removed in ' - 'nibabel v3.0; use nibabel.testing.error_warnings.', - FutureWarning) - super(ErrorWarnings, self).__init__(*args, **kwargs) + pass +@deprecate_with_version('IgnoreWarnings is deprecated; use nibabel.testing.suppress_warnings.', + since='2.1.0', until='3.0.0') class IgnoreWarnings(suppress_warnings): - - def __init__(self, *args, **kwargs): - warnings.warn('IgnoreWarnings is deprecated and will be removed in ' - 'nibabel v3.0; use nibabel.testing.suppress_warnings.', - FutureWarning) - super(IgnoreWarnings, self).__init__(*args, **kwargs) + pass diff --git a/nibabel/minc.py b/nibabel/minc.py index 94e8da57fc..09523bdc36 100644 --- a/nibabel/minc.py +++ b/nibabel/minc.py @@ -2,9 +2,9 @@ import warnings -warnings.warn("We will remove this module from nibabel soon; " +warnings.warn("We will remove this module from nibabel 3.0; " "Please use the 'minc1' module instead", - FutureWarning, + DeprecationWarning, stacklevel=2) from .minc1 import * # noqa diff --git a/nibabel/minc1.py b/nibabel/minc1.py index 369922bf99..a8535eec05 100644 --- a/nibabel/minc1.py +++ b/nibabel/minc1.py @@ -18,7 +18,7 @@ from .fileslice import canonical_slicers from .keywordonly import kw_only_meth -from .deprecated import FutureWarningMixin +from .deprecated import deprecate_with_version _dt_dict = { ('b', 'unsigned'): np.uint8, @@ -331,13 +331,13 @@ def from_file_map(klass, file_map, mmap=True, keep_file_open=None): # Backwards compatibility -class MincFile(FutureWarningMixin, Minc1File): - """ Deprecated alternative name for Minc1File - """ - warn_message = 'MincFile is deprecated; please use Minc1File instead' +@deprecate_with_version('MincFile is deprecated; please use Minc1File instead', + since='2.0.0', until='3.0.0', warn_class=FutureWarning) +class MincFile(Minc1File): + pass -class MincImage(FutureWarningMixin, Minc1Image): - """ Deprecated alternative name for Minc1Image - """ - warn_message = 'MincImage is deprecated; please use Minc1Image instead' +@deprecate_with_version('MincImage is deprecated; please use Minc1Image instead', + since='2.0.0', until='3.0.0', warn_class=FutureWarning) +class MincImage(Minc1Image): + pass diff --git a/nibabel/testing/__init__.py b/nibabel/testing/__init__.py index 2c0a93fe32..16f2112299 100644 --- a/nibabel/testing/__init__.py +++ b/nibabel/testing/__init__.py @@ -16,11 +16,13 @@ from os.path import dirname, abspath, join as pjoin import numpy as np -from numpy.testing import assert_array_equal +from numpy.testing import assert_array_equal, assert_warns from numpy.testing import dec skipif = dec.skipif slow = dec.slow +from ..deprecated import deprecate_with_version as _deprecate_with_version + # Allow failed import of nose if not now running tests try: from nose.tools import (assert_equal, assert_not_equal, @@ -187,12 +189,11 @@ class suppress_warnings(error_warnings): filter = 'ignore' +@_deprecate_with_version('catch_warn_reset is deprecated; use ' + 'nibabel.testing.clear_and_catch_warnings.', + since='2.1.0', until='3.0.0') class catch_warn_reset(clear_and_catch_warnings): - - def __init__(self, *args, **kwargs): - warnings.warn('catch_warn_reset is deprecated and will be removed in ' - 'nibabel v3.0; use nibabel.testing.clear_and_catch_warnings.', - FutureWarning) + pass EXTRA_SET = os.environ.get('NIPY_EXTRA_TESTS', '').split(',') diff --git a/nibabel/tests/test_checkwarns.py b/nibabel/tests/test_checkwarns.py index 11c7422326..b1e6483273 100644 --- a/nibabel/tests/test_checkwarns.py +++ b/nibabel/tests/test_checkwarns.py @@ -1,21 +1,11 @@ """ Tests for warnings context managers """ -from __future__ import division, print_function, absolute_import - -from nose.tools import assert_equal -from ..testing import clear_and_catch_warnings, suppress_warnings +from ..testing import assert_equal, assert_warns, suppress_warnings def test_ignore_and_error_warnings(): with suppress_warnings(): from .. import checkwarns - with clear_and_catch_warnings() as w: - checkwarns.IgnoreWarnings() - assert_equal(len(w), 1) - assert_equal(w[0].category, FutureWarning) - - with clear_and_catch_warnings() as w: - checkwarns.ErrorWarnings() - assert_equal(len(w), 1) - assert_equal(w[0].category, FutureWarning) + assert_warns(DeprecationWarning, checkwarns.IgnoreWarnings) + assert_warns(DeprecationWarning, checkwarns.ErrorWarnings) diff --git a/nibabel/tests/test_minc1.py b/nibabel/tests/test_minc1.py index cb59d921eb..1c150b02d5 100644 --- a/nibabel/tests/test_minc1.py +++ b/nibabel/tests/test_minc1.py @@ -24,10 +24,9 @@ from .. import minc1 from ..minc1 import Minc1File, Minc1Image, MincHeader -from nose.tools import (assert_true, assert_equal, assert_false, assert_raises) -from numpy.testing import assert_array_equal from ..tmpdirs import InTemporaryDirectory -from ..testing import data_path +from ..testing import (assert_true, assert_equal, assert_false, assert_raises, assert_warns, + assert_array_equal, data_path, clear_and_catch_warnings) from . import test_spatialimages as tsi from .test_fileslice import slicer_samples @@ -106,7 +105,8 @@ def test_old_namespace(): # Check warnings raised arr = np.arange(24).reshape((2, 3, 4)) aff = np.diag([2, 3, 4, 1]) - with warnings.catch_warnings(record=True) as warns: + with clear_and_catch_warnings() as warns: + warnings.simplefilter('always', DeprecationWarning) # Top level import. # This import does not trigger an import of the minc.py module, because # it's the proxy object. @@ -122,7 +122,9 @@ def test_old_namespace(): # depending on whether the minc.py module is already imported in this # test run. if not previous_import: - assert_equal(warns.pop(0).category, FutureWarning) + assert_equal(warns.pop(0).category, DeprecationWarning) + + with clear_and_catch_warnings() as warns: from .. import Minc1Image, MincImage assert_equal(warns, []) # The import from old module is the same as that from new @@ -132,17 +134,17 @@ def test_old_namespace(): assert_equal(warns, []) # Create object using old name mimg = MincImage(arr, aff) - assert_array_equal(mimg.get_data(), arr) # Call to create object created warning assert_equal(warns.pop(0).category, FutureWarning) + assert_array_equal(mimg.get_data(), arr) # Another old name from ..minc1 import MincFile, Minc1File assert_false(MincFile is Minc1File) assert_equal(warns, []) mf = MincFile(netcdf_file(EG_FNAME)) - assert_equal(mf.get_data_shape(), (10, 20, 20)) # Call to create object created warning assert_equal(warns.pop(0).category, FutureWarning) + assert_equal(mf.get_data_shape(), (10, 20, 20)) class _TestMincFile(object): diff --git a/nibabel/tests/test_removalschedule.py b/nibabel/tests/test_removalschedule.py new file mode 100644 index 0000000000..24f9bdd12c --- /dev/null +++ b/nibabel/tests/test_removalschedule.py @@ -0,0 +1,34 @@ +from ..info import cmp_pkg_version +from ..testing import assert_raises, assert_false + +MODULE_SCHEDULE = [ + ('4.0.0', ['nibabel.trackvis']), + ('3.0.0', ['nibabel.minc', 'nibabel.checkwarns']), + # Verify that the test will be quiet if the schedule outlives the modules + ('1.0.0', ['nibabel.neverexisted']), + ] + +OBJECT_SCHEDULE = [ + ('3.0.0', [('nibabel.testing', 'catch_warn_reset')]), + # Verify that the test will be quiet if the schedule outlives the modules + ('1.0.0', [('nibabel', 'neverexisted')]), + ] + + +def test_module_removal(): + for version, to_remove in MODULE_SCHEDULE: + if cmp_pkg_version(version) < 1: + for module in to_remove: + with assert_raises(ImportError, msg="Time to remove " + module): + __import__(module) + + +def test_object_removal(): + for version, to_remove in OBJECT_SCHEDULE: + if cmp_pkg_version(version) < 1: + for module_name, obj in to_remove: + try: + module = __import__(module_name) + except ImportError: + continue + assert_false(hasattr(module, obj), msg="Time to remove %s.%s" % (module_name, obj)) diff --git a/nibabel/tests/test_trackvis.py b/nibabel/tests/test_trackvis.py index 9f8d84946c..96f96a3f44 100644 --- a/nibabel/tests/test_trackvis.py +++ b/nibabel/tests/test_trackvis.py @@ -10,9 +10,9 @@ from ..orientations import aff2axcodes from ..volumeutils import native_code, swapped_code -from nose.tools import assert_true, assert_false, assert_equal, assert_raises -from numpy.testing import assert_array_equal, assert_array_almost_equal -from ..testing import error_warnings, suppress_warnings +from numpy.testing import assert_array_almost_equal +from ..testing import (assert_true, assert_false, assert_equal, assert_raises, assert_warns, + assert_array_equal, suppress_warnings) def test_write(): @@ -217,8 +217,7 @@ def _rt(streams, hdr, points_space): assert_raises(tv.HeaderError, tv.read, out_f, False, 'voxel') # There's a warning for any voxel sizes == 0 hdr = {'voxel_size': [2, 3, 0]} - with error_warnings(): - assert_raises(UserWarning, _rt, vx_streams, hdr, 'voxel') + assert_warns(UserWarning, _rt, vx_streams, hdr, 'voxel') # This should be OK hdr = {'voxel_size': [2, 3, 4]} (raw_streams, hdr), (proc_streams, _) = _rt(vx_streams, hdr, 'voxel') @@ -305,9 +304,8 @@ def test__check_hdr_points_space(): tv._check_hdr_points_space, hdr, 'voxel') # Warning here only hdr['voxel_size'] = [2, 3, 0] - with error_warnings(): - assert_raises(UserWarning, - tv._check_hdr_points_space, hdr, 'voxel') + assert_warns(UserWarning, + tv._check_hdr_points_space, hdr, 'voxel') # This is OK hdr['voxel_size'] = [2, 3, 4] assert_equal(tv._check_hdr_points_space(hdr, 'voxel'), None) @@ -370,10 +368,6 @@ def test_empty_header(): def test_get_affine(): # Test get affine behavior, including pending deprecation hdr = tv.empty_header() - # Using version 1 affine is not a good idea because is fragile and not - # very useful. The default atleast_v2=None mode raises a FutureWarning - with error_warnings(): - assert_raises(FutureWarning, tv.aff_from_hdr, hdr) # testing the old behavior old_afh = partial(tv.aff_from_hdr, atleast_v2=False) # default header gives useless affine @@ -421,9 +415,8 @@ def test_get_affine(): assert_equal(hdr['voxel_order'], o_codes) # Check it came back the way we wanted assert_array_equal(old_afh(hdr), in_aff) - # Check that the default case matches atleast_v2=False case - with suppress_warnings(): - assert_array_equal(tv.aff_from_hdr(hdr), flipped_aff) + # Check that v1 header raises error + assert_raises(tv.HeaderError, tv.aff_from_hdr, hdr) # now use the easier vox_to_ras field hdr = tv.empty_header() aff = np.eye(4) @@ -455,15 +448,7 @@ def test_aff_to_hdr(): # Historically we flip the first axis if there is a negative determinant assert_array_almost_equal(hdr['voxel_size'], [-1, 2, 3]) assert_array_almost_equal(tv.aff_from_hdr(hdr, atleast_v2=False), aff2) - # Test that default mode raises DeprecationWarning - with error_warnings(): - assert_raises(FutureWarning, tv.aff_to_hdr, affine, hdr) - assert_raises(FutureWarning, tv.aff_to_hdr, affine, hdr, None, None) - assert_raises(FutureWarning, tv.aff_to_hdr, affine, hdr, False, None) - assert_raises(FutureWarning, tv.aff_to_hdr, affine, hdr, None, False) - # And has same effect as above - with suppress_warnings(): - tv.aff_to_hdr(affine, hdr) + tv.aff_to_hdr(affine, hdr, pos_vox=False, set_order=False) assert_array_almost_equal(tv.aff_from_hdr(hdr, atleast_v2=False), affine) # Check pos_vox and order flags for hdr in ({}, {'version': 2}, {'version': 1}): @@ -515,13 +500,6 @@ def test_tv_class(): affine = np.diag([1, 2, 3, 1]) affine[:3, 3] = [10, 11, 12] # affine methods will raise same warnings and errors as function - with error_warnings(): - assert_raises(FutureWarning, tvf.set_affine, affine) - assert_raises(FutureWarning, tvf.set_affine, affine, None, None) - assert_raises(FutureWarning, tvf.set_affine, affine, False, None) - assert_raises(FutureWarning, tvf.set_affine, affine, None, False) - assert_raises(FutureWarning, tvf.get_affine) - assert_raises(FutureWarning, tvf.get_affine, None) tvf.set_affine(affine, pos_vox=True, set_order=True) aff = tvf.get_affine(atleast_v2=True) assert_array_almost_equal(aff, affine) diff --git a/nibabel/trackvis.py b/nibabel/trackvis.py index 7da4ffcbe1..233e10ba79 100644 --- a/nibabel/trackvis.py +++ b/nibabel/trackvis.py @@ -17,12 +17,18 @@ from .openers import ImageOpener from .orientations import aff2axcodes from .affines import apply_affine +from .deprecated import deprecate_with_version try: basestring except NameError: # python 3 basestring = str +warnings.warn("The trackvis interface has been deprecated and will be removed " + "in v4.0; please use the 'nibabel.streamlines' interface.", + DeprecationWarning, + stacklevel=2) + # Definition of trackvis header structure. # See http://www.trackvis.org/docs/?subsect=fileformat # See https://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html @@ -99,6 +105,9 @@ class DataError(Exception): """ +@deprecate_with_version('trackvis.read is deprecated; please use ' + 'nibabel.streamlines.load, instead.', + since='2.5.0', until='4.0.0') def read(fileobj, as_generator=False, points_space=None, strict=True): ''' Read trackvis file from `fileobj`, return `streamlines`, `header` @@ -254,6 +263,9 @@ def track_gen(): return streamlines, hdr +@deprecate_with_version('trackvis.write is deprecated; please use ' + 'nibabel.streamlines.save, instead.', + since='2.5.0', until='4.0.0') def write(fileobj, streamlines, hdr_mapping=None, endianness=None, points_space=None): ''' Write header and `streamlines` to trackvis file `fileobj` @@ -536,6 +548,9 @@ def _hdr_from_mapping(hdr=None, mapping=None, endianness=native_code): return hdr +@deprecate_with_version('empty_header is deprecated; please use ' + 'nibabel.streamlines.TrkFile.create_empty_header, instead.', + since='2.5.0', until='4.0.0') def empty_header(endianness=None, version=2): ''' Empty trackvis header @@ -590,7 +605,10 @@ def empty_header(endianness=None, version=2): return hdr -def aff_from_hdr(trk_hdr, atleast_v2=None): +@deprecate_with_version('aff_from_hdr is deprecated; please use ' + 'nibabel.streamlines.trk.get_affine_trackvis_to_rasmm, instead.', + since='2.5.0', until='4.0.0') +def aff_from_hdr(trk_hdr, atleast_v2=True): ''' Return voxel to mm affine from trackvis header Affine is mapping from voxel space to Nifti (RAS) output coordinate @@ -625,12 +643,6 @@ def aff_from_hdr(trk_hdr, atleast_v2=None): origin field to 0. In future, we'll raise an error rather than try and estimate the affine from version 1 fields ''' - if atleast_v2 is None: - warnings.warn('Defaulting to `atleast_v2` of False. Future versions ' - 'will default to True', - FutureWarning, - stacklevel=2) - atleast_v2 = False if trk_hdr['version'] == 2: aff = trk_hdr['vox_to_ras'] if aff[3, 3] != 0: @@ -673,7 +685,10 @@ def aff_from_hdr(trk_hdr, atleast_v2=None): return aff -def aff_to_hdr(affine, trk_hdr, pos_vox=None, set_order=None): +@deprecate_with_version('aff_to_hdr is deprecated; please use the ' + 'nibabel.streamlines.TrkFile.affine_to_rasmm property, instead.', + since='2.5.0', until='4.0.0') +def aff_to_hdr(affine, trk_hdr, pos_vox=True, set_order=True): ''' Set affine `affine` into trackvis header `trk_hdr` Affine is mapping from voxel space to Nifti RAS) output coordinate @@ -715,18 +730,6 @@ def aff_to_hdr(affine, trk_hdr, pos_vox=None, set_order=None): application). The application also ignores the origin field, and may not use the 'image_orientation_patient' field. ''' - if pos_vox is None: - warnings.warn('Default for ``pos_vox`` will change to True in ' - 'future versions of nibabel', - FutureWarning, - stacklevel=2) - pos_vox = False - if set_order is None: - warnings.warn('Default for ``set_order`` will change to True in ' - 'future versions of nibabel', - FutureWarning, - stacklevel=2) - set_order = False try: version = trk_hdr['version'] except (KeyError, ValueError): # dict or structured array @@ -797,6 +800,9 @@ class TrackvisFile(object): relationship between voxels, rasmm and voxmm space (above). ''' + @deprecate_with_version('TrackvisFile is deprecated; please use ' + 'nibabel.streamlines.TrkFile, instead.', + since='2.5.0', until='4.0.0') def __init__(self, streamlines, mapping=None, @@ -836,7 +842,7 @@ def to_file(self, file_like): self.filename = (file_like if isinstance(file_like, basestring) else None) - def get_affine(self, atleast_v2=None): + def get_affine(self, atleast_v2=True): """ Get affine from header in object Returns @@ -853,15 +859,9 @@ def get_affine(self, atleast_v2=None): consider it unsafe for version 1 headers, and in future versions of nibabel we will raise an error for trackvis headers < version 2. """ - if atleast_v2 is None: - warnings.warn('Defaulting to `atleast_v2` of False. Future ' - 'versions will default to True', - FutureWarning, - stacklevel=2) - atleast_v2 = False return aff_from_hdr(self.header, atleast_v2) - def set_affine(self, affine, pos_vox=None, set_order=None): + def set_affine(self, affine, pos_vox=True, set_order=True): """ Set affine `affine` into trackvis header Affine is mapping from voxel space to Nifti RAS) output coordinate @@ -888,16 +888,4 @@ def set_affine(self, affine, pos_vox=None, set_order=None): ------- None """ - if pos_vox is None: - warnings.warn('Default for ``pos_vox`` will change to True in ' - 'future versions of nibabel', - FutureWarning, - stacklevel=2) - pos_vox = False - if set_order is None: - warnings.warn('Default for ``set_order`` will change to True in ' - 'future versions of nibabel', - FutureWarning, - stacklevel=2) - set_order = False return aff_to_hdr(affine, self.header, pos_vox, set_order)