summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Berg <sebastian@sipsolutions.net>2013-07-25 16:10:54 +0200
committerSebastian Berg <sebastian@sipsolutions.net>2014-05-04 18:14:11 +0200
commit9b8f6c72caea0c6f3fa08b304135239636e4f165 (patch)
treeb3418650ed740be1bb369f5ab2979749d4d27919
parent84831ca7b7926bf1c73e1702201e7591c55588a3 (diff)
downloadnumpy-9b8f6c72caea0c6f3fa08b304135239636e4f165.tar.gz
DEP: Deprecate that comparisons ignore errors.
This means that for example broadcasting errors get raised. The array_equiv function is changed to explicitely test if broadcasting is possible. It may be nice to do this test differently, but I am not sure if that is possible. Create a FutureWarning for comparisons to None, which should result in areal elementwise (object) comparisons. Slightly adepted a wrong test. Poly changes: Some changes in the polycode was necessary, the one is probably a bug fix, the other needs to be thought over, since len check is not perfect maybe, since it is more liekly to raise raise an error. Closes gh-3759 and gh-1608
-rw-r--r--numpy/core/numeric.py6
-rw-r--r--numpy/core/src/multiarray/arrayobject.c26
-rw-r--r--numpy/core/tests/test_deprecations.py54
-rw-r--r--numpy/core/tests/test_multiarray.py5
-rw-r--r--numpy/lib/polynomial.py18
-rw-r--r--numpy/polynomial/polytemplate.py6
6 files changed, 105 insertions, 10 deletions
diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py
index 8c569ea15..7962f9679 100644
--- a/numpy/core/numeric.py
+++ b/numpy/core/numeric.py
@@ -2388,10 +2388,12 @@ def array_equiv(a1, a2):
except:
return False
try:
- return bool(asarray(a1 == a2).all())
- except ValueError:
+ multiarray.broadcast(a1, a2)
+ except:
return False
+ return bool(asarray(a1 == a2).all())
+
_errdict = {"ignore":ERR_IGNORE,
"warn":ERR_WARN,
diff --git a/numpy/core/src/multiarray/arrayobject.c b/numpy/core/src/multiarray/arrayobject.c
index a09e0e3b9..cd0912510 100644
--- a/numpy/core/src/multiarray/arrayobject.c
+++ b/numpy/core/src/multiarray/arrayobject.c
@@ -1292,6 +1292,10 @@ array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op)
break;
case Py_EQ:
if (other == Py_None) {
+ if (DEPRECATE_FUTUREWARNING("comparison to `None` will result in "
+ "an elementwise object comparison in the future.") < 0) {
+ return NULL;
+ }
Py_INCREF(Py_False);
return Py_False;
}
@@ -1347,13 +1351,26 @@ array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op)
* indicate that
*/
if (result == NULL) {
+ /*
+ * Comparisons should raise errors when element-wise comparison
+ * is not possible.
+ */
PyErr_Clear();
+ if (DEPRECATE("elementwise comparison failed; "
+ "this will raise the error in the future.") < 0) {
+ return NULL;
+ }
+
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
break;
case Py_NE:
if (other == Py_None) {
+ if (DEPRECATE_FUTUREWARNING("comparison to `None` will result in "
+ "an elementwise object comparison in the future.") < 0) {
+ return NULL;
+ }
Py_INCREF(Py_True);
return Py_True;
}
@@ -1404,7 +1421,16 @@ array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op)
}
if (result == NULL) {
+ /*
+ * Comparisons should raise errors when element-wise comparison
+ * is not possible.
+ */
PyErr_Clear();
+ if (DEPRECATE("elementwise comparison failed; "
+ "this will raise the error in the future.") < 0) {
+ return NULL;
+ }
+
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
diff --git a/numpy/core/tests/test_deprecations.py b/numpy/core/tests/test_deprecations.py
index 6e559ab26..58d62aa89 100644
--- a/numpy/core/tests/test_deprecations.py
+++ b/numpy/core/tests/test_deprecations.py
@@ -86,7 +86,7 @@ class _DeprecationTestCase(object):
elif not ignore_others:
raise AssertionError("expected DeprecationWarning but %s given"
% warning.category)
- if num_found != num:
+ if num is not None and num_found != num:
raise AssertionError("%i warnings found but %i expected"
% (len(self.log), num))
@@ -375,5 +375,57 @@ class TestRankDeprecation(_DeprecationTestCase):
assert_warns(np.VisibleDeprecationWarning, np.rank, a)
+class TestComparisonDepreactions(_DeprecationTestCase):
+ """This tests the deprecation, for non-elementwise comparison logic.
+ This used to mean that when an error occured 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; " \
+ "this will raise the error in the future."
+
+ 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)
+
+ # 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)
+
+
+ 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, this is only to document
+ # that fact (it likely should be changed). This means that the
+ # following works (and returns False) due to dtype mismatch:
+ a == []
+
+
+ def test_none_comparison(self):
+ # Test comparison of None, which should result in elementwise
+ # 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)
+
+ with warnings.catch_warnings():
+ warnings.filterwarnings('error', '', FutureWarning)
+ assert_raises(FutureWarning, operator.eq, np.arange(3), None)
+ assert_raises(FutureWarning, operator.ne, np.arange(3), None)
+
+
if __name__ == "__main__":
run_module_suite()
diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py
index 51e4fc650..194ba0e37 100644
--- a/numpy/core/tests/test_multiarray.py
+++ b/numpy/core/tests/test_multiarray.py
@@ -561,8 +561,9 @@ class TestStructured(TestCase):
a = np.zeros((3, 5), dtype=[('a', ('i4', (2, 2)))])
a['a'] = np.arange(60).reshape(3, 5, 2, 2)
- # Since the subarray is always in C-order, these aren't equal
- assert_(np.any(a['a'].T != a.T['a']))
+ # Since the subarray is always in C-order, a transpose
+ # does not swap the subarray:
+ assert_array_equal(a.T['a'], a['a'].transpose(1, 0, 2, 3))
# In Fortran order, the subarray gets appended
# like in all other cases, not prepended as a special case
diff --git a/numpy/lib/polynomial.py b/numpy/lib/polynomial.py
index 0dcb85bb2..e85e957e0 100644
--- a/numpy/lib/polynomial.py
+++ b/numpy/lib/polynomial.py
@@ -1193,10 +1193,24 @@ class poly1d(object):
__rtruediv__ = __rdiv__
def __eq__(self, other):
- return NX.alltrue(self.coeffs == other.coeffs)
+ dim = min(self.coeffs.shape[0], other.coeffs.shape[0])
+ if (self.coeffs[-dim:] != other.coeffs[-dim:]).any():
+ return False
+ elif (self.coeffs[:-dim] != 0).any():
+ return False
+ elif (other.coeffs[:-dim] != 0).any():
+ return False
+ return True
def __ne__(self, other):
- return NX.any(self.coeffs != other.coeffs)
+ 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
def __setattr__(self, key, val):
raise ValueError("Attributes cannot be changed this way.")
diff --git a/numpy/polynomial/polytemplate.py b/numpy/polynomial/polytemplate.py
index 6c60ab3b2..b0006407b 100644
--- a/numpy/polynomial/polytemplate.py
+++ b/numpy/polynomial/polytemplate.py
@@ -737,7 +737,7 @@ class $name(pu.PolyBase) :
then a minimal domain that covers the points `x` is chosen. If
``[]`` the default domain ``$domain`` is used. The default
value is $domain in numpy 1.4.x and ``None`` in later versions.
- The ``'[]`` value was added in numpy 1.5.0.
+ The ``[]`` value was added in numpy 1.5.0.
rcond : float, optional
Relative condition number of the fit. Singular values smaller
than this relative to the largest singular value will be
@@ -780,10 +780,10 @@ class $name(pu.PolyBase) :
"""
if domain is None:
domain = pu.getdomain(x)
- elif domain == []:
+ elif len(domain) == 0:
domain = $domain
- if window == []:
+ if len(window) == 0:
window = $domain
xnew = pu.mapdomain(x, domain, window)