123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873 |
- """
- Tests related to deprecation warnings. Also a convenient place
- to document how deprecations should eventually be turned into errors.
- """
- import datetime
- import operator
- import warnings
- import pytest
- import tempfile
- import re
- import sys
- import numpy as np
- from numpy.testing import (
- assert_raises, assert_warns, assert_, assert_array_equal
- )
- from numpy.core._multiarray_tests import fromstring_null_term_c_api
- try:
- import pytz
- _has_pytz = True
- except ImportError:
- _has_pytz = False
- class _DeprecationTestCase:
- # Just as warning: warnings uses re.match, so the start of this message
- # must match.
- message = ''
- warning_cls = DeprecationWarning
- def setup(self):
- self.warn_ctx = warnings.catch_warnings(record=True)
- self.log = self.warn_ctx.__enter__()
- # Do *not* ignore other DeprecationWarnings. Ignoring warnings
- # can give very confusing results because of
- # https://bugs.python.org/issue4180 and it is probably simplest to
- # try to keep the tests cleanly giving only the right warning type.
- # (While checking them set to "error" those are ignored anyway)
- # We still have them show up, because otherwise they would be raised
- warnings.filterwarnings("always", category=self.warning_cls)
- warnings.filterwarnings("always", message=self.message,
- category=self.warning_cls)
- def teardown(self):
- self.warn_ctx.__exit__()
- def assert_deprecated(self, function, num=1, ignore_others=False,
- function_fails=False,
- exceptions=np._NoValue,
- args=(), kwargs={}):
- """Test if DeprecationWarnings are given and raised.
- This first checks if the function when called gives `num`
- DeprecationWarnings, after that it tries to raise these
- DeprecationWarnings and compares them with `exceptions`.
- The exceptions can be different for cases where this code path
- is simply not anticipated and the exception is replaced.
- Parameters
- ----------
- function : callable
- The function to test
- num : int
- Number of DeprecationWarnings to expect. This should normally be 1.
- ignore_others : bool
- Whether warnings of the wrong type should be ignored (note that
- the message is not checked)
- function_fails : bool
- If the function would normally fail, setting this will check for
- warnings inside a try/except block.
- exceptions : Exception or tuple of Exceptions
- Exception to expect when turning the warnings into an error.
- The default checks for DeprecationWarnings. If exceptions is
- empty the function is expected to run successfully.
- args : tuple
- Arguments for `function`
- kwargs : dict
- Keyword arguments for `function`
- """
- __tracebackhide__ = True # Hide traceback for py.test
- # reset the log
- self.log[:] = []
- if exceptions is np._NoValue:
- exceptions = (self.warning_cls,)
- try:
- function(*args, **kwargs)
- except (Exception if function_fails else tuple()):
- pass
- # just in case, clear the registry
- num_found = 0
- for warning in self.log:
- if warning.category is self.warning_cls:
- num_found += 1
- elif not ignore_others:
- raise AssertionError(
- "expected %s but got: %s" %
- (self.warning_cls.__name__, warning.category))
- if num is not None and num_found != num:
- msg = "%i warnings found but %i expected." % (len(self.log), num)
- lst = [str(w) for w in self.log]
- raise AssertionError("\n".join([msg] + lst))
- with warnings.catch_warnings():
- warnings.filterwarnings("error", message=self.message,
- category=self.warning_cls)
- try:
- function(*args, **kwargs)
- if exceptions != tuple():
- raise AssertionError(
- "No error raised during function call")
- except exceptions:
- if exceptions == tuple():
- raise AssertionError(
- "Error raised during function call")
- def assert_not_deprecated(self, function, args=(), kwargs={}):
- """Test that warnings are not raised.
- This is just a shorthand for:
- self.assert_deprecated(function, num=0, ignore_others=True,
- exceptions=tuple(), args=args, kwargs=kwargs)
- """
- self.assert_deprecated(function, num=0, ignore_others=True,
- exceptions=tuple(), args=args, kwargs=kwargs)
- class _VisibleDeprecationTestCase(_DeprecationTestCase):
- warning_cls = np.VisibleDeprecationWarning
- class TestNonTupleNDIndexDeprecation:
- def test_basic(self):
- a = np.zeros((5, 5))
- with warnings.catch_warnings():
- warnings.filterwarnings('always')
- assert_warns(FutureWarning, a.__getitem__, [[0, 1], [0, 1]])
- assert_warns(FutureWarning, a.__getitem__, [slice(None)])
- warnings.filterwarnings('error')
- assert_raises(FutureWarning, a.__getitem__, [[0, 1], [0, 1]])
- assert_raises(FutureWarning, a.__getitem__, [slice(None)])
- # a a[[0, 1]] always was advanced indexing, so no error/warning
- a[[0, 1]]
- class TestComparisonDeprecations(_DeprecationTestCase):
- """This tests the deprecation, for non-element-wise comparison logic.
- This used to mean that when an error occurred during element-wise comparison
- (i.e. broadcasting) NotImplemented was returned, but also in the comparison
- itself, False was given instead of the error.
- Also test FutureWarning for the None comparison.
- """
- message = "elementwise.* comparison failed; .*"
- def test_normal_types(self):
- for op in (operator.eq, operator.ne):
- # Broadcasting errors:
- self.assert_deprecated(op, args=(np.zeros(3), []))
- a = np.zeros(3, dtype='i,i')
- # (warning is issued a couple of times here)
- self.assert_deprecated(op, args=(a, a[:-1]), num=None)
- # ragged array comparison returns True/False
- a = np.array([1, np.array([1,2,3])], dtype=object)
- b = np.array([1, np.array([1,2,3])], dtype=object)
- self.assert_deprecated(op, args=(a, b), num=None)
- def test_string(self):
- # For two string arrays, strings always raised the broadcasting error:
- a = np.array(['a', 'b'])
- b = np.array(['a', 'b', 'c'])
- assert_raises(ValueError, lambda x, y: x == y, a, b)
- # The empty list is not cast to string, and this used to pass due
- # to dtype mismatch; now (2018-06-21) it correctly leads to a
- # FutureWarning.
- assert_warns(FutureWarning, lambda: a == [])
- def test_void_dtype_equality_failures(self):
- class NotArray:
- def __array__(self):
- raise TypeError
- # Needed so Python 3 does not raise DeprecationWarning twice.
- def __ne__(self, other):
- return NotImplemented
- self.assert_deprecated(lambda: np.arange(2) == NotArray())
- self.assert_deprecated(lambda: np.arange(2) != NotArray())
- struct1 = np.zeros(2, dtype="i4,i4")
- struct2 = np.zeros(2, dtype="i4,i4,i4")
- assert_warns(FutureWarning, lambda: struct1 == 1)
- assert_warns(FutureWarning, lambda: struct1 == struct2)
- assert_warns(FutureWarning, lambda: struct1 != 1)
- assert_warns(FutureWarning, lambda: struct1 != struct2)
- def test_array_richcompare_legacy_weirdness(self):
- # It doesn't really work to use assert_deprecated here, b/c part of
- # the point of assert_deprecated is to check that when warnings are
- # set to "error" mode then the error is propagated -- which is good!
- # But here we are testing a bunch of code that is deprecated *because*
- # it has the habit of swallowing up errors and converting them into
- # different warnings. So assert_warns will have to be sufficient.
- assert_warns(FutureWarning, lambda: np.arange(2) == "a")
- assert_warns(FutureWarning, lambda: np.arange(2) != "a")
- # No warning for scalar comparisons
- with warnings.catch_warnings():
- warnings.filterwarnings("error")
- assert_(not (np.array(0) == "a"))
- assert_(np.array(0) != "a")
- assert_(not (np.int16(0) == "a"))
- assert_(np.int16(0) != "a")
- for arg1 in [np.asarray(0), np.int16(0)]:
- struct = np.zeros(2, dtype="i4,i4")
- for arg2 in [struct, "a"]:
- for f in [operator.lt, operator.le, operator.gt, operator.ge]:
- with warnings.catch_warnings() as l:
- warnings.filterwarnings("always")
- assert_raises(TypeError, f, arg1, arg2)
- assert_(not l)
- class TestDatetime64Timezone(_DeprecationTestCase):
- """Parsing of datetime64 with timezones deprecated in 1.11.0, because
- datetime64 is now timezone naive rather than UTC only.
- It will be quite a while before we can remove this, because, at the very
- least, a lot of existing code uses the 'Z' modifier to avoid conversion
- from local time to UTC, even if otherwise it handles time in a timezone
- naive fashion.
- """
- def test_string(self):
- self.assert_deprecated(np.datetime64, args=('2000-01-01T00+01',))
- self.assert_deprecated(np.datetime64, args=('2000-01-01T00Z',))
- @pytest.mark.skipif(not _has_pytz,
- reason="The pytz module is not available.")
- def test_datetime(self):
- tz = pytz.timezone('US/Eastern')
- dt = datetime.datetime(2000, 1, 1, 0, 0, tzinfo=tz)
- self.assert_deprecated(np.datetime64, args=(dt,))
- class TestNonCContiguousViewDeprecation(_DeprecationTestCase):
- """View of non-C-contiguous arrays deprecated in 1.11.0.
- The deprecation will not be raised for arrays that are both C and F
- contiguous, as C contiguous is dominant. There are more such arrays
- with relaxed stride checking than without so the deprecation is not
- as visible with relaxed stride checking in force.
- """
- def test_fortran_contiguous(self):
- self.assert_deprecated(np.ones((2,2)).T.view, args=(complex,))
- self.assert_deprecated(np.ones((2,2)).T.view, args=(np.int8,))
- class TestArrayDataAttributeAssignmentDeprecation(_DeprecationTestCase):
- """Assigning the 'data' attribute of an ndarray is unsafe as pointed
- out in gh-7093. Eventually, such assignment should NOT be allowed, but
- in the interests of maintaining backwards compatibility, only a Deprecation-
- Warning will be raised instead for the time being to give developers time to
- refactor relevant code.
- """
- def test_data_attr_assignment(self):
- a = np.arange(10)
- b = np.linspace(0, 1, 10)
- self.message = ("Assigning the 'data' attribute is an "
- "inherently unsafe operation and will "
- "be removed in the future.")
- self.assert_deprecated(a.__setattr__, args=('data', b.data))
- class TestBinaryReprInsufficientWidthParameterForRepresentation(_DeprecationTestCase):
- """
- If a 'width' parameter is passed into ``binary_repr`` that is insufficient to
- represent the number in base 2 (positive) or 2's complement (negative) form,
- the function used to silently ignore the parameter and return a representation
- using the minimal number of bits needed for the form in question. Such behavior
- is now considered unsafe from a user perspective and will raise an error in the future.
- """
- def test_insufficient_width_positive(self):
- args = (10,)
- kwargs = {'width': 2}
- self.message = ("Insufficient bit width provided. This behavior "
- "will raise an error in the future.")
- self.assert_deprecated(np.binary_repr, args=args, kwargs=kwargs)
- def test_insufficient_width_negative(self):
- args = (-5,)
- kwargs = {'width': 2}
- self.message = ("Insufficient bit width provided. This behavior "
- "will raise an error in the future.")
- self.assert_deprecated(np.binary_repr, args=args, kwargs=kwargs)
- class TestNumericStyleTypecodes(_DeprecationTestCase):
- """
- Most numeric style typecodes were previously deprecated (and removed)
- in 1.20. This also deprecates the remaining ones.
- """
- # 2020-06-09, NumPy 1.20
- def test_all_dtypes(self):
- deprecated_types = ['Bytes0', 'Datetime64', 'Str0']
- # Depending on intp size, either Uint32 or Uint64 is defined:
- deprecated_types.append(f"U{np.dtype(np.intp).name}")
- for dt in deprecated_types:
- self.assert_deprecated(np.dtype, exceptions=(TypeError,),
- args=(dt,))
- class TestTestDeprecated:
- def test_assert_deprecated(self):
- test_case_instance = _DeprecationTestCase()
- test_case_instance.setup()
- assert_raises(AssertionError,
- test_case_instance.assert_deprecated,
- lambda: None)
- def foo():
- warnings.warn("foo", category=DeprecationWarning, stacklevel=2)
- test_case_instance.assert_deprecated(foo)
- test_case_instance.teardown()
- class TestNonNumericConjugate(_DeprecationTestCase):
- """
- Deprecate no-op behavior of ndarray.conjugate on non-numeric dtypes,
- which conflicts with the error behavior of np.conjugate.
- """
- def test_conjugate(self):
- for a in np.array(5), np.array(5j):
- self.assert_not_deprecated(a.conjugate)
- for a in (np.array('s'), np.array('2016', 'M'),
- np.array((1, 2), [('a', int), ('b', int)])):
- self.assert_deprecated(a.conjugate)
- class TestNPY_CHAR(_DeprecationTestCase):
- # 2017-05-03, 1.13.0
- def test_npy_char_deprecation(self):
- from numpy.core._multiarray_tests import npy_char_deprecation
- self.assert_deprecated(npy_char_deprecation)
- assert_(npy_char_deprecation() == 'S1')
- class TestPyArray_AS1D(_DeprecationTestCase):
- def test_npy_pyarrayas1d_deprecation(self):
- from numpy.core._multiarray_tests import npy_pyarrayas1d_deprecation
- assert_raises(NotImplementedError, npy_pyarrayas1d_deprecation)
- class TestPyArray_AS2D(_DeprecationTestCase):
- def test_npy_pyarrayas2d_deprecation(self):
- from numpy.core._multiarray_tests import npy_pyarrayas2d_deprecation
- assert_raises(NotImplementedError, npy_pyarrayas2d_deprecation)
- class Test_UPDATEIFCOPY(_DeprecationTestCase):
- """
- v1.14 deprecates creating an array with the UPDATEIFCOPY flag, use
- WRITEBACKIFCOPY instead
- """
- def test_npy_updateifcopy_deprecation(self):
- from numpy.core._multiarray_tests import npy_updateifcopy_deprecation
- arr = np.arange(9).reshape(3, 3)
- v = arr.T
- self.assert_deprecated(npy_updateifcopy_deprecation, args=(v,))
- class TestDatetimeEvent(_DeprecationTestCase):
- # 2017-08-11, 1.14.0
- def test_3_tuple(self):
- for cls in (np.datetime64, np.timedelta64):
- # two valid uses - (unit, num) and (unit, num, den, None)
- self.assert_not_deprecated(cls, args=(1, ('ms', 2)))
- self.assert_not_deprecated(cls, args=(1, ('ms', 2, 1, None)))
- # trying to use the event argument, removed in 1.7.0, is deprecated
- # it used to be a uint8
- self.assert_deprecated(cls, args=(1, ('ms', 2, 'event')))
- self.assert_deprecated(cls, args=(1, ('ms', 2, 63)))
- self.assert_deprecated(cls, args=(1, ('ms', 2, 1, 'event')))
- self.assert_deprecated(cls, args=(1, ('ms', 2, 1, 63)))
- class TestTruthTestingEmptyArrays(_DeprecationTestCase):
- # 2017-09-25, 1.14.0
- message = '.*truth value of an empty array is ambiguous.*'
- def test_1d(self):
- self.assert_deprecated(bool, args=(np.array([]),))
- def test_2d(self):
- self.assert_deprecated(bool, args=(np.zeros((1, 0)),))
- self.assert_deprecated(bool, args=(np.zeros((0, 1)),))
- self.assert_deprecated(bool, args=(np.zeros((0, 0)),))
- class TestBincount(_DeprecationTestCase):
- # 2017-06-01, 1.14.0
- def test_bincount_minlength(self):
- self.assert_deprecated(lambda: np.bincount([1, 2, 3], minlength=None))
- class TestAlen(_DeprecationTestCase):
- # 2019-08-02, 1.18.0
- def test_alen(self):
- self.assert_deprecated(lambda: np.alen(np.array([1, 2, 3])))
- class TestGeneratorSum(_DeprecationTestCase):
- # 2018-02-25, 1.15.0
- def test_generator_sum(self):
- self.assert_deprecated(np.sum, args=((i for i in range(5)),))
- class TestPositiveOnNonNumerical(_DeprecationTestCase):
- # 2018-06-28, 1.16.0
- def test_positive_on_non_number(self):
- self.assert_deprecated(operator.pos, args=(np.array('foo'),))
- class TestFromstring(_DeprecationTestCase):
- # 2017-10-19, 1.14
- def test_fromstring(self):
- self.assert_deprecated(np.fromstring, args=('\x00'*80,))
- class TestFromStringAndFileInvalidData(_DeprecationTestCase):
- # 2019-06-08, 1.17.0
- # Tests should be moved to real tests when deprecation is done.
- message = "string or file could not be read to its end"
- @pytest.mark.parametrize("invalid_str", [",invalid_data", "invalid_sep"])
- def test_deprecate_unparsable_data_file(self, invalid_str):
- x = np.array([1.51, 2, 3.51, 4], dtype=float)
- with tempfile.TemporaryFile(mode="w") as f:
- x.tofile(f, sep=',', format='%.2f')
- f.write(invalid_str)
- f.seek(0)
- self.assert_deprecated(lambda: np.fromfile(f, sep=","))
- f.seek(0)
- self.assert_deprecated(lambda: np.fromfile(f, sep=",", count=5))
- # Should not raise:
- with warnings.catch_warnings():
- warnings.simplefilter("error", DeprecationWarning)
- f.seek(0)
- res = np.fromfile(f, sep=",", count=4)
- assert_array_equal(res, x)
- @pytest.mark.parametrize("invalid_str", [",invalid_data", "invalid_sep"])
- def test_deprecate_unparsable_string(self, invalid_str):
- x = np.array([1.51, 2, 3.51, 4], dtype=float)
- x_str = "1.51,2,3.51,4{}".format(invalid_str)
- self.assert_deprecated(lambda: np.fromstring(x_str, sep=","))
- self.assert_deprecated(lambda: np.fromstring(x_str, sep=",", count=5))
- # The C-level API can use not fixed size, but 0 terminated strings,
- # so test that as well:
- bytestr = x_str.encode("ascii")
- self.assert_deprecated(lambda: fromstring_null_term_c_api(bytestr))
- with assert_warns(DeprecationWarning):
- # this is slightly strange, in that fromstring leaves data
- # potentially uninitialized (would be good to error when all is
- # read, but count is larger then actual data maybe).
- res = np.fromstring(x_str, sep=",", count=5)
- assert_array_equal(res[:-1], x)
- with warnings.catch_warnings():
- warnings.simplefilter("error", DeprecationWarning)
- # Should not raise:
- res = np.fromstring(x_str, sep=",", count=4)
- assert_array_equal(res, x)
- class Test_GetSet_NumericOps(_DeprecationTestCase):
- # 2018-09-20, 1.16.0
- def test_get_numeric_ops(self):
- from numpy.core._multiarray_tests import getset_numericops
- self.assert_deprecated(getset_numericops, num=2)
- # empty kwargs prevents any state actually changing which would break
- # other tests.
- self.assert_deprecated(np.set_numeric_ops, kwargs={})
- assert_raises(ValueError, np.set_numeric_ops, add='abc')
- class TestShape1Fields(_DeprecationTestCase):
- warning_cls = FutureWarning
- # 2019-05-20, 1.17.0
- def test_shape_1_fields(self):
- self.assert_deprecated(np.dtype, args=([('a', int, 1)],))
- class TestNonZero(_DeprecationTestCase):
- # 2019-05-26, 1.17.0
- def test_zerod(self):
- self.assert_deprecated(lambda: np.nonzero(np.array(0)))
- self.assert_deprecated(lambda: np.nonzero(np.array(1)))
- def test_deprecate_ragged_arrays():
- # 2019-11-29 1.19.0
- #
- # NEP 34 deprecated automatic object dtype when creating ragged
- # arrays. Also see the "ragged" tests in `test_multiarray`
- #
- # emits a VisibleDeprecationWarning
- arg = [1, [2, 3]]
- with assert_warns(np.VisibleDeprecationWarning):
- np.array(arg)
- class TestTooDeepDeprecation(_VisibleDeprecationTestCase):
- # NumPy 1.20, 2020-05-08
- # This is a bit similar to the above ragged array deprecation case.
- message = re.escape("Creating an ndarray from nested sequences exceeding")
- def test_deprecation(self):
- nested = [1]
- for i in range(np.MAXDIMS - 1):
- nested = [nested]
- self.assert_not_deprecated(np.array, args=(nested,))
- self.assert_not_deprecated(np.array,
- args=(nested,), kwargs=dict(dtype=object))
- self.assert_deprecated(np.array, args=([nested],))
- class TestToString(_DeprecationTestCase):
- # 2020-03-06 1.19.0
- message = re.escape("tostring() is deprecated. Use tobytes() instead.")
- def test_tostring(self):
- arr = np.array(list(b"test\xFF"), dtype=np.uint8)
- self.assert_deprecated(arr.tostring)
- def test_tostring_matches_tobytes(self):
- arr = np.array(list(b"test\xFF"), dtype=np.uint8)
- b = arr.tobytes()
- with assert_warns(DeprecationWarning):
- s = arr.tostring()
- assert s == b
- class TestDTypeCoercion(_DeprecationTestCase):
- # 2020-02-06 1.19.0
- message = "Converting .* to a dtype .*is deprecated"
- deprecated_types = [
- # The builtin scalar super types:
- np.generic, np.flexible, np.number,
- np.inexact, np.floating, np.complexfloating,
- np.integer, np.unsignedinteger, np.signedinteger,
- # character is a deprecated S1 special case:
- np.character,
- ]
- def test_dtype_coercion(self):
- for scalar_type in self.deprecated_types:
- self.assert_deprecated(np.dtype, args=(scalar_type,))
- def test_array_construction(self):
- for scalar_type in self.deprecated_types:
- self.assert_deprecated(np.array, args=([], scalar_type,))
- def test_not_deprecated(self):
- # All specific types are not deprecated:
- for group in np.sctypes.values():
- for scalar_type in group:
- self.assert_not_deprecated(np.dtype, args=(scalar_type,))
- for scalar_type in [type, dict, list, tuple]:
- # Typical python types are coerced to object currently:
- self.assert_not_deprecated(np.dtype, args=(scalar_type,))
- class BuiltInRoundComplexDType(_DeprecationTestCase):
- # 2020-03-31 1.19.0
- deprecated_types = [np.csingle, np.cdouble, np.clongdouble]
- not_deprecated_types = [
- np.int8, np.int16, np.int32, np.int64,
- np.uint8, np.uint16, np.uint32, np.uint64,
- np.float16, np.float32, np.float64,
- ]
- def test_deprecated(self):
- for scalar_type in self.deprecated_types:
- scalar = scalar_type(0)
- self.assert_deprecated(round, args=(scalar,))
- self.assert_deprecated(round, args=(scalar, 0))
- self.assert_deprecated(round, args=(scalar,), kwargs={'ndigits': 0})
- def test_not_deprecated(self):
- for scalar_type in self.not_deprecated_types:
- scalar = scalar_type(0)
- self.assert_not_deprecated(round, args=(scalar,))
- self.assert_not_deprecated(round, args=(scalar, 0))
- self.assert_not_deprecated(round, args=(scalar,), kwargs={'ndigits': 0})
- class TestIncorrectAdvancedIndexWithEmptyResult(_DeprecationTestCase):
- # 2020-05-27, NumPy 1.20.0
- message = "Out of bound index found. This was previously ignored.*"
- @pytest.mark.parametrize("index", [([3, 0],), ([0, 0], [3, 0])])
- def test_empty_subspace(self, index):
- # Test for both a single and two/multiple advanced indices. These
- # This will raise an IndexError in the future.
- arr = np.ones((2, 2, 0))
- self.assert_deprecated(arr.__getitem__, args=(index,))
- self.assert_deprecated(arr.__setitem__, args=(index, 0.))
- # for this array, the subspace is only empty after applying the slice
- arr2 = np.ones((2, 2, 1))
- index2 = (slice(0, 0),) + index
- self.assert_deprecated(arr2.__getitem__, args=(index2,))
- self.assert_deprecated(arr2.__setitem__, args=(index2, 0.))
- def test_empty_index_broadcast_not_deprecated(self):
- arr = np.ones((2, 2, 2))
- index = ([[3], [2]], []) # broadcast to an empty result.
- self.assert_not_deprecated(arr.__getitem__, args=(index,))
- self.assert_not_deprecated(arr.__setitem__,
- args=(index, np.empty((2, 0, 2))))
- class TestNonExactMatchDeprecation(_DeprecationTestCase):
- # 2020-04-22
- def test_non_exact_match(self):
- arr = np.array([[3, 6, 6], [4, 5, 1]])
- # misspelt mode check
- self.assert_deprecated(lambda: np.ravel_multi_index(arr, (7, 6), mode='Cilp'))
- # using completely different word with first character as R
- self.assert_deprecated(lambda: np.searchsorted(arr[0], 4, side='Random'))
- class TestDeprecatedGlobals(_DeprecationTestCase):
- # 2020-06-06
- @pytest.mark.skipif(
- sys.version_info < (3, 7),
- reason='module-level __getattr__ not supported')
- def test_type_aliases(self):
- # from builtins
- self.assert_deprecated(lambda: np.bool(True))
- self.assert_deprecated(lambda: np.int(1))
- self.assert_deprecated(lambda: np.float(1))
- self.assert_deprecated(lambda: np.complex(1))
- self.assert_deprecated(lambda: np.object())
- self.assert_deprecated(lambda: np.str('abc'))
- # from np.compat
- self.assert_deprecated(lambda: np.long(1))
- self.assert_deprecated(lambda: np.unicode('abc'))
- class TestMatrixInOuter(_DeprecationTestCase):
- # 2020-05-13 NumPy 1.20.0
- message = (r"add.outer\(\) was passed a numpy matrix as "
- r"(first|second) argument.")
- def test_deprecated(self):
- arr = np.array([1, 2, 3])
- m = np.array([1, 2, 3]).view(np.matrix)
- self.assert_deprecated(np.add.outer, args=(m, m), num=2)
- self.assert_deprecated(np.add.outer, args=(arr, m))
- self.assert_deprecated(np.add.outer, args=(m, arr))
- self.assert_not_deprecated(np.add.outer, args=(arr, arr))
- class TestRaggedArray(_DeprecationTestCase):
- # 2020-07-24, NumPy 1.20.0
- message = "setting an array element with a sequence"
- def test_deprecated(self):
- arr = np.ones((1, 1))
- # Deprecated if the array is a leave node:
- self.assert_deprecated(lambda: np.array([arr, 0], dtype=np.float64))
- self.assert_deprecated(lambda: np.array([0, arr], dtype=np.float64))
- # And when it is an assignment into a lower dimensional subarray:
- self.assert_deprecated(lambda: np.array([arr, [0]], dtype=np.float64))
- self.assert_deprecated(lambda: np.array([[0], arr], dtype=np.float64))
- class FlatteningConcatenateUnsafeCast(_DeprecationTestCase):
- # NumPy 1.20, 2020-09-03
- message = "concatenate with `axis=None` will use same-kind casting"
- def test_deprecated(self):
- self.assert_deprecated(np.concatenate,
- args=(([0.], [1.]),),
- kwargs=dict(axis=None, out=np.empty(2, dtype=np.int64)))
- def test_not_deprecated(self):
- self.assert_not_deprecated(np.concatenate,
- args=(([0.], [1.]),),
- kwargs={'axis': None, 'out': np.empty(2, dtype=np.int64),
- 'casting': "unsafe"})
- with assert_raises(TypeError):
- # Tests should notice if the deprecation warning is given first...
- np.concatenate(([0.], [1.]), out=np.empty(2, dtype=np.int64),
- casting="same_kind")
- class TestDeprecateSubarrayDTypeDuringArrayCoercion(_DeprecationTestCase):
- warning_cls = FutureWarning
- message = "(creating|casting) an array (with|to) a subarray dtype"
- def test_deprecated_array(self):
- # Arrays are more complex, since they "broadcast" on success:
- arr = np.array([1, 2])
- self.assert_deprecated(lambda: arr.astype("(2)i,"))
- with pytest.warns(FutureWarning):
- res = arr.astype("(2)i,")
- assert_array_equal(res, [[1, 2], [1, 2]])
- self.assert_deprecated(lambda: np.array(arr, dtype="(2)i,"))
- with pytest.warns(FutureWarning):
- res = np.array(arr, dtype="(2)i,")
- assert_array_equal(res, [[1, 2], [1, 2]])
- with pytest.warns(FutureWarning):
- res = np.array([[(1,), (2,)], arr], dtype="(2)i,")
- assert_array_equal(res, [[[1, 1], [2, 2]], [[1, 2], [1, 2]]])
- def test_deprecated_and_error(self):
- # These error paths do not give a warning, but will succeed in the
- # future.
- arr = np.arange(5 * 2).reshape(5, 2)
- def check():
- with pytest.raises(ValueError):
- arr.astype("(2,2)f")
- self.assert_deprecated(check)
- def check():
- with pytest.raises(ValueError):
- np.array(arr, dtype="(2,2)f")
- self.assert_deprecated(check)
- class TestFutureWarningArrayLikeNotIterable(_DeprecationTestCase):
- # Deprecated 2020-12-09, NumPy 1.20
- warning_cls = FutureWarning
- message = "The input object of type.*but not a sequence"
- @pytest.mark.parametrize("protocol",
- ["__array__", "__array_interface__", "__array_struct__"])
- def test_deprecated(self, protocol):
- """Test that these objects give a warning since they are not 0-D,
- not coerced at the top level `np.array(obj)`, but nested, and do
- *not* define the sequence protocol.
- NOTE: Tests for the versions including __len__ and __getitem__ exist
- in `test_array_coercion.py` and they can be modified or ammended
- when this deprecation expired.
- """
- blueprint = np.arange(10)
- MyArr = type("MyArr", (), {protocol: getattr(blueprint, protocol)})
- self.assert_deprecated(lambda: np.array([MyArr()], dtype=object))
- @pytest.mark.parametrize("protocol",
- ["__array__", "__array_interface__", "__array_struct__"])
- def test_0d_not_deprecated(self, protocol):
- # 0-D always worked (albeit it would use __float__ or similar for the
- # conversion, which may not happen anymore)
- blueprint = np.array(1.)
- MyArr = type("MyArr", (), {protocol: getattr(blueprint, protocol)})
- myarr = MyArr()
- self.assert_not_deprecated(lambda: np.array([myarr], dtype=object))
- res = np.array([myarr], dtype=object)
- expected = np.empty(1, dtype=object)
- expected[0] = myarr
- assert_array_equal(res, expected)
- @pytest.mark.parametrize("protocol",
- ["__array__", "__array_interface__", "__array_struct__"])
- def test_unnested_not_deprecated(self, protocol):
- blueprint = np.arange(10)
- MyArr = type("MyArr", (), {protocol: getattr(blueprint, protocol)})
- myarr = MyArr()
- self.assert_not_deprecated(lambda: np.array(myarr))
- res = np.array(myarr)
- assert_array_equal(res, blueprint)
- @pytest.mark.parametrize("protocol",
- ["__array__", "__array_interface__", "__array_struct__"])
- def test_strange_dtype_handling(self, protocol):
- """The old code would actually use the dtype from the array, but
- then end up not using the array (for dimension discovery)
- """
- blueprint = np.arange(10).astype("f4")
- MyArr = type("MyArr", (), {protocol: getattr(blueprint, protocol),
- "__float__": lambda _: 0.5})
- myarr = MyArr()
- # Make sure we warn (and capture the FutureWarning)
- with pytest.warns(FutureWarning, match=self.message):
- res = np.array([[myarr]])
- assert res.shape == (1, 1)
- assert res.dtype == "f4"
- assert res[0, 0] == 0.5
- @pytest.mark.parametrize("protocol",
- ["__array__", "__array_interface__", "__array_struct__"])
- def test_assignment_not_deprecated(self, protocol):
- # If the result is dtype=object we do not unpack a nested array or
- # array-like, if it is nested at exactly the right depth.
- # NOTE: We actually do still call __array__, etc. but ignore the result
- # in the end. For `dtype=object` we could optimize that away.
- blueprint = np.arange(10).astype("f4")
- MyArr = type("MyArr", (), {protocol: getattr(blueprint, protocol),
- "__float__": lambda _: 0.5})
- myarr = MyArr()
- res = np.empty(3, dtype=object)
- def set():
- res[:] = [myarr, myarr, myarr]
- self.assert_not_deprecated(set)
- assert res[0] is myarr
- assert res[1] is myarr
- assert res[2] is myarr
- class TestDeprecatedUnpickleObjectScalar(_DeprecationTestCase):
- # Deprecated 2020-11-24, NumPy 1.20
- """
- Technically, it should be impossible to create numpy object scalars,
- but there was an unpickle path that would in theory allow it. That
- path is invalid and must lead to the warning.
- """
- message = "Unpickling a scalar with object dtype is deprecated."
- def test_deprecated(self):
- ctor = np.core.multiarray.scalar
- self.assert_deprecated(lambda: ctor(np.dtype("O"), 1))
|