diff options
22 files changed, 47 insertions, 62 deletions
diff --git a/doc/release/upcoming_changes/14800.improvement.rst b/doc/release/upcoming_changes/14800.improvement.rst deleted file mode 100644 index 158c31536..000000000 --- a/doc/release/upcoming_changes/14800.improvement.rst +++ /dev/null @@ -1,14 +0,0 @@ -Comparison on ``object`` dtypes will prefer ``object`` output -------------------------------------------------------------- -Comparison ufuncs (``np.equal`` and friends) would return boolean arrays when -the input array dtype was ``object``. This led to inconsistent behaviour for -ragged arrays ``a = np.array([1, np.array([1, 2, 3])], dtype=object)``. This -will now return an object array:: - - >>> a = np.array([1, np.array([1, 2, 3])], dtype=object) - >>> np.equal(a, a) - array([True, array([ True, True, True])], dtype=object) - -The old behaviour, which will raise a ``ValueError`` in this case, is still -available by specifying a dtype as ``np.equal(a, a, dtype=bool)``. - diff --git a/numpy/core/code_generators/generate_umath.py b/numpy/core/code_generators/generate_umath.py index 760b9c919..9e67a45ef 100644 --- a/numpy/core/code_generators/generate_umath.py +++ b/numpy/core/code_generators/generate_umath.py @@ -227,6 +227,8 @@ chartoname = { } noobj = '?bBhHiIlLqQefdgFDGmM' +all = '?bBhHiIlLqQefdgFDGOmM' + O = 'O' P = 'P' ints = 'bBhHiIlLqQ' @@ -429,7 +431,7 @@ defdict = { Ufunc(2, 1, None, docstrings.get('numpy.core.umath.greater'), 'PyUFunc_SimpleBinaryComparisonTypeResolver', - TD(noobj, out='?', simd=[('avx2', ints)]), + TD(all, out='?', simd=[('avx2', ints)]), [TypeDescription('O', FullTypeDescr, 'OO', 'O')], TD('O', out='?'), ), @@ -437,7 +439,7 @@ defdict = { Ufunc(2, 1, None, docstrings.get('numpy.core.umath.greater_equal'), 'PyUFunc_SimpleBinaryComparisonTypeResolver', - TD(noobj, out='?', simd=[('avx2', ints)]), + TD(all, out='?', simd=[('avx2', ints)]), [TypeDescription('O', FullTypeDescr, 'OO', 'O')], TD('O', out='?'), ), @@ -445,7 +447,7 @@ defdict = { Ufunc(2, 1, None, docstrings.get('numpy.core.umath.less'), 'PyUFunc_SimpleBinaryComparisonTypeResolver', - TD(noobj, out='?', simd=[('avx2', ints)]), + TD(all, out='?', simd=[('avx2', ints)]), [TypeDescription('O', FullTypeDescr, 'OO', 'O')], TD('O', out='?'), ), @@ -453,7 +455,7 @@ defdict = { Ufunc(2, 1, None, docstrings.get('numpy.core.umath.less_equal'), 'PyUFunc_SimpleBinaryComparisonTypeResolver', - TD(noobj, out='?', simd=[('avx2', ints)]), + TD(all, out='?', simd=[('avx2', ints)]), [TypeDescription('O', FullTypeDescr, 'OO', 'O')], TD('O', out='?'), ), @@ -461,7 +463,7 @@ defdict = { Ufunc(2, 1, None, docstrings.get('numpy.core.umath.equal'), 'PyUFunc_SimpleBinaryComparisonTypeResolver', - TD(noobj, out='?', simd=[('avx2', ints)]), + TD(all, out='?', simd=[('avx2', ints)]), [TypeDescription('O', FullTypeDescr, 'OO', 'O')], TD('O', out='?'), ), @@ -469,7 +471,7 @@ defdict = { Ufunc(2, 1, None, docstrings.get('numpy.core.umath.not_equal'), 'PyUFunc_SimpleBinaryComparisonTypeResolver', - TD(noobj, out='?', simd=[('avx2', ints)]), + TD(all, out='?', simd=[('avx2', ints)]), [TypeDescription('O', FullTypeDescr, 'OO', 'O')], TD('O', out='?'), ), diff --git a/numpy/core/setup.py b/numpy/core/setup.py index a33318472..a4b5cfe5f 100644 --- a/numpy/core/setup.py +++ b/numpy/core/setup.py @@ -774,7 +774,7 @@ def configuration(parent_package='',top_path=None): join('src', 'multiarray', 'arrayobject.h'), join('src', 'multiarray', 'arraytypes.h'), join('src', 'multiarray', 'arrayfunction_override.h'), - join('src', 'multiarray', 'buffer.h'), + join('src', 'multiarray', 'npy_buffer.h'), join('src', 'multiarray', 'calculation.h'), join('src', 'multiarray', 'common.h'), join('src', 'multiarray', 'convert_datatype.h'), diff --git a/numpy/core/src/multiarray/arrayobject.c b/numpy/core/src/multiarray/arrayobject.c index 5ed5b7635..a5cebfbd8 100644 --- a/numpy/core/src/multiarray/arrayobject.c +++ b/numpy/core/src/multiarray/arrayobject.c @@ -48,7 +48,7 @@ maintainer email: oliphant.travis@ieee.org #include "mapping.h" #include "getset.h" #include "sequence.h" -#include "buffer.h" +#include "npy_buffer.h" #include "array_assign.h" #include "alloc.h" #include "mem_overlap.h" diff --git a/numpy/core/src/multiarray/arraytypes.c.src b/numpy/core/src/multiarray/arraytypes.c.src index 5c6699a3b..e36b95c00 100644 --- a/numpy/core/src/multiarray/arraytypes.c.src +++ b/numpy/core/src/multiarray/arraytypes.c.src @@ -36,7 +36,7 @@ #include "cblasfuncs.h" #include "npy_cblas.h" -#include "buffer.h" +#include "npy_buffer.h" /* check for sequences, but ignore the types numpy considers scalars */ static NPY_INLINE npy_bool diff --git a/numpy/core/src/multiarray/buffer.c b/numpy/core/src/multiarray/buffer.c index b729027ad..0edadee98 100644 --- a/numpy/core/src/multiarray/buffer.c +++ b/numpy/core/src/multiarray/buffer.c @@ -11,7 +11,7 @@ #include "npy_pycompat.h" -#include "buffer.h" +#include "npy_buffer.h" #include "common.h" #include "numpyos.h" #include "arrayobject.h" diff --git a/numpy/core/src/multiarray/common.c b/numpy/core/src/multiarray/common.c index a71b0818c..c991f7428 100644 --- a/numpy/core/src/multiarray/common.c +++ b/numpy/core/src/multiarray/common.c @@ -12,7 +12,7 @@ #include "usertypes.h" #include "common.h" -#include "buffer.h" +#include "npy_buffer.h" #include "get_attr_string.h" #include "mem_overlap.h" diff --git a/numpy/core/src/multiarray/conversion_utils.c b/numpy/core/src/multiarray/conversion_utils.c index 5f0ad5817..ca126b4b1 100644 --- a/numpy/core/src/multiarray/conversion_utils.c +++ b/numpy/core/src/multiarray/conversion_utils.c @@ -16,7 +16,7 @@ #include "conversion_utils.h" #include "alloc.h" -#include "buffer.h" +#include "npy_buffer.h" static int PyArray_PyIntAsInt_ErrMsg(PyObject *o, const char * msg) NPY_GCC_NONNULL(2); diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index 62804b979..64933ae1b 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -19,7 +19,7 @@ #include "ctors.h" #include "convert_datatype.h" #include "shape.h" -#include "buffer.h" +#include "npy_buffer.h" #include "lowlevel_strided_loops.h" #include "methods.h" #include "_datetime.h" diff --git a/numpy/core/src/multiarray/descriptor.c b/numpy/core/src/multiarray/descriptor.c index 522b69307..d4e18e457 100644 --- a/numpy/core/src/multiarray/descriptor.c +++ b/numpy/core/src/multiarray/descriptor.c @@ -19,7 +19,7 @@ #include "descriptor.h" #include "alloc.h" #include "assert.h" -#include "buffer.h" +#include "npy_buffer.h" /* * offset: A starting offset. diff --git a/numpy/core/src/multiarray/getset.c b/numpy/core/src/multiarray/getset.c index 116e37ce5..6e5d480d0 100644 --- a/numpy/core/src/multiarray/getset.c +++ b/numpy/core/src/multiarray/getset.c @@ -20,7 +20,7 @@ #include "arrayobject.h" #include "mem_overlap.h" #include "alloc.h" -#include "buffer.h" +#include "npy_buffer.h" /******************* array attribute get and set routines ******************/ diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c index ab70367c5..9169814c2 100644 --- a/numpy/core/src/multiarray/multiarraymodule.c +++ b/numpy/core/src/multiarray/multiarraymodule.c @@ -1115,6 +1115,14 @@ _pyarray_correlate(PyArrayObject *ap1, PyArrayObject *ap2, int typenum, n1 = PyArray_DIMS(ap1)[0]; n2 = PyArray_DIMS(ap2)[0]; + if (n1 == 0) { + PyErr_SetString(PyExc_ValueError, "first array argument cannot be empty"); + return NULL; + } + if (n2 == 0) { + PyErr_SetString(PyExc_ValueError, "second array argument cannot be empty"); + return NULL; + } if (n1 < n2) { ret = ap1; ap1 = ap2; diff --git a/numpy/core/src/multiarray/buffer.h b/numpy/core/src/multiarray/npy_buffer.h index fae413c85..fae413c85 100644 --- a/numpy/core/src/multiarray/buffer.h +++ b/numpy/core/src/multiarray/npy_buffer.h diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src index 9adca6773..32d712e0c 100644 --- a/numpy/core/src/multiarray/scalartypes.c.src +++ b/numpy/core/src/multiarray/scalartypes.c.src @@ -28,7 +28,7 @@ #include "npy_import.h" #include "dragon4.h" #include "npy_longdouble.h" -#include "buffer.h" +#include "npy_buffer.h" #include <stdlib.h> diff --git a/numpy/core/tests/test_deprecations.py b/numpy/core/tests/test_deprecations.py index 9bdcd8241..363ff26db 100644 --- a/numpy/core/tests/test_deprecations.py +++ b/numpy/core/tests/test_deprecations.py @@ -175,8 +175,7 @@ class TestComparisonDeprecations(_DeprecationTestCase): # 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) - res = op(a, b) - assert res.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: diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py index 1358b45e9..4d322e50e 100644 --- a/numpy/core/tests/test_numeric.py +++ b/numpy/core/tests/test_numeric.py @@ -2567,6 +2567,11 @@ class TestCorrelate(object): z = np.correlate(y, x, mode='full') assert_array_almost_equal(z, r_z) + def test_zero_size(self): + with pytest.raises(ValueError): + np.correlate(np.array([]), np.ones(1000), mode='full') + with pytest.raises(ValueError): + np.correlate(np.ones(1000), np.array([]), mode='full') class TestConvolve(object): def test_object(self): diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py index d9f961581..ba1aee55b 100644 --- a/numpy/core/tests/test_ufunc.py +++ b/numpy/core/tests/test_ufunc.py @@ -1090,18 +1090,13 @@ class TestUfunc(object): return '==' arr0d = np.array(HasComparisons()) - assert_equal(arr0d == arr0d, '==') - assert_equal(np.equal(arr0d, arr0d), '==') - assert_equal(np.equal(arr0d, arr0d, dtype=bool), True) - assert_equal(np.equal(arr0d, arr0d, dtype=object), '==') + assert_equal(arr0d == arr0d, True) + assert_equal(np.equal(arr0d, arr0d), True) # normal behavior is a cast arr1d = np.array([HasComparisons()]) - ret_obj = np.array(['=='], dtype=object) - ret_bool = np.array([True]) - assert_equal(arr1d == arr1d, ret_obj) - assert_equal(np.equal(arr1d, arr1d), ret_obj) - assert_equal(np.equal(arr1d, arr1d, dtype=object), ret_obj) - assert_equal(np.equal(arr1d, arr1d, dtype=bool), ret_bool) + assert_equal(arr1d == arr1d, np.array([True])) + assert_equal(np.equal(arr1d, arr1d), np.array([True])) # normal behavior is a cast + assert_equal(np.equal(arr1d, arr1d, dtype=object), np.array(['=='])) def test_object_array_reduction(self): # Reductions on object arrays diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py index 96a9f1f8b..1d71766ef 100644 --- a/numpy/core/tests/test_umath.py +++ b/numpy/core/tests/test_umath.py @@ -173,8 +173,7 @@ class TestComparisons(object): # Check comparing identical objects whose comparison # is not a simple boolean, e.g., arrays that are compared elementwise. a = np.array([np.array([1, 2, 3]), None], dtype=object) - b = np.equal(a, a.copy()) - assert b.shape == a.shape + assert_raises(ValueError, np.equal, a, a) # Check error raised when comparing identical non-comparable objects. class FunkyType(object): @@ -192,8 +191,7 @@ class TestComparisons(object): # Check comparing identical objects whose comparison # is not a simple boolean, e.g., arrays that are compared elementwise. a = np.array([np.array([1, 2, 3]), None], dtype=object) - b = np.not_equal(a, a.copy()) - assert b.shape == a.shape + assert_raises(ValueError, np.not_equal, a, a) # Check error raised when comparing identical non-comparable objects. class FunkyType(object): diff --git a/numpy/lib/arraysetops.py b/numpy/lib/arraysetops.py index cf45e181b..2309f7e42 100644 --- a/numpy/lib/arraysetops.py +++ b/numpy/lib/arraysetops.py @@ -562,15 +562,11 @@ def in1d(ar1, ar2, assume_unique=False, invert=False): if invert: mask = np.ones(len(ar1), dtype=bool) for a in ar2: - # convert object arrays to bool - # cannot use np.not_equal until 'S' and 'U' have loops - mask &= (ar1 != a).astype(bool) + mask &= (ar1 != a) else: mask = np.zeros(len(ar1), dtype=bool) for a in ar2: - # convert object arrays to bool - # cannot use np.equal until 'S' and 'U' have loops - mask |= (ar1 == a).astype(bool) + mask |= (ar1 == a) return mask # Otherwise use sorting diff --git a/numpy/linalg/tests/test_regression.py b/numpy/linalg/tests/test_regression.py index 289566109..bd3a45872 100644 --- a/numpy/linalg/tests/test_regression.py +++ b/numpy/linalg/tests/test_regression.py @@ -109,9 +109,10 @@ class TestRegression(object): assert_raises(ValueError, linalg.norm, testvector, ord='nuc') assert_raises(ValueError, linalg.norm, testvector, ord=np.inf) assert_raises(ValueError, linalg.norm, testvector, ord=-np.inf) - # Succeeds, equivalent to "sum(x != 0)" - r = linalg.norm(testvector, ord=0) - assert_(r.dtype == 'bool') + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + assert_raises((AttributeError, DeprecationWarning), + linalg.norm, testvector, ord=0) assert_raises(ValueError, linalg.norm, testvector, ord=-1) assert_raises(ValueError, linalg.norm, testvector, ord=-2) diff --git a/numpy/ma/core.py b/numpy/ma/core.py index f98a29d82..bb0d8d412 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -4790,12 +4790,7 @@ class MaskedArray(ndarray): mask = _check_mask_axis(self._mask, axis, **kwargs) if out is None: - r = self.filled(True).all(axis=axis, **kwargs) - # object dtypes with axis=None return a scalar - if isinstance(r, bool): - d = type(self)(r) - else: - d = r.view(type(self)) + d = self.filled(True).all(axis=axis, **kwargs).view(type(self)) if d.ndim: d.__setmask__(mask) elif mask: diff --git a/test_requirements.txt b/test_requirements.txt index 845e3093e..32b95897a 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -1,4 +1,4 @@ -cython==0.29.13 +cython==0.29.14 pytest==5.2.2 pytz==2019.3 pytest-cov==2.8.1 |