summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--numpy/core/src/umath/loops.c.src25
-rw-r--r--numpy/core/tests/test_deprecations.py56
-rw-r--r--numpy/core/tests/test_umath.py11
-rw-r--r--numpy/lib/polynomial.py18
-rw-r--r--numpy/polynomial/_polybase.py5
-rw-r--r--numpy/polynomial/polytemplate.py4
6 files changed, 80 insertions, 39 deletions
diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src
index c3abd02f8..d0374fc0a 100644
--- a/numpy/core/src/umath/loops.c.src
+++ b/numpy/core/src/umath/loops.c.src
@@ -2562,22 +2562,28 @@ NPY_NO_EXPORT void
/**begin repeat
* #kind = equal, not_equal, greater, greater_equal, less, less_equal#
* #OP = EQ, NE, GT, GE, LT, LE#
- * #identity = NPY_TRUE, NPY_FALSE, NPY_FALSE, NPY_TRUE, NPY_FALSE, NPY_TRUE#
+ * #identity = NPY_TRUE, NPY_FALSE, -1*4#
*/
NPY_NO_EXPORT void
OBJECT_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) {
BINARY_LOOP {
+ int ret;
+ PyObject *ret_obj;
PyObject *in1 = *(PyObject **)ip1;
PyObject *in2 = *(PyObject **)ip2;
+
in1 = in1 ? in1 : Py_None;
in2 = in2 ? in2 : Py_None;
+
/*
- * Do not use RichCompareBool because it includes an identity check.
- * But this is wrong for elementwise behaviour, since i.e. it says
- * that NaN can be equal to NaN, and an array is equal to itself.
+ * Do not use RichCompareBool because it includes an identity check
+ * (for == and !=).
+ * This is wrong for elementwise behaviour, since it means
+ * that NaN can be equal to NaN and an array is equal to itself.
*/
- PyObject *ret_obj = PyObject_RichCompare(in1, in2, Py_@OP@);
+ ret_obj = PyObject_RichCompare(in1, in2, Py_@OP@);
if (ret_obj == NULL) {
+#if @identity@ != -1
if (in1 == in2) {
PyErr_Clear();
if (DEPRECATE("numpy @kind@ will not check object identity "
@@ -2588,10 +2594,12 @@ OBJECT_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUS
*((npy_bool *)op1) = @identity@;
continue;
}
+#endif
return;
}
- int ret = PyObject_IsTrue(ret_obj);
+ ret = PyObject_IsTrue(ret_obj);
if (ret == -1) {
+#if @identity@ != -1
if (in1 == in2) {
PyErr_Clear();
if (DEPRECATE("numpy @kind@ will not check object identity "
@@ -2603,19 +2611,22 @@ OBJECT_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUS
*((npy_bool *)op1) = @identity@;
continue;
}
+#endif
return;
}
+#if @identity@ != -1
if ((in1 == in2) && ((npy_bool)ret != @identity@)) {
if (DEPRECATE_FUTUREWARNING(
"numpy @kind@ will not check object identity "
"in the future. The comparison did not return the "
- "same result as suggested by the identity "
+ "same result as suggested by the identity (`is`)) "
"and will change.") < 0) {
return;
}
*((npy_bool *)op1) = @identity@;
continue;
}
+#endif
*((npy_bool *)op1) = (npy_bool)ret;
}
}
diff --git a/numpy/core/tests/test_deprecations.py b/numpy/core/tests/test_deprecations.py
index 58d62aa89..a2b30c3c9 100644
--- a/numpy/core/tests/test_deprecations.py
+++ b/numpy/core/tests/test_deprecations.py
@@ -397,7 +397,8 @@ class TestComparisonDepreactions(_DeprecationTestCase):
# Element comparison error (numpy array can't be compared).
a = np.array([1, np.array([1,2,3])], dtype=object)
- self.assert_deprecated(op, args=(a, a), num=None)
+ b = np.array([1, np.array([1,2,3])], dtype=object)
+ self.assert_deprecated(op, args=(a, b), num=None)
def test_string(self):
@@ -417,7 +418,6 @@ class TestComparisonDepreactions(_DeprecationTestCase):
# comparison in the future. [1, 2] == None should be [False, False].
with warnings.catch_warnings():
warnings.filterwarnings('always', '', FutureWarning)
- a = np.array([1, 2])
assert_warns(FutureWarning, operator.eq, np.arange(3), None)
assert_warns(FutureWarning, operator.ne, np.arange(3), None)
@@ -427,5 +427,57 @@ class TestComparisonDepreactions(_DeprecationTestCase):
assert_raises(FutureWarning, operator.ne, np.arange(3), None)
+class TestIdentityComparisonDepreactions(_DeprecationTestCase):
+ """This tests the equal and not_equal object ufuncs identity check
+ deprecation. This was due to the usage of PyObject_RichCompareBool.
+
+ This tests that for example for `a = np.array([np.nan], dtype=object)`
+ `a == a` it is warned that False and not `np.nan is np.nan` is returned.
+
+ Should be kept in sync with TestComparisonDepreactions and new tests
+ added when the deprecation is over. Requires only removing of @identity@
+ (and blocks) from the ufunc loops.c.src of the OBJECT comparisons.
+ """
+
+ message = "numpy .* will not check object identity in the future."
+
+ def test_identity_equality_mismatch(self):
+ a = np.array([np.nan], dtype=object)
+
+ with warnings.catch_warnings():
+ warnings.filterwarnings('always', '', FutureWarning)
+ assert_warns(FutureWarning, np.equal, a, a)
+ assert_warns(FutureWarning, np.not_equal, a, a)
+
+ with warnings.catch_warnings():
+ warnings.filterwarnings('error', '', FutureWarning)
+ assert_raises(FutureWarning, np.equal, a, a)
+ assert_raises(FutureWarning, np.not_equal, a, a)
+ # And the other do not warn:
+ np.less(a, a)
+ np.greater(a, a)
+ np.less_equal(a, a)
+ np.greater_equal(a, a)
+
+
+ def test_comparison_error(self):
+ class FunkyType(object):
+ def __eq__(self, other):
+ raise TypeError("I won't compare")
+ def __ne__(self, other):
+ raise TypeError("I won't compare")
+
+ a = np.array([FunkyType()])
+ self.assert_deprecated(np.equal, args=(a, a))
+ self.assert_deprecated(np.not_equal, args=(a, a))
+
+
+ def test_bool_error(self):
+ # The comparison result cannot be interpreted as a bool
+ a = np.array([np.array([1, 2, 3]), None], dtype=object)
+ self.assert_deprecated(np.equal, args=(a, a))
+ self.assert_deprecated(np.not_equal, args=(a, a))
+
+
if __name__ == "__main__":
run_module_suite()
diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py
index b7b2f6308..3646fd2a9 100644
--- a/numpy/core/tests/test_umath.py
+++ b/numpy/core/tests/test_umath.py
@@ -1534,16 +1534,5 @@ def test_complex_nan_comparisons():
assert_equal(x == y, False, err_msg="%r == %r" % (x, y))
-def test_object_array_comparison():
- obj_array = np.arange(3)
- a = np.array([obj_array, 1])
- # Should raise an error because (obj_array == obj_array) is not a bool.
- # At this time, a == a would return False because of the error.
- assert_raises(ValueError, np.equal, a, a)
-
- # Check the same for NaN, when it is the *same* NaN.
- a = np.array([np.nan])
- assert_equal(a == a, [False])
-
if __name__ == "__main__":
run_module_suite()
diff --git a/numpy/lib/polynomial.py b/numpy/lib/polynomial.py
index e85e957e0..10ae32a60 100644
--- a/numpy/lib/polynomial.py
+++ b/numpy/lib/polynomial.py
@@ -1193,24 +1193,12 @@ class poly1d(object):
__rtruediv__ = __rdiv__
def __eq__(self, other):
- dim = min(self.coeffs.shape[0], other.coeffs.shape[0])
- if (self.coeffs[-dim:] != other.coeffs[-dim:]).any():
+ if self.coeffs.shape != other.coeffs.shape:
return False
- elif (self.coeffs[:-dim] != 0).any():
- return False
- elif (other.coeffs[:-dim] != 0).any():
- return False
- return True
+ return (self.coeffs == other.coeffs).all()
def __ne__(self, other):
- dim = min(self.coeffs.shape[0], other.coeffs.shape[0])
- if (self.coeffs[-dim:] != other.coeffs[-dim:]).any():
- return True
- elif (self.coeffs[:-dim] != 0).any():
- return True
- elif (other.coeffs[:-dim] != 0).any():
- return True
- return False
+ return not self.__eq__(other)
def __setattr__(self, key, val):
raise ValueError("Attributes cannot be changed this way.")
diff --git a/numpy/polynomial/_polybase.py b/numpy/polynomial/_polybase.py
index 83119579c..23608c74a 100644
--- a/numpy/polynomial/_polybase.py
+++ b/numpy/polynomial/_polybase.py
@@ -438,6 +438,7 @@ class ABCPolyBase(object):
res = (isinstance(other, self.__class__) and
np.all(self.domain == other.domain) and
np.all(self.window == other.window) and
+ (self.coef.shape == other.coef.shape) and
np.all(self.coef == other.coef))
return res
@@ -792,7 +793,7 @@ class ABCPolyBase(object):
"""
if domain is None:
domain = pu.getdomain(x)
- elif isinstance(domain, list) and len(domain) == 0:
+ elif type(domain) is list and len(domain) == 0:
domain = cls.domain
if window is None:
@@ -836,7 +837,7 @@ class ABCPolyBase(object):
[roots] = pu.as_series([roots], trim=False)
if domain is None:
domain = pu.getdomain(roots)
- elif isinstance(domain, list) and len(domain) == 0:
+ elif type(domain) is list and len(domain) == 0:
domain = cls.domain
if window is None:
diff --git a/numpy/polynomial/polytemplate.py b/numpy/polynomial/polytemplate.py
index b0006407b..e68dd18ef 100644
--- a/numpy/polynomial/polytemplate.py
+++ b/numpy/polynomial/polytemplate.py
@@ -780,10 +780,10 @@ class $name(pu.PolyBase) :
"""
if domain is None:
domain = pu.getdomain(x)
- elif len(domain) == 0:
+ elif type(domain) is list and len(domain) == 0:
domain = $domain
- if len(window) == 0:
+ if type(window) is list and len(window) == 0:
window = $domain
xnew = pu.mapdomain(x, domain, window)