diff options
Diffstat (limited to 'numpy/core/tests/test_multiarray.py')
-rw-r--r-- | numpy/core/tests/test_multiarray.py | 513 |
1 files changed, 402 insertions, 111 deletions
diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 027384fba..196c2dc13 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import collections.abc import tempfile import sys @@ -9,6 +11,7 @@ import functools import ctypes import os import gc +import re import weakref import pytest from contextlib import contextmanager @@ -27,11 +30,12 @@ from numpy.testing import ( assert_, assert_raises, assert_warns, assert_equal, assert_almost_equal, assert_array_equal, assert_raises_regex, assert_array_almost_equal, assert_allclose, IS_PYPY, IS_PYSTON, HAS_REFCOUNT, assert_array_less, - runstring, temppath, suppress_warnings, break_cycles, + runstring, temppath, suppress_warnings, break_cycles, _SUPPORTS_SVE, ) from numpy.testing._private.utils import requires_memory, _no_tracing from numpy.core.tests._locales import CommaDecimalPointLocale from numpy.lib.recfunctions import repack_fields +from numpy.core.multiarray import _get_ndarray_c_version # Need to test an object that does not fully implement math interface from datetime import timedelta, datetime @@ -402,6 +406,13 @@ class TestAttributes: assert_array_equal(x['a'], [3.5, 3.5]) assert_array_equal(x['b'], [-2, -2]) + def test_fill_readonly(self): + # gh-22922 + a = np.zeros(11) + a.setflags(write=False) + with pytest.raises(ValueError, match=".*read-only"): + a.fill(0) + class TestArrayConstruction: def test_array(self): @@ -1185,6 +1196,17 @@ class TestCreation: expected = expected * (arr.nbytes // len(expected)) assert arr.tobytes() == expected + @pytest.mark.parametrize("func", [ + np.array, np.asarray, np.asanyarray, np.ascontiguousarray, + np.asfortranarray]) + def test_creation_from_dtypemeta(self, func): + dtype = np.dtype('i') + arr1 = func([1, 2, 3], dtype=dtype) + arr2 = func([1, 2, 3], dtype=type(dtype)) + assert_array_equal(arr1, arr2) + assert arr2.dtype == dtype + + class TestStructured: def test_subarray_field_access(self): a = np.zeros((3, 5), dtype=[('a', ('i4', (2, 2)))]) @@ -1257,9 +1279,9 @@ class TestStructured: # The main importance is that it does not return True: with pytest.raises(TypeError): x == y - + def test_empty_structured_array_comparison(self): - # Check that comparison works on empty arrays with nontrivially + # Check that comparison works on empty arrays with nontrivially # shaped fields a = np.zeros(0, [('a', '<f8', (1, 1))]) assert_equal(a, a) @@ -1270,6 +1292,13 @@ class TestStructured: a = np.zeros((1, 0, 1), [('a', '<f8', (1, 1))]) assert_equal(a, a) + @pytest.mark.parametrize("op", [operator.eq, operator.ne]) + def test_structured_array_comparison_bad_broadcasts(self, op): + a = np.zeros(3, dtype='i,i') + b = np.array([], dtype="i,i") + with pytest.raises(ValueError): + op(a, b) + def test_structured_comparisons_with_promotion(self): # Check that structured arrays can be compared so long as their # dtypes promote fine: @@ -1290,7 +1319,10 @@ class TestStructured: assert_equal(a == b, [False, True]) assert_equal(a != b, [True, False]) - def test_void_comparison_failures(self): + @pytest.mark.parametrize("op", [ + operator.eq, lambda x, y: operator.eq(y, x), + operator.ne, lambda x, y: operator.ne(y, x)]) + def test_void_comparison_failures(self, op): # In principle, one could decide to return an array of False for some # if comparisons are impossible. But right now we return TypeError # when "void" dtype are involved. @@ -1298,18 +1330,18 @@ class TestStructured: y = np.zeros(3) # Cannot compare non-structured to structured: with pytest.raises(TypeError): - x == y + op(x, y) # Added title prevents promotion, but casts are OK: y = np.zeros(3, dtype=[(('title', 'a'), 'i1')]) assert np.can_cast(y.dtype, x.dtype) with pytest.raises(TypeError): - x == y + op(x, y) x = np.zeros(3, dtype="V7") y = np.zeros(3, dtype="V8") with pytest.raises(TypeError): - x == y + op(x, y) def test_casting(self): # Check that casting a structured array to change its byte order @@ -1687,7 +1719,7 @@ class TestBool: @pytest.mark.xfail(reason="See gh-9847") def test_cast_from_unicode(self): - self._test_cast_from_flexible(np.unicode_) + self._test_cast_from_flexible(np.str_) @pytest.mark.xfail(reason="See gh-9847") def test_cast_from_bytes(self): @@ -1902,8 +1934,9 @@ class TestMethods: assert_array_equal(a2.prod(axis=-1), np.array([24, 1890, 600], ctype)) - def test_repeat(self): - m = np.array([1, 2, 3, 4, 5, 6]) + @pytest.mark.parametrize('dtype', [None, object]) + def test_repeat(self, dtype): + m = np.array([1, 2, 3, 4, 5, 6], dtype=dtype) m_rect = m.reshape((2, 3)) A = m.repeat([1, 3, 2, 1, 1, 2]) @@ -2069,7 +2102,7 @@ class TestMethods: msg = 'byte-swapped complex sort, dtype={0}'.format(dt) assert_equal(c, arr, msg) - @pytest.mark.parametrize('dtype', [np.bytes_, np.unicode_]) + @pytest.mark.parametrize('dtype', [np.bytes_, np.str_]) def test_sort_string(self, dtype): # np.array will perform the encoding to bytes for us in the bytes test a = np.array(['aaaaaaaa' + chr(i) for i in range(101)], dtype=dtype) @@ -2097,19 +2130,26 @@ class TestMethods: c.sort(kind=kind) assert_equal(c, a, msg) - def test_sort_structured(self): + @pytest.mark.parametrize("dt", [ + np.dtype([('f', float), ('i', int)]), + np.dtype([('f', float), ('i', object)])]) + @pytest.mark.parametrize("step", [1, 2]) + def test_sort_structured(self, dt, step): # test record array sorts. - dt = np.dtype([('f', float), ('i', int)]) - a = np.array([(i, i) for i in range(101)], dtype=dt) + a = np.array([(i, i) for i in range(101*step)], dtype=dt) b = a[::-1] for kind in ['q', 'h', 'm']: msg = "kind=%s" % kind - c = a.copy() + c = a.copy()[::step] + indx = c.argsort(kind=kind) c.sort(kind=kind) - assert_equal(c, a, msg) - c = b.copy() + assert_equal(c, a[::step], msg) + assert_equal(a[::step][indx], a[::step], msg) + c = b.copy()[::step] + indx = c.argsort(kind=kind) c.sort(kind=kind) - assert_equal(c, a, msg) + assert_equal(c, a[step-1::step], msg) + assert_equal(b[::step][indx], a[step-1::step], msg) @pytest.mark.parametrize('dtype', ['datetime64[D]', 'timedelta64[D]']) def test_sort_time(self, dtype): @@ -2232,7 +2272,7 @@ class TestMethods: assert_c(a.copy('C')) assert_fortran(a.copy('F')) assert_c(a.copy('A')) - + @pytest.mark.parametrize("dtype", ['O', np.int32, 'i,O']) def test__deepcopy__(self, dtype): # Force the entry of NULLs into array @@ -2343,7 +2383,7 @@ class TestMethods: # test unicode argsorts. s = 'aaaaaaaa' - a = np.array([s + chr(i) for i in range(101)], dtype=np.unicode_) + a = np.array([s + chr(i) for i in range(101)], dtype=np.str_) b = a[::-1] r = np.arange(101) rr = r[::-1] @@ -2426,7 +2466,7 @@ class TestMethods: a = np.array(['aaaaaaaaa' for i in range(100)]) assert_equal(a.argsort(kind='m'), r) # unicode - a = np.array(['aaaaaaaaa' for i in range(100)], dtype=np.unicode_) + a = np.array(['aaaaaaaaa' for i in range(100)], dtype=np.str_) assert_equal(a.argsort(kind='m'), r) def test_sort_unicode_kind(self): @@ -2441,7 +2481,7 @@ class TestMethods: np.array([0, 1, np.nan]), ]) def test_searchsorted_floats(self, a): - # test for floats arrays containing nans. Explicitly test + # test for floats arrays containing nans. Explicitly test # half, single, and double precision floats to verify that # the NaN-handling is correct. msg = "Test real (%s) searchsorted with nans, side='l'" % a.dtype @@ -2457,7 +2497,7 @@ class TestMethods: assert_equal(y, 2) def test_searchsorted_complex(self): - # test for complex arrays containing nans. + # test for complex arrays containing nans. # The search sorted routines use the compare functions for the # array type, so this checks if that is consistent with the sort # order. @@ -2479,7 +2519,7 @@ class TestMethods: a = np.array([0, 128], dtype='>i4') b = a.searchsorted(np.array(128, dtype='>i4')) assert_equal(b, 1, msg) - + def test_searchsorted_n_elements(self): # Check 0 elements a = np.ones(0) @@ -2570,7 +2610,7 @@ class TestMethods: 'P:\\20x_dapi_cy3\\20x_dapi_cy3_20100197_1', 'P:\\20x_dapi_cy3\\20x_dapi_cy3_20100198_1', 'P:\\20x_dapi_cy3\\20x_dapi_cy3_20100199_1'], - dtype=np.unicode_) + dtype=np.str_) ind = np.arange(len(a)) assert_equal([a.searchsorted(v, 'left') for v in a], ind) assert_equal([a.searchsorted(v, 'right') for v in a], ind + 1) @@ -3605,9 +3645,13 @@ class TestMethods: msg = 'dtype: {0}'.format(dt) ap = complex(a) assert_equal(ap, a, msg) - bp = complex(b) + + with assert_warns(DeprecationWarning): + bp = complex(b) assert_equal(bp, b, msg) - cp = complex(c) + + with assert_warns(DeprecationWarning): + cp = complex(c) assert_equal(cp, c, msg) def test__complex__should_not_work(self): @@ -3630,7 +3674,8 @@ class TestMethods: assert_raises(TypeError, complex, d) e = np.array(['1+1j'], 'U') - assert_raises(TypeError, complex, e) + with assert_warns(DeprecationWarning): + assert_raises(TypeError, complex, e) class TestCequenceMethods: def test_array_contains(self): @@ -3692,7 +3737,7 @@ class TestBinop: 'and': (np.bitwise_and, True, int), 'xor': (np.bitwise_xor, True, int), 'or': (np.bitwise_or, True, int), - 'matmul': (np.matmul, False, float), + 'matmul': (np.matmul, True, float), # 'ge': (np.less_equal, False), # 'gt': (np.less, False), # 'le': (np.greater_equal, False), @@ -4710,23 +4755,23 @@ class TestArgmax: a = np.array([1, 2**7 - 1, -2**7], dtype=np.int8) assert_equal(np.argmax(a), 1) - a.repeat(129) - assert_equal(np.argmax(a), 1) + a = a.repeat(129) + assert_equal(np.argmax(a), 129) a = np.array([1, 2**15 - 1, -2**15], dtype=np.int16) assert_equal(np.argmax(a), 1) - a.repeat(129) - assert_equal(np.argmax(a), 1) + a = a.repeat(129) + assert_equal(np.argmax(a), 129) a = np.array([1, 2**31 - 1, -2**31], dtype=np.int32) assert_equal(np.argmax(a), 1) - a.repeat(129) - assert_equal(np.argmax(a), 1) + a = a.repeat(129) + assert_equal(np.argmax(a), 129) a = np.array([1, 2**63 - 1, -2**63], dtype=np.int64) assert_equal(np.argmax(a), 1) - a.repeat(129) - assert_equal(np.argmax(a), 1) + a = a.repeat(129) + assert_equal(np.argmax(a), 129) class TestArgmin: usg_data = [ @@ -4852,23 +4897,23 @@ class TestArgmin: a = np.array([1, -2**7, -2**7 + 1, 2**7 - 1], dtype=np.int8) assert_equal(np.argmin(a), 1) - a.repeat(129) - assert_equal(np.argmin(a), 1) + a = a.repeat(129) + assert_equal(np.argmin(a), 129) a = np.array([1, -2**15, -2**15 + 1, 2**15 - 1], dtype=np.int16) assert_equal(np.argmin(a), 1) - a.repeat(129) - assert_equal(np.argmin(a), 1) + a = a.repeat(129) + assert_equal(np.argmin(a), 129) a = np.array([1, -2**31, -2**31 + 1, 2**31 - 1], dtype=np.int32) assert_equal(np.argmin(a), 1) - a.repeat(129) - assert_equal(np.argmin(a), 1) + a = a.repeat(129) + assert_equal(np.argmin(a), 129) a = np.array([1, -2**63, -2**63 + 1, 2**63 - 1], dtype=np.int64) assert_equal(np.argmin(a), 1) - a.repeat(129) - assert_equal(np.argmin(a), 1) + a = a.repeat(129) + assert_equal(np.argmin(a), 129) class TestMinMax: @@ -5066,6 +5111,22 @@ class TestPutmask: with pytest.raises(ValueError): np.putmask(a, a >= 2, 3) + def test_kwargs(self): + x = np.array([0, 0]) + np.putmask(x, [0, 1], [-1, -2]) + assert_array_equal(x, [0, -2]) + + x = np.array([0, 0]) + np.putmask(x, mask=[0, 1], values=[-1, -2]) + assert_array_equal(x, [0, -2]) + + x = np.array([0, 0]) + np.putmask(x, values=[-1, -2], mask=[0, 1]) + assert_array_equal(x, [0, -2]) + + with pytest.raises(TypeError): + np.putmask(a=x, values=[-1, -2], mask=[0, 1]) + class TestTake: def tst_basic(self, x): @@ -5517,33 +5578,6 @@ class TestIO: tmp_filename, dtype='<f4') - @pytest.mark.slow # takes > 1 minute on mechanical hard drive - def test_big_binary(self): - """Test workarounds for 32-bit limit for MSVC fwrite, fseek, and ftell - - These normally would hang doing something like this. - See : https://github.com/numpy/numpy/issues/2256 - """ - if sys.platform != 'win32' or '[GCC ' in sys.version: - return - try: - # before workarounds, only up to 2**32-1 worked - fourgbplus = 2**32 + 2**16 - testbytes = np.arange(8, dtype=np.int8) - n = len(testbytes) - flike = tempfile.NamedTemporaryFile() - f = flike.file - np.tile(testbytes, fourgbplus // testbytes.nbytes).tofile(f) - flike.seek(0) - a = np.fromfile(f, dtype=np.int8) - flike.close() - assert_(len(a) == fourgbplus) - # check only start and end for speed: - assert_((a[:n] == testbytes).all()) - assert_((a[-n:] == testbytes).all()) - except (MemoryError, ValueError): - pass - def test_string(self, tmp_filename): self._check_from(b'1,2,3,4', [1., 2., 3., 4.], tmp_filename, sep=',') @@ -6196,7 +6230,7 @@ class TestStats: def test_mean_axis_error(self): # Ensure that AxisError is raised instead of IndexError when axis is # out of bounds, see gh-15817. - with assert_raises(np.core._exceptions.AxisError): + with assert_raises(np.exceptions.AxisError): np.arange(10).mean(axis=2) def test_mean_where(self): @@ -6280,7 +6314,7 @@ class TestStats: def test_var_axis_error(self): # Ensure that AxisError is raised instead of IndexError when axis is # out of bounds, see gh-15817. - with assert_raises(np.core._exceptions.AxisError): + with assert_raises(np.exceptions.AxisError): np.arange(10).var(axis=2) def test_var_where(self): @@ -6647,6 +6681,22 @@ class TestDot: r = np.empty((1024, 32), dtype=int) assert_raises(ValueError, dot, f, v, r) + def test_dot_out_result(self): + x = np.ones((), dtype=np.float16) + y = np.ones((5,), dtype=np.float16) + z = np.zeros((5,), dtype=np.float16) + res = x.dot(y, out=z) + assert np.array_equal(res, y) + assert np.array_equal(z, y) + + def test_dot_out_aliasing(self): + x = np.ones((), dtype=np.float16) + y = np.ones((5,), dtype=np.float16) + z = np.zeros((5,), dtype=np.float16) + res = x.dot(y, out=z) + z[0] = 2 + assert np.array_equal(res, z) + def test_dot_array_order(self): a = np.array([[1, 2], [3, 4]], order='C') b = np.array([[1, 2], [3, 4]], order='F') @@ -6731,6 +6781,18 @@ class TestDot: res = np.dot(data, data) assert res == 2**30+100 + def test_dtype_discovery_fails(self): + # See gh-14247, error checking was missing for failed dtype discovery + class BadObject(object): + def __array__(self): + raise TypeError("just this tiny mint leaf") + + with pytest.raises(TypeError): + np.dot(BadObject(), BadObject()) + + with pytest.raises(TypeError): + np.dot(3.0, BadObject()) + class MatmulCommon: """Common tests for '@' operator and numpy.matmul. @@ -7142,16 +7204,69 @@ class TestMatmulOperator(MatmulCommon): assert_raises(TypeError, self.matmul, np.void(b'abc'), np.void(b'abc')) assert_raises(TypeError, self.matmul, np.arange(10), np.void(b'abc')) -def test_matmul_inplace(): - # It would be nice to support in-place matmul eventually, but for now - # we don't have a working implementation, so better just to error out - # and nudge people to writing "a = a @ b". - a = np.eye(3) - b = np.eye(3) - assert_raises(TypeError, a.__imatmul__, b) - import operator - assert_raises(TypeError, operator.imatmul, a, b) - assert_raises(TypeError, exec, "a @= b", globals(), locals()) + +class TestMatmulInplace: + DTYPES = {} + for i in MatmulCommon.types: + for j in MatmulCommon.types: + if np.can_cast(j, i): + DTYPES[f"{i}-{j}"] = (np.dtype(i), np.dtype(j)) + + @pytest.mark.parametrize("dtype1,dtype2", DTYPES.values(), ids=DTYPES) + def test_basic(self, dtype1: np.dtype, dtype2: np.dtype) -> None: + a = np.arange(10).reshape(5, 2).astype(dtype1) + a_id = id(a) + b = np.ones((2, 2), dtype=dtype2) + + ref = a @ b + a @= b + + assert id(a) == a_id + assert a.dtype == dtype1 + assert a.shape == (5, 2) + if dtype1.kind in "fc": + np.testing.assert_allclose(a, ref) + else: + np.testing.assert_array_equal(a, ref) + + SHAPES = { + "2d_large": ((10**5, 10), (10, 10)), + "3d_large": ((10**4, 10, 10), (1, 10, 10)), + "1d": ((3,), (3,)), + "2d_1d": ((3, 3), (3,)), + "1d_2d": ((3,), (3, 3)), + "2d_broadcast": ((3, 3), (3, 1)), + "2d_broadcast_reverse": ((1, 3), (3, 3)), + "3d_broadcast1": ((3, 3, 3), (1, 3, 1)), + "3d_broadcast2": ((3, 3, 3), (1, 3, 3)), + "3d_broadcast3": ((3, 3, 3), (3, 3, 1)), + "3d_broadcast_reverse1": ((1, 3, 3), (3, 3, 3)), + "3d_broadcast_reverse2": ((3, 1, 3), (3, 3, 3)), + "3d_broadcast_reverse3": ((1, 1, 3), (3, 3, 3)), + } + + @pytest.mark.parametrize("a_shape,b_shape", SHAPES.values(), ids=SHAPES) + def test_shapes(self, a_shape: tuple[int, ...], b_shape: tuple[int, ...]): + a_size = np.prod(a_shape) + a = np.arange(a_size).reshape(a_shape).astype(np.float64) + a_id = id(a) + + b_size = np.prod(b_shape) + b = np.arange(b_size).reshape(b_shape) + + ref = a @ b + if ref.shape != a_shape: + with pytest.raises(ValueError): + a @= b + return + else: + a @= b + + assert id(a) == a_id + assert a.dtype.type == np.float64 + assert a.shape == a_shape + np.testing.assert_allclose(a, ref) + def test_matmul_axes(): a = np.arange(3*4*5).reshape(3, 4, 5) @@ -8647,14 +8762,16 @@ class TestConversion: int_funcs = (int, lambda x: x.__int__()) for int_func in int_funcs: assert_equal(int_func(np.array(0)), 0) - assert_equal(int_func(np.array([1])), 1) - assert_equal(int_func(np.array([[42]])), 42) + with assert_warns(DeprecationWarning): + assert_equal(int_func(np.array([1])), 1) + with assert_warns(DeprecationWarning): + assert_equal(int_func(np.array([[42]])), 42) assert_raises(TypeError, int_func, np.array([1, 2])) # gh-9972 assert_equal(4, int_func(np.array('4'))) assert_equal(5, int_func(np.bytes_(b'5'))) - assert_equal(6, int_func(np.unicode_('6'))) + assert_equal(6, int_func(np.str_('6'))) # The delegation of int() to __trunc__ was deprecated in # Python 3.11. @@ -8663,7 +8780,8 @@ class TestConversion: def __trunc__(self): return 3 assert_equal(3, int_func(np.array(HasTrunc()))) - assert_equal(3, int_func(np.array([HasTrunc()]))) + with assert_warns(DeprecationWarning): + assert_equal(3, int_func(np.array([HasTrunc()]))) else: pass @@ -8672,8 +8790,9 @@ class TestConversion: raise NotImplementedError assert_raises(NotImplementedError, int_func, np.array(NotConvertible())) - assert_raises(NotImplementedError, - int_func, np.array([NotConvertible()])) + with assert_warns(DeprecationWarning): + assert_raises(NotImplementedError, + int_func, np.array([NotConvertible()])) class TestWhere: @@ -8840,6 +8959,11 @@ class TestWhere: result = array.nonzero() assert_array_equal(benchmark, result) + def test_kwargs(self): + a = np.zeros(1) + with assert_raises(TypeError): + np.where(a, x=a, y=a) + if not IS_PYPY: # sys.getsizeof() is not valid on PyPy @@ -9021,33 +9145,33 @@ class TestUnicodeEncoding: def test_assign_scalar(self): # gh-3258 l = np.array(['aa', 'bb']) - l[:] = np.unicode_('cc') + l[:] = np.str_('cc') assert_equal(l, ['cc', 'cc']) def test_fill_scalar(self): # gh-7227 l = np.array(['aa', 'bb']) - l.fill(np.unicode_('cc')) + l.fill(np.str_('cc')) assert_equal(l, ['cc', 'cc']) class TestUnicodeArrayNonzero: def test_empty_ustring_array_is_falsey(self): - assert_(not np.array([''], dtype=np.unicode_)) + assert_(not np.array([''], dtype=np.str_)) def test_whitespace_ustring_array_is_falsey(self): - a = np.array(['eggs'], dtype=np.unicode_) + a = np.array(['eggs'], dtype=np.str_) a[0] = ' \0\0' assert_(not a) def test_all_null_ustring_array_is_falsey(self): - a = np.array(['eggs'], dtype=np.unicode_) + a = np.array(['eggs'], dtype=np.str_) a[0] = '\0\0\0\0' assert_(not a) def test_null_inside_ustring_array_is_truthy(self): - a = np.array(['eggs'], dtype=np.unicode_) + a = np.array(['eggs'], dtype=np.str_) a[0] = ' \0 \0' assert_(a) @@ -9312,6 +9436,61 @@ class TestArange: assert len(keyword_start_stop) == 6 assert_array_equal(keyword_stop, keyword_zerotostop) + def test_arange_booleans(self): + # Arange makes some sense for booleans and works up to length 2. + # But it is weird since `arange(2, 4, dtype=bool)` works. + # Arguably, much or all of this could be deprecated/removed. + res = np.arange(False, dtype=bool) + assert_array_equal(res, np.array([], dtype="bool")) + + res = np.arange(True, dtype="bool") + assert_array_equal(res, [False]) + + res = np.arange(2, dtype="bool") + assert_array_equal(res, [False, True]) + + # This case is especially weird, but drops out without special case: + res = np.arange(6, 8, dtype="bool") + assert_array_equal(res, [True, True]) + + with pytest.raises(TypeError): + np.arange(3, dtype="bool") + + @pytest.mark.parametrize("dtype", ["S3", "U", "5i"]) + def test_rejects_bad_dtypes(self, dtype): + dtype = np.dtype(dtype) + DType_name = re.escape(str(type(dtype))) + with pytest.raises(TypeError, + match=rf"arange\(\) not supported for inputs .* {DType_name}"): + np.arange(2, dtype=dtype) + + def test_rejects_strings(self): + # Explicitly test error for strings which may call "b" - "a": + DType_name = re.escape(str(type(np.array("a").dtype))) + with pytest.raises(TypeError, + match=rf"arange\(\) not supported for inputs .* {DType_name}"): + np.arange("a", "b") + + def test_byteswapped(self): + res_be = np.arange(1, 1000, dtype=">i4") + res_le = np.arange(1, 1000, dtype="<i4") + assert res_be.dtype == ">i4" + assert res_le.dtype == "<i4" + assert_array_equal(res_le, res_be) + + @pytest.mark.parametrize("which", [0, 1, 2]) + def test_error_paths_and_promotion(self, which): + args = [0, 1, 2] # start, stop, and step + args[which] = np.float64(2.) # should ensure float64 output + + assert np.arange(*args).dtype == np.float64 + + # Cover stranger error path, test only to achieve code coverage! + args[which] = [None, []] + with pytest.raises(ValueError): + # Fails discovering start dtype + np.arange(*args) + class TestArrayFinalize: """ Tests __array_finalize__ """ @@ -9425,6 +9604,105 @@ def test_equal_override(): assert_equal(array != my_always_equal, 'ne') +@pytest.mark.parametrize("op", [operator.eq, operator.ne]) +@pytest.mark.parametrize(["dt1", "dt2"], [ + ([("f", "i")], [("f", "i")]), # structured comparison (successful) + ("M8", "d"), # impossible comparison: result is all True or False + ("d", "d"), # valid comparison + ]) +def test_equal_subclass_no_override(op, dt1, dt2): + # Test how the three different possible code-paths deal with subclasses + + class MyArr(np.ndarray): + called_wrap = 0 + + def __array_wrap__(self, new): + type(self).called_wrap += 1 + return super().__array_wrap__(new) + + numpy_arr = np.zeros(5, dtype=dt1) + my_arr = np.zeros(5, dtype=dt2).view(MyArr) + + assert type(op(numpy_arr, my_arr)) is MyArr + assert type(op(my_arr, numpy_arr)) is MyArr + # We expect 2 calls (more if there were more fields): + assert MyArr.called_wrap == 2 + + +@pytest.mark.parametrize(["dt1", "dt2"], [ + ("M8[ns]", "d"), + ("M8[s]", "l"), + ("m8[ns]", "d"), + # Missing: ("m8[ns]", "l") as timedelta currently promotes ints + ("M8[s]", "m8[s]"), + ("S5", "U5"), + # Structured/void dtypes have explicit paths not tested here. +]) +def test_no_loop_gives_all_true_or_false(dt1, dt2): + # Make sure they broadcast to test result shape, use random values, since + # the actual value should be ignored + arr1 = np.random.randint(5, size=100).astype(dt1) + arr2 = np.random.randint(5, size=99)[:, np.newaxis].astype(dt2) + + res = arr1 == arr2 + assert res.shape == (99, 100) + assert res.dtype == bool + assert not res.any() + + res = arr1 != arr2 + assert res.shape == (99, 100) + assert res.dtype == bool + assert res.all() + + # incompatible shapes raise though + arr2 = np.random.randint(5, size=99).astype(dt2) + with pytest.raises(ValueError): + arr1 == arr2 + + with pytest.raises(ValueError): + arr1 != arr2 + + # Basic test with another operation: + with pytest.raises(np.core._exceptions._UFuncNoLoopError): + arr1 > arr2 + + +@pytest.mark.parametrize("op", [ + operator.eq, operator.ne, operator.le, operator.lt, operator.ge, + operator.gt]) +def test_comparisons_forwards_error(op): + class NotArray: + def __array__(self): + raise TypeError("run you fools") + + with pytest.raises(TypeError, match="run you fools"): + op(np.arange(2), NotArray()) + + with pytest.raises(TypeError, match="run you fools"): + op(NotArray(), np.arange(2)) + + +def test_richcompare_scalar_boolean_singleton_return(): + # These are currently guaranteed to be the boolean singletons, but maybe + # returning NumPy booleans would also be OK: + assert (np.array(0) == "a") is False + assert (np.array(0) != "a") is True + assert (np.int16(0) == "a") is False + assert (np.int16(0) != "a") is True + + +@pytest.mark.parametrize("op", [ + operator.eq, operator.ne, operator.le, operator.lt, operator.ge, + operator.gt]) +def test_ragged_comparison_fails(op): + # This needs to convert the internal array to True/False, which fails: + a = np.array([1, np.array([1, 2, 3])], dtype=object) + b = np.array([1, np.array([1, 2, 3])], dtype=object) + + with pytest.raises(ValueError, match="The truth value.*ambiguous"): + op(a, b) + + @pytest.mark.parametrize( ["fun", "npfun"], [ @@ -9651,40 +9929,50 @@ class TestViewDtype: assert_array_equal(x.view('<i2'), expected) +@pytest.mark.xfail(_SUPPORTS_SVE, reason="gh-22982") # Test various array sizes that hit different code paths in quicksort-avx512 -@pytest.mark.parametrize("N", [8, 16, 24, 32, 48, 64, 96, 128, 151, 191, - 256, 383, 512, 1023, 2047]) -def test_sort_float(N): +@pytest.mark.parametrize("N", np.arange(1, 512)) +@pytest.mark.parametrize("dtype", ['e', 'f', 'd']) +def test_sort_float(N, dtype): # Regular data with nan sprinkled np.random.seed(42) - arr = -0.5 + np.random.sample(N).astype('f') + arr = -0.5 + np.random.sample(N).astype(dtype) arr[np.random.choice(arr.shape[0], 3)] = np.nan assert_equal(np.sort(arr, kind='quick'), np.sort(arr, kind='heap')) # (2) with +INF - infarr = np.inf*np.ones(N, dtype='f') + infarr = np.inf*np.ones(N, dtype=dtype) infarr[np.random.choice(infarr.shape[0], 5)] = -1.0 assert_equal(np.sort(infarr, kind='quick'), np.sort(infarr, kind='heap')) # (3) with -INF - neginfarr = -np.inf*np.ones(N, dtype='f') + neginfarr = -np.inf*np.ones(N, dtype=dtype) neginfarr[np.random.choice(neginfarr.shape[0], 5)] = 1.0 assert_equal(np.sort(neginfarr, kind='quick'), np.sort(neginfarr, kind='heap')) # (4) with +/-INF - infarr = np.inf*np.ones(N, dtype='f') + infarr = np.inf*np.ones(N, dtype=dtype) infarr[np.random.choice(infarr.shape[0], (int)(N/2))] = -np.inf assert_equal(np.sort(infarr, kind='quick'), np.sort(infarr, kind='heap')) - -def test_sort_int(): - # Random data with NPY_MAX_INT32 and NPY_MIN_INT32 sprinkled - rng = np.random.default_rng(42) - N = 2047 - minv = np.iinfo(np.int32).min - maxv = np.iinfo(np.int32).max - arr = rng.integers(low=minv, high=maxv, size=N).astype('int32') +def test_sort_float16(): + arr = np.arange(65536, dtype=np.int16) + temp = np.frombuffer(arr.tobytes(), dtype=np.float16) + data = np.copy(temp) + np.random.shuffle(data) + data_backup = data + assert_equal(np.sort(data, kind='quick'), + np.sort(data_backup, kind='heap')) + + +@pytest.mark.parametrize("N", np.arange(1, 512)) +@pytest.mark.parametrize("dtype", ['h', 'H', 'i', 'I', 'l', 'L']) +def test_sort_int(N, dtype): + # Random data with MAX and MIN sprinkled + minv = np.iinfo(dtype).min + maxv = np.iinfo(dtype).max + arr = np.random.randint(low=minv, high=maxv-1, size=N, dtype=dtype) arr[np.random.choice(arr.shape[0], 10)] = minv arr[np.random.choice(arr.shape[0], 10)] = maxv assert_equal(np.sort(arr, kind='quick'), np.sort(arr, kind='heap')) @@ -9698,3 +9986,6 @@ def test_sort_uint(): arr = rng.integers(low=0, high=maxv, size=N).astype('uint32') arr[np.random.choice(arr.shape[0], 10)] = maxv assert_equal(np.sort(arr, kind='quick'), np.sort(arr, kind='heap')) + +def test_private_get_ndarray_c_version(): + assert isinstance(_get_ndarray_c_version(), int) |