diff options
Diffstat (limited to 'numpy/core')
-rw-r--r-- | numpy/core/code_generators/cversions.txt | 3 | ||||
-rw-r--r-- | numpy/core/code_generators/numpy_api.py | 2 | ||||
-rw-r--r-- | numpy/core/include/numpy/numpyconfig.h | 1 | ||||
-rw-r--r-- | numpy/core/numerictypes.py | 50 | ||||
-rw-r--r-- | numpy/core/setup_common.py | 4 | ||||
-rw-r--r-- | numpy/core/src/multiarray/_multiarray_tests.c.src | 73 | ||||
-rw-r--r-- | numpy/core/src/multiarray/arrayobject.c | 186 | ||||
-rw-r--r-- | numpy/core/src/multiarray/einsum.c.src | 2 | ||||
-rw-r--r-- | numpy/core/src/multiarray/nditer_api.c | 60 | ||||
-rw-r--r-- | numpy/core/src/multiarray/nditer_constr.c | 23 | ||||
-rw-r--r-- | numpy/core/src/multiarray/nditer_pywrap.c | 104 | ||||
-rw-r--r-- | numpy/core/src/multiarray/scalartypes.c.src | 14 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_object.c | 231 | ||||
-rw-r--r-- | numpy/core/tests/test_deprecations.py | 8 | ||||
-rw-r--r-- | numpy/core/tests/test_nditer.py | 13 | ||||
-rw-r--r-- | numpy/core/tests/test_numerictypes.py | 6 | ||||
-rw-r--r-- | numpy/core/tests/test_regression.py | 16 | ||||
-rw-r--r-- | numpy/core/tests/test_ufunc.py | 21 |
18 files changed, 302 insertions, 515 deletions
diff --git a/numpy/core/code_generators/cversions.txt b/numpy/core/code_generators/cversions.txt index cc6c3a5fb..43c32eac6 100644 --- a/numpy/core/code_generators/cversions.txt +++ b/numpy/core/code_generators/cversions.txt @@ -39,8 +39,7 @@ 0x0000000b = edb1ba83730c650fd9bc5772a919cda7 # Version 12 (NumPy 1.14) Added PyArray_ResolveWritebackIfCopy, +# Version 12 (NumPy 1.15) No change. # PyArray_SetWritebackIfCopyBase and deprecated PyArray_SetUpdateIfCopyBase. 0x0000000c = a1bc756c5782853ec2e3616cf66869d8 -# Version 13 (NumPy 1.15) Added NpyIter_Close -0x0000000d = 4386e829d65aafce6bd09a85b142d585 diff --git a/numpy/core/code_generators/numpy_api.py b/numpy/core/code_generators/numpy_api.py index 6cfbbbcc7..d8a9ee6b4 100644 --- a/numpy/core/code_generators/numpy_api.py +++ b/numpy/core/code_generators/numpy_api.py @@ -350,8 +350,6 @@ multiarray_funcs_api = { 'PyArray_ResolveWritebackIfCopy': (302,), 'PyArray_SetWritebackIfCopyBase': (303,), # End 1.14 API - 'NpyIter_Close': (304,), - # End 1.15 API } ufunc_types_api = { diff --git a/numpy/core/include/numpy/numpyconfig.h b/numpy/core/include/numpy/numpyconfig.h index 04a3738b9..ab198f36b 100644 --- a/numpy/core/include/numpy/numpyconfig.h +++ b/numpy/core/include/numpy/numpyconfig.h @@ -36,5 +36,6 @@ #define NPY_1_12_API_VERSION 0x00000008 #define NPY_1_13_API_VERSION 0x00000008 #define NPY_1_14_API_VERSION 0x00000008 +#define NPY_1_15_API_VERSION 0x00000008 #endif diff --git a/numpy/core/numerictypes.py b/numpy/core/numerictypes.py index 7cd80f432..727fb66d1 100644 --- a/numpy/core/numerictypes.py +++ b/numpy/core/numerictypes.py @@ -323,31 +323,37 @@ def _add_aliases(): # insert bit-width version for this class (if relevant) base, bit, char = bitname(info.type) - if base != '': - myname = "%s%d" % (base, bit) - if (name not in ('longdouble', 'clongdouble') or - myname not in allTypes): - base_capitalize = english_capitalize(base) - if base == 'complex': - na_name = '%s%d' % (base_capitalize, bit//2) - elif base == 'bool': - na_name = base_capitalize - else: - na_name = "%s%d" % (base_capitalize, bit) - allTypes[myname] = info.type + assert base != '' + myname = "%s%d" % (base, bit) + + # ensure that (c)longdouble does not overwrite the aliases assigned to + # (c)double + if name in ('longdouble', 'clongdouble') and myname in allTypes: + continue + + base_capitalize = english_capitalize(base) + if base == 'complex': + na_name = '%s%d' % (base_capitalize, bit//2) + elif base == 'bool': + na_name = base_capitalize + else: + na_name = "%s%d" % (base_capitalize, bit) + + allTypes[myname] = info.type + + # add mapping for both the bit name and the numarray name + sctypeDict[myname] = info.type + sctypeDict[na_name] = info.type - # add mapping for both the bit name and the numarray name - sctypeDict[myname] = info.type - sctypeDict[na_name] = info.type + # add forward, reverse, and string mapping to numarray + sctypeNA[na_name] = info.type + sctypeNA[info.type] = na_name + sctypeNA[info.char] = na_name - # add forward, reverse, and string mapping to numarray - sctypeNA[na_name] = info.type - sctypeNA[info.type] = na_name - sctypeNA[info.char] = na_name - if char != '': - sctypeDict[char] = info.type - sctypeNA[char] = na_name + assert char != '' + sctypeDict[char] = info.type + sctypeNA[char] = na_name _add_aliases() def _add_integer_aliases(): diff --git a/numpy/core/setup_common.py b/numpy/core/setup_common.py index 70a43046c..356482b07 100644 --- a/numpy/core/setup_common.py +++ b/numpy/core/setup_common.py @@ -40,8 +40,8 @@ C_ABI_VERSION = 0x01000009 # 0x0000000a - 1.12.x # 0x0000000b - 1.13.x # 0x0000000c - 1.14.x -# 0x0000000d - 1.15.x -C_API_VERSION = 0x0000000d +# 0x0000000c - 1.15.x +C_API_VERSION = 0x0000000c class MismatchCAPIWarning(Warning): pass diff --git a/numpy/core/src/multiarray/_multiarray_tests.c.src b/numpy/core/src/multiarray/_multiarray_tests.c.src index cba96a4c2..67c9a333c 100644 --- a/numpy/core/src/multiarray/_multiarray_tests.c.src +++ b/numpy/core/src/multiarray/_multiarray_tests.c.src @@ -1042,76 +1042,6 @@ test_nditer_too_large(PyObject *NPY_UNUSED(self), PyObject *args) { } static PyObject * -test_nditer_writeback(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) -{ - /* like npyiter_init */ - PyObject *op_in = NULL, *op_dtypes_in = NULL, *value = NULL; - PyArrayObject * opview; - int iop, nop = 0; - PyArrayObject *op[NPY_MAXARGS]; - npy_uint32 flags = 0; - NPY_ORDER order = NPY_KEEPORDER; - NPY_CASTING casting = NPY_EQUIV_CASTING; - npy_uint32 op_flags[NPY_MAXARGS]; - PyArray_Descr *op_request_dtypes[NPY_MAXARGS]; - int retval; - unsigned char do_close; - int buffersize = 0; - NpyIter *iter = NULL; - static char *kwlist[] = {"value", "do_close", "input", "op_dtypes", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "ObO|O:test_nditer_writeback", kwlist, - &value, - &do_close, - &op_in, - &op_dtypes_in)) { - return NULL; - } - /* op and op_flags */ - if (! PyArray_Check(op_in)) { - return NULL; - } - nop = 1; - op[0] = (PyArrayObject*)op_in; - op_flags[0] = NPY_ITER_READWRITE|NPY_ITER_UPDATEIFCOPY; - - /* Set the dtypes */ - for (iop=0; iop<nop; iop++) { - PyObject *dtype = PySequence_GetItem(op_dtypes_in, iop); - PyArray_DescrConverter2(dtype, &op_request_dtypes[iop]); - } - - iter = NpyIter_AdvancedNew(nop, op, flags, order, casting, op_flags, - op_request_dtypes, - -1, NULL, NULL, - buffersize); - if (iter == NULL) { - goto fail; - } - - opview = NpyIter_GetIterView(iter, 0); - retval = PyArray_FillWithScalar(opview, value); - Py_DECREF(opview); - if (retval < 0) { - NpyIter_Deallocate(iter); - return NULL; - } - if (do_close != 0) { - NpyIter_Close(iter); - } - NpyIter_Deallocate(iter); - Py_RETURN_NONE; - -fail: - for (iop = 0; iop < nop; ++iop) { - Py_XDECREF(op[iop]); - Py_XDECREF(op_request_dtypes[iop]); - } - return NULL; -} - -static PyObject * array_solve_diophantine(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) { PyObject *A = NULL; @@ -1948,9 +1878,6 @@ static PyMethodDef Multiarray_TestsMethods[] = { {"test_nditer_too_large", test_nditer_too_large, METH_VARARGS, NULL}, - {"test_nditer_writeback", - (PyCFunction)test_nditer_writeback, - METH_VARARGS | METH_KEYWORDS, NULL}, {"solve_diophantine", (PyCFunction)array_solve_diophantine, METH_VARARGS | METH_KEYWORDS, NULL}, diff --git a/numpy/core/src/multiarray/arrayobject.c b/numpy/core/src/multiarray/arrayobject.c index 943edc772..368f5ded7 100644 --- a/numpy/core/src/multiarray/arrayobject.c +++ b/numpy/core/src/multiarray/arrayobject.c @@ -482,8 +482,7 @@ array_dealloc(PyArrayObject *self) { char const * msg = "WRITEBACKIFCOPY detected in array_dealloc. " " Required call to PyArray_ResolveWritebackIfCopy or " - "PyArray_DiscardWritebackIfCopy is missing. This could also " - "be caused by using a nditer without a context manager"; + "PyArray_DiscardWritebackIfCopy is missing."; Py_INCREF(self); /* hold on to self in next call since if * refcount == 0 it will recurse back into *array_dealloc @@ -1250,7 +1249,8 @@ PyArray_ChainExceptionsCause(PyObject *exc, PyObject *val, PyObject *tb) } } -/* Silence the current error and emit a deprecation warning instead. +/* + * Silence the current error and emit a deprecation warning instead. * * If warnings are raised as errors, this sets the warning __cause__ to the * silenced error. @@ -1269,6 +1269,118 @@ DEPRECATE_silence_error(const char *msg) { return 0; } +/* + * Comparisons can fail, but we do not always want to pass on the exception + * (see comment in array_richcompare below), but rather return NotImplemented. + * Here, an exception should be set on entrance. + * Returns either NotImplemented with the exception cleared, or NULL + * with the exception set. + * Raises deprecation warnings for cases where behaviour is meant to change + * (2015-05-14, 1.10) + */ + +NPY_NO_EXPORT PyObject * +_failed_comparison_workaround(PyArrayObject *self, PyObject *other, int cmp_op) +{ + PyObject *exc, *val, *tb; + PyArrayObject *array_other; + int other_is_flexible, ndim_other; + int self_is_flexible = PyTypeNum_ISFLEXIBLE(PyArray_DESCR(self)->type_num); + + PyErr_Fetch(&exc, &val, &tb); + /* + * Determine whether other has a flexible dtype; here, inconvertible + * is counted as inflexible. (This repeats work done in the ufunc, + * but OK to waste some time in an unlikely path.) + */ + array_other = (PyArrayObject *)PyArray_FROM_O(other); + if (array_other) { + other_is_flexible = PyTypeNum_ISFLEXIBLE( + PyArray_DESCR(array_other)->type_num); + ndim_other = PyArray_NDIM(array_other); + Py_DECREF(array_other); + } + else { + PyErr_Clear(); /* we restore the original error if needed */ + other_is_flexible = 0; + ndim_other = 0; + } + if (cmp_op == Py_EQ || cmp_op == Py_NE) { + /* + * note: for == and !=, a structured dtype self cannot get here, + * but a string can. Other can be string or structured. + */ + if (other_is_flexible || self_is_flexible) { + /* + * For scalars, returning NotImplemented is correct. + * For arrays, we emit a future deprecation warning. + * When this warning is removed, a correctly shaped + * array of bool should be returned. + */ + if (ndim_other != 0 || PyArray_NDIM(self) != 0) { + /* 2015-05-14, 1.10 */ + if (DEPRECATE_FUTUREWARNING( + "elementwise comparison failed; returning scalar " + "instead, but in the future will perform " + "elementwise comparison") < 0) { + goto fail; + } + } + } + else { + /* + * If neither self nor other had a flexible dtype, the error cannot + * have been caused by a lack of implementation in the ufunc. + * + * 2015-05-14, 1.10 + */ + if (DEPRECATE( + "elementwise comparison failed; " + "this will raise an error in the future.") < 0) { + goto fail; + } + } + Py_XDECREF(exc); + Py_XDECREF(val); + Py_XDECREF(tb); + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + else if (other_is_flexible || self_is_flexible) { + /* + * For LE, LT, GT, GE and a flexible self or other, we return + * NotImplemented, which is the correct answer since the ufuncs do + * not in fact implement loops for those. On python 3 this will + * get us the desired TypeError, but on python 2, one gets strange + * ordering, so we emit a warning. + */ +#if !defined(NPY_PY3K) + /* 2015-05-14, 1.10 */ + if (DEPRECATE( + "unorderable dtypes; returning scalar but in " + "the future this will be an error") < 0) { + goto fail; + } +#endif + Py_XDECREF(exc); + Py_XDECREF(val); + Py_XDECREF(tb); + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + else { + /* LE, LT, GT, or GE with non-flexible other; just pass on error */ + goto fail; + } + +fail: + /* + * Reraise the original exception, possibly chaining with a new one. + */ + PyArray_ChainExceptionsCause(exc, val, tb); + return NULL; +} + NPY_NO_EXPORT PyObject * array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op) { @@ -1366,26 +1478,6 @@ array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op) result = PyArray_GenericBinaryFunction(self, (PyObject *)other, n_ops.equal); - /* - * If the comparison results in NULL, then the - * two array objects can not be compared together; - * indicate that - */ - if (result == NULL) { - /* - * Comparisons should raise errors when element-wise comparison - * is not possible. - */ - /* 2015-05-14, 1.10 */ - if (DEPRECATE_silence_error( - "elementwise == comparison failed; " - "this will raise an error in the future.") < 0) { - return NULL; - } - - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } break; case Py_NE: RICHCMP_GIVE_UP_IF_NEEDED(obj_self, other); @@ -1437,21 +1529,6 @@ array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op) result = PyArray_GenericBinaryFunction(self, (PyObject *)other, n_ops.not_equal); - if (result == NULL) { - /* - * Comparisons should raise errors when element-wise comparison - * is not possible. - */ - /* 2015-05-14, 1.10 */ - if (DEPRECATE_silence_error( - "elementwise != comparison failed; " - "this will raise an error in the future.") < 0) { - return NULL; - } - - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } break; case Py_GT: RICHCMP_GIVE_UP_IF_NEEDED(obj_self, other); @@ -1464,8 +1541,37 @@ array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op) n_ops.greater_equal); break; default: - result = Py_NotImplemented; - Py_INCREF(result); + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + if (result == NULL) { + /* + * 2015-05-14, 1.10; updated 2018-06-18, 1.16. + * + * Comparisons can raise errors when element-wise comparison is not + * possible. Some of these, though, should not be passed on. + * In particular, the ufuncs do not have loops for flexible dtype, + * so those should be treated separately. Furthermore, for EQ and NE, + * we should never fail. + * + * Our ideal behaviour would be: + * + * 1. For EQ and NE: + * - If self and other are scalars, return NotImplemented, + * so that python can assign True of False as appropriate. + * - If either is an array, return an array of False or True. + * + * 2. For LT, LE, GE, GT: + * - If self or other was flexible, return NotImplemented + * (as is in fact the case), so python can raise a TypeError. + * - If other is not convertible to an array, pass on the error + * (MHvK, 2018-06-18: not sure about this, but it's what we have). + * + * However, for backwards compatibilty, we cannot yet return arrays, + * so we raise warnings instead. Furthermore, we warn on python2 + * for LT, LE, GE, GT, since fall-back behaviour is poorly defined. + */ + result = _failed_comparison_workaround(self, other, cmp_op); } return result; } diff --git a/numpy/core/src/multiarray/einsum.c.src b/numpy/core/src/multiarray/einsum.c.src index 039bcc15e..33184d99a 100644 --- a/numpy/core/src/multiarray/einsum.c.src +++ b/numpy/core/src/multiarray/einsum.c.src @@ -2857,7 +2857,6 @@ PyArray_EinsteinSum(char *subscripts, npy_intp nop, iternext = NpyIter_GetIterNext(iter, NULL); if (iternext == NULL) { - NpyIter_Close(iter); NpyIter_Deallocate(iter); Py_DECREF(ret); goto fail; @@ -2881,7 +2880,6 @@ PyArray_EinsteinSum(char *subscripts, npy_intp nop, } finish: - NpyIter_Close(iter); NpyIter_Deallocate(iter); for (iop = 0; iop < nop; ++iop) { Py_DECREF(op[iop]); diff --git a/numpy/core/src/multiarray/nditer_api.c b/numpy/core/src/multiarray/nditer_api.c index ba9e9f273..7a33ac05e 100644 --- a/numpy/core/src/multiarray/nditer_api.c +++ b/numpy/core/src/multiarray/nditer_api.c @@ -1381,47 +1381,6 @@ NpyIter_GetInnerLoopSizePtr(NpyIter *iter) } /*NUMPY_API - * Resolves all writebackifcopy scratch buffers, not safe to use iterator - * operands after this call, in this iterator as well as any copies. - * Returns 0 on success, -1 on failure - */ -NPY_NO_EXPORT int -NpyIter_Close(NpyIter *iter) -{ - int ret=0, iop, nop; - PyArrayObject ** operands; - npyiter_opitflags *op_itflags; - if (iter == NULL) { - return 0; - } - nop = NIT_NOP(iter); - operands = NIT_OPERANDS(iter); - op_itflags = NIT_OPITFLAGS(iter); - /* If NPY_OP_ITFLAG_HAS_WRITEBACK flag set on operand, resolve it. - * If the resolution fails (should never happen), continue from the - * next operand and discard the writeback scratch buffers, and return - * failure status - */ - for (iop=0; iop<nop; iop++) { - if (op_itflags[iop] & NPY_OP_ITFLAG_HAS_WRITEBACK) { - op_itflags[iop] &= ~NPY_OP_ITFLAG_HAS_WRITEBACK; - if (PyArray_ResolveWritebackIfCopy(operands[iop]) < 0) { - ret = -1; - iop++; - break; - } - } - } - for (; iop<nop; iop++) { - if (op_itflags[iop] & NPY_OP_ITFLAG_HAS_WRITEBACK) { - op_itflags[iop] &= ~NPY_OP_ITFLAG_HAS_WRITEBACK; - PyArray_DiscardWritebackIfCopy(operands[iop]); - } - } - return ret; -} - -/*NUMPY_API * For debugging */ NPY_NO_EXPORT void @@ -2830,4 +2789,23 @@ npyiter_checkreducesize(NpyIter *iter, npy_intp count, } return count * (*reduce_innersize); } + +NPY_NO_EXPORT npy_bool +npyiter_has_writeback(NpyIter *iter) +{ + int iop, nop; + npyiter_opitflags *op_itflags; + if (iter == NULL) { + return 0; + } + nop = NIT_NOP(iter); + op_itflags = NIT_OPITFLAGS(iter); + + for (iop=0; iop<nop; iop++) { + if (op_itflags[iop] & NPY_OP_ITFLAG_HAS_WRITEBACK) { + return NPY_TRUE; + } + } + return NPY_FALSE; +} #undef NPY_ITERATOR_IMPLEMENTATION_CODE diff --git a/numpy/core/src/multiarray/nditer_constr.c b/numpy/core/src/multiarray/nditer_constr.c index b07137858..c56376f58 100644 --- a/numpy/core/src/multiarray/nditer_constr.c +++ b/numpy/core/src/multiarray/nditer_constr.c @@ -403,7 +403,6 @@ NpyIter_AdvancedNew(int nop, PyArrayObject **op_in, npy_uint32 flags, */ if (!npyiter_allocate_arrays(iter, flags, op_dtype, subtype, op_flags, op_itflags, op_axes)) { - NpyIter_Close(iter); NpyIter_Deallocate(iter); return NULL; } @@ -465,14 +464,12 @@ NpyIter_AdvancedNew(int nop, PyArrayObject **op_in, npy_uint32 flags, /* If buffering is set without delayed allocation */ if (itflags & NPY_ITFLAG_BUFFER) { if (!npyiter_allocate_transfer_functions(iter)) { - NpyIter_Close(iter); NpyIter_Deallocate(iter); return NULL; } if (!(itflags & NPY_ITFLAG_DELAYBUF)) { /* Allocate the buffers */ if (!npyiter_allocate_buffers(iter, NULL)) { - NpyIter_Close(iter); NpyIter_Deallocate(iter); return NULL; } @@ -654,6 +651,8 @@ NpyIter_Deallocate(NpyIter *iter) int iop, nop; PyArray_Descr **dtype; PyArrayObject **object; + npyiter_opitflags *op_itflags; + npy_bool resolve = 1; if (iter == NULL) { return NPY_SUCCEED; @@ -663,6 +662,7 @@ NpyIter_Deallocate(NpyIter *iter) nop = NIT_NOP(iter); dtype = NIT_DTYPES(iter); object = NIT_OPERANDS(iter); + op_itflags = NIT_OPITFLAGS(iter); /* Deallocate any buffers and buffering data */ if (itflags & NPY_ITFLAG_BUFFER) { @@ -691,15 +691,28 @@ NpyIter_Deallocate(NpyIter *iter) } } - /* Deallocate all the dtypes and objects that were iterated */ + /* + * Deallocate all the dtypes and objects that were iterated and resolve + * any writeback buffers created by the iterator + */ for(iop = 0; iop < nop; ++iop, ++dtype, ++object) { + if (op_itflags[iop] & NPY_OP_ITFLAG_HAS_WRITEBACK) { + if (resolve && PyArray_ResolveWritebackIfCopy(*object) < 0) { + resolve = 0; + } + else { + PyArray_DiscardWritebackIfCopy(*object); + } + } Py_XDECREF(*dtype); Py_XDECREF(*object); } /* Deallocate the iterator memory */ PyObject_Free(iter); - + if (resolve == 0) { + return NPY_FAIL; + } return NPY_SUCCEED; } diff --git a/numpy/core/src/multiarray/nditer_pywrap.c b/numpy/core/src/multiarray/nditer_pywrap.c index 0b6c80c8a..5a9f3c5fa 100644 --- a/numpy/core/src/multiarray/nditer_pywrap.c +++ b/numpy/core/src/multiarray/nditer_pywrap.c @@ -1,5 +1,5 @@ /* - * This file implements the CPython wrapper of the new NumPy iterator. + * This file implements the CPython wrapper of NpyIter * * Copyright (c) 2010 by Mark Wiebe (mwwiebe@gmail.com) * The University of British Columbia @@ -19,6 +19,10 @@ #include "common.h" #include "ctors.h" +/* Functions not part of the public NumPy C API */ +npy_bool npyiter_has_writeback(NpyIter *iter); + + typedef struct NewNpyArrayIterObject_tag NewNpyArrayIterObject; struct NewNpyArrayIterObject_tag { @@ -27,8 +31,6 @@ struct NewNpyArrayIterObject_tag { NpyIter *iter; /* Flag indicating iteration started/stopped */ char started, finished; - /* iter operands cannot be referenced if iter is closed */ - npy_bool is_closed; /* Child to update for nested iteration */ NewNpyArrayIterObject *nested_child; /* Cached values from the iterator */ @@ -88,7 +90,6 @@ npyiter_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) if (self != NULL) { self->iter = NULL; self->nested_child = NULL; - self->is_closed = 0; } return (PyObject *)self; @@ -1173,10 +1174,29 @@ fail: return NULL; } + static void npyiter_dealloc(NewNpyArrayIterObject *self) { if (self->iter) { + if (npyiter_has_writeback(self->iter)) { + if (PyErr_WarnEx(PyExc_RuntimeWarning, + "Temporary data has not been written back to one of the " + "operands. Typically nditer is used as a context manager " + "otherwise 'close' must be called before reading iteration " + "results.", 1) < 0) { + PyObject *s; + + s = PyUString_FromString("npyiter_dealloc"); + if (s) { + PyErr_WriteUnraisable(s); + Py_DECREF(s); + } + else { + PyErr_WriteUnraisable(Py_None); + } + } + } NpyIter_Deallocate(self->iter); self->iter = NULL; Py_XDECREF(self->nested_child); @@ -1418,12 +1438,6 @@ static PyObject *npyiter_value_get(NewNpyArrayIterObject *self) ret = npyiter_seq_item(self, 0); } else { - if (self->is_closed) { - PyErr_SetString(PyExc_ValueError, - "Iterator is closed"); - return NULL; - } - ret = PyTuple_New(nop); if (ret == NULL) { return NULL; @@ -1453,12 +1467,6 @@ static PyObject *npyiter_operands_get(NewNpyArrayIterObject *self) "Iterator is invalid"); return NULL; } - if (self->is_closed) { - PyErr_SetString(PyExc_ValueError, - "Iterator is closed"); - return NULL; - } - nop = NpyIter_GetNOp(self->iter); operands = self->operands; @@ -1487,13 +1495,6 @@ static PyObject *npyiter_itviews_get(NewNpyArrayIterObject *self) "Iterator is invalid"); return NULL; } - - if (self->is_closed) { - PyErr_SetString(PyExc_ValueError, - "Iterator is closed"); - return NULL; - } - nop = NpyIter_GetNOp(self->iter); ret = PyTuple_New(nop); @@ -1517,7 +1518,7 @@ static PyObject * npyiter_next(NewNpyArrayIterObject *self) { if (self->iter == NULL || self->iternext == NULL || - self->finished || self->is_closed) { + self->finished) { return NULL; } @@ -1911,13 +1912,6 @@ static PyObject *npyiter_dtypes_get(NewNpyArrayIterObject *self) "Iterator is invalid"); return NULL; } - - if (self->is_closed) { - PyErr_SetString(PyExc_ValueError, - "Iterator is closed"); - return NULL; - } - nop = NpyIter_GetNOp(self->iter); ret = PyTuple_New(nop); @@ -2011,13 +2005,6 @@ npyiter_seq_item(NewNpyArrayIterObject *self, Py_ssize_t i) "and no reset has been done yet"); return NULL; } - - if (self->is_closed) { - PyErr_SetString(PyExc_ValueError, - "Iterator is closed"); - return NULL; - } - nop = NpyIter_GetNOp(self->iter); /* Negative indexing */ @@ -2090,13 +2077,6 @@ npyiter_seq_slice(NewNpyArrayIterObject *self, "and no reset has been done yet"); return NULL; } - - if (self->is_closed) { - PyErr_SetString(PyExc_ValueError, - "Iterator is closed"); - return NULL; - } - nop = NpyIter_GetNOp(self->iter); if (ilow < 0) { ilow = 0; @@ -2156,13 +2136,6 @@ npyiter_seq_ass_item(NewNpyArrayIterObject *self, Py_ssize_t i, PyObject *v) "and no reset has been done yet"); return -1; } - - if (self->is_closed) { - PyErr_SetString(PyExc_ValueError, - "Iterator is closed"); - return -1; - } - nop = NpyIter_GetNOp(self->iter); /* Negative indexing */ @@ -2234,13 +2207,6 @@ npyiter_seq_ass_slice(NewNpyArrayIterObject *self, Py_ssize_t ilow, "and no reset has been done yet"); return -1; } - - if (self->is_closed) { - PyErr_SetString(PyExc_ValueError, - "Iterator is closed"); - return -1; - } - nop = NpyIter_GetNOp(self->iter); if (ilow < 0) { ilow = 0; @@ -2292,12 +2258,6 @@ npyiter_subscript(NewNpyArrayIterObject *self, PyObject *op) return NULL; } - if (self->is_closed) { - PyErr_SetString(PyExc_ValueError, - "Iterator is closed"); - return NULL; - } - if (PyInt_Check(op) || PyLong_Check(op) || (PyIndex_Check(op) && !PySequence_Check(op))) { npy_intp i = PyArray_PyIntAsIntp(op); @@ -2347,12 +2307,6 @@ npyiter_ass_subscript(NewNpyArrayIterObject *self, PyObject *op, return -1; } - if (self->is_closed) { - PyErr_SetString(PyExc_ValueError, - "Iterator is closed"); - return -1; - } - if (PyInt_Check(op) || PyLong_Check(op) || (PyIndex_Check(op) && !PySequence_Check(op))) { npy_intp i = PyArray_PyIntAsIntp(op); @@ -2387,10 +2341,6 @@ npyiter_enter(NewNpyArrayIterObject *self) PyErr_SetString(PyExc_RuntimeError, "operation on non-initialized iterator"); return NULL; } - if (self->is_closed) { - PyErr_SetString(PyExc_ValueError, "cannot reuse closed iterator"); - return NULL; - } Py_INCREF(self); return (PyObject *)self; } @@ -2403,8 +2353,8 @@ npyiter_close(NewNpyArrayIterObject *self) if (self->iter == NULL) { Py_RETURN_NONE; } - ret = NpyIter_Close(iter); - self->is_closed = 1; + ret = NpyIter_Deallocate(iter); + self->iter = NULL; if (ret < 0) { return NULL; } diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src index 25e0668ed..a32aa47ab 100644 --- a/numpy/core/src/multiarray/scalartypes.c.src +++ b/numpy/core/src/multiarray/scalartypes.c.src @@ -1675,16 +1675,6 @@ gentype_itemset(PyObject *NPY_UNUSED(self), PyObject *NPY_UNUSED(args)) return NULL; } -static PyObject * -gentype_squeeze(PyObject *self, PyObject *args) -{ - if (!PyArg_ParseTuple(args, "")) { - return NULL; - } - Py_INCREF(self); - return self; -} - static Py_ssize_t gentype_getreadbuf(PyObject *, Py_ssize_t, void **); @@ -1738,7 +1728,7 @@ gentype_byteswap(PyObject *self, PyObject *args, PyObject *kwds) * std, var, sum, cumsum, prod, cumprod, compress, sort, argsort, * round, argmax, argmin, max, min, ptp, any, all, astype, resize, * reshape, choose, tostring, tobytes, copy, searchsorted, view, - * flatten, ravel# + * flatten, ravel, squeeze# */ static PyObject * gentype_@name@(PyObject *self, PyObject *args, PyObject *kwds) @@ -2121,7 +2111,7 @@ static PyMethodDef gentype_methods[] = { METH_VARARGS | METH_KEYWORDS, NULL}, {"squeeze", (PyCFunction)gentype_squeeze, - METH_VARARGS, NULL}, + METH_VARARGS | METH_KEYWORDS, NULL}, {"view", (PyCFunction)gentype_view, METH_VARARGS | METH_KEYWORDS, NULL}, diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c index 5e92bc991..b964c568e 100644 --- a/numpy/core/src/umath/ufunc_object.c +++ b/numpy/core/src/umath/ufunc_object.c @@ -577,9 +577,6 @@ get_ufunc_arguments(PyUFuncObject *ufunc, PyObject *obj, *context; PyObject *str_key_obj = NULL; const char *ufunc_name = ufunc_get_name_cstr(ufunc); - int type_num; - - int any_flexible = 0, any_object = 0, any_flexible_userloops = 0; int has_sig = 0; /* @@ -638,166 +635,6 @@ get_ufunc_arguments(PyUFuncObject *ufunc, if (out_op[i] == NULL) { goto fail; } - - type_num = PyArray_DESCR(out_op[i])->type_num; - if (!any_flexible && - PyTypeNum_ISFLEXIBLE(type_num)) { - any_flexible = 1; - } - if (!any_object && - PyTypeNum_ISOBJECT(type_num)) { - any_object = 1; - } - - /* - * If any operand is a flexible dtype, check to see if any - * struct dtype ufuncs are registered. A ufunc has been registered - * for a struct dtype if ufunc's arg_dtypes array is not NULL. - */ - if (PyTypeNum_ISFLEXIBLE(type_num) && - !any_flexible_userloops && - ufunc->userloops != NULL) { - PyUFunc_Loop1d *funcdata; - PyObject *key, *obj; - key = PyInt_FromLong(type_num); - if (key == NULL) { - continue; - } - obj = PyDict_GetItem(ufunc->userloops, key); - Py_DECREF(key); - if (obj == NULL) { - continue; - } - funcdata = (PyUFunc_Loop1d *)NpyCapsule_AsVoidPtr(obj); - while (funcdata != NULL) { - if (funcdata->arg_dtypes != NULL) { - any_flexible_userloops = 1; - break; - } - funcdata = funcdata->next; - } - } - } - - if (any_flexible && !any_flexible_userloops && !any_object && nin == 2) { - /* Traditionally, we return -2 here (meaning "NotImplemented") anytime - * we hit the above condition. - * - * This condition basically means "we are doomed", b/c the "flexible" - * dtypes -- strings and void -- cannot have their own ufunc loops - * registered (except via the special "flexible userloops" mechanism), - * and they can't be cast to anything except object (and we only cast - * to object if any_object is true). So really we should do nothing - * here and continue and let the proper error be raised. But, we can't - * quite yet, b/c of backcompat. - * - * Most of the time, this NotImplemented either got returned directly - * to the user (who can't do anything useful with it), or got passed - * back out of a special function like __mul__. And fortunately, for - * almost all special functions, the end result of this was a - * TypeError. Which is also what we get if we just continue without - * this special case, so this special case is unnecessary. - * - * The only thing that actually depended on the NotImplemented is - * array_richcompare, which did two things with it. First, it needed - * to see this NotImplemented in order to implement the special-case - * comparisons for - * - * string < <= == != >= > string - * void == != void - * - * Now it checks for those cases first, before trying to call the - * ufunc, so that's no problem. What it doesn't handle, though, is - * cases like - * - * float < string - * - * or - * - * float == void - * - * For those, it just let the NotImplemented bubble out, and accepted - * Python's default handling. And unfortunately, for comparisons, - * Python's default is *not* to raise an error. Instead, it returns - * something that depends on the operator: - * - * == return False - * != return True - * < <= >= > Python 2: use "fallback" (= weird and broken) ordering - * Python 3: raise TypeError (hallelujah) - * - * In most cases this is straightforwardly broken, because comparison - * of two arrays should always return an array, and here we end up - * returning a scalar. However, there is an exception: if we are - * comparing two scalars for equality, then it actually is correct to - * return a scalar bool instead of raising an error. If we just - * removed this special check entirely, then "np.float64(1) == 'foo'" - * would raise an error instead of returning False, which is genuinely - * wrong. - * - * The proper end goal here is: - * 1) == and != should be implemented in a proper vectorized way for - * all types. The short-term hack for this is just to add a - * special case to PyUFunc_DefaultLegacyInnerLoopSelector where - * if it can't find a comparison loop for the given types, and - * the ufunc is np.equal or np.not_equal, then it returns a loop - * that just fills the output array with False (resp. True). Then - * array_richcompare could trust that whenever its special cases - * don't apply, simply calling the ufunc will do the right thing, - * even without this special check. - * 2) < <= >= > should raise an error if no comparison function can - * be found. array_richcompare already handles all string <> - * string cases, and void dtypes don't have ordering, so again - * this would mean that array_richcompare could simply call the - * ufunc and it would do the right thing (i.e., raise an error), - * again without needing this special check. - * - * So this means that for the transition period, our goal is: - * == and != on scalars should simply return NotImplemented like - * they always did, since everything ends up working out correctly - * in this case only - * == and != on arrays should issue a FutureWarning and then return - * NotImplemented - * < <= >= > on all flexible dtypes on py2 should raise a - * DeprecationWarning, and then return NotImplemented. On py3 we - * skip the warning, though, b/c it would just be immediately be - * followed by an exception anyway. - * - * And for all other operations, we let things continue as normal. - */ - /* strcmp() is a hack but I think we can get away with it for this - * temporary measure. - */ - if (!strcmp(ufunc_name, "equal") || - !strcmp(ufunc_name, "not_equal")) { - /* Warn on non-scalar, return NotImplemented regardless */ - if (PyArray_NDIM(out_op[0]) != 0 || - PyArray_NDIM(out_op[1]) != 0) { - if (DEPRECATE_FUTUREWARNING( - "elementwise comparison failed; returning scalar " - "instead, but in the future will perform elementwise " - "comparison") < 0) { - goto fail; - } - } - Py_DECREF(out_op[0]); - Py_DECREF(out_op[1]); - return -2; - } - else if (!strcmp(ufunc_name, "less") || - !strcmp(ufunc_name, "less_equal") || - !strcmp(ufunc_name, "greater") || - !strcmp(ufunc_name, "greater_equal")) { -#if !defined(NPY_PY3K) - if (DEPRECATE("unorderable dtypes; returning scalar but in " - "the future this will be an error") < 0) { - goto fail; - } -#endif - Py_DECREF(out_op[0]); - Py_DECREF(out_op[1]); - return -2; - } } /* Get positional output arguments */ @@ -1281,7 +1118,6 @@ iterator_loop(PyUFuncObject *ufunc, PyArrayObject **op_it; npy_uint32 iter_flags; - int retval; NPY_BEGIN_THREADS_DEF; @@ -1355,7 +1191,6 @@ iterator_loop(PyUFuncObject *ufunc, /* Call the __array_prepare__ functions for the new array */ if (prepare_ufunc_output(ufunc, &op[nin+i], arr_prep[i], full_args, i) < 0) { - NpyIter_Close(iter); NpyIter_Deallocate(iter); return -1; } @@ -1384,7 +1219,6 @@ iterator_loop(PyUFuncObject *ufunc, baseptrs[i] = PyArray_BYTES(op_it[i]); } if (NpyIter_ResetBasePointers(iter, baseptrs, NULL) != NPY_SUCCEED) { - NpyIter_Close(iter); NpyIter_Deallocate(iter); return -1; } @@ -1392,7 +1226,6 @@ iterator_loop(PyUFuncObject *ufunc, /* Get the variables needed for the loop */ iternext = NpyIter_GetIterNext(iter, NULL); if (iternext == NULL) { - NpyIter_Close(iter); NpyIter_Deallocate(iter); return -1; } @@ -1410,9 +1243,7 @@ iterator_loop(PyUFuncObject *ufunc, NPY_END_THREADS; } - retval = NpyIter_Close(iter); - NpyIter_Deallocate(iter); - return retval; + return NpyIter_Deallocate(iter); } /* @@ -1597,7 +1428,7 @@ execute_fancy_ufunc_loop(PyUFuncObject *ufunc, PyObject **arr_prep, ufunc_full_args full_args) { - int retval, i, nin = ufunc->nin, nout = ufunc->nout; + int i, nin = ufunc->nin, nout = ufunc->nout; int nop = nin + nout; npy_uint32 op_flags[NPY_MAXARGS]; NpyIter *iter; @@ -1709,7 +1540,6 @@ execute_fancy_ufunc_loop(PyUFuncObject *ufunc, if (prepare_ufunc_output(ufunc, &op_tmp, arr_prep[i], full_args, i) < 0) { - NpyIter_Close(iter); NpyIter_Deallocate(iter); return -1; } @@ -1720,7 +1550,6 @@ execute_fancy_ufunc_loop(PyUFuncObject *ufunc, "The __array_prepare__ functions modified the data " "pointer addresses in an invalid fashion"); Py_DECREF(op_tmp); - NpyIter_Close(iter); NpyIter_Deallocate(iter); return -1; } @@ -1755,7 +1584,6 @@ execute_fancy_ufunc_loop(PyUFuncObject *ufunc, wheremask != NULL ? fixed_strides[nop] : fixed_strides[nop + nin], &innerloop, &innerloopdata, &needs_api) < 0) { - NpyIter_Close(iter); NpyIter_Deallocate(iter); return -1; } @@ -1763,7 +1591,6 @@ execute_fancy_ufunc_loop(PyUFuncObject *ufunc, /* Get the variables needed for the loop */ iternext = NpyIter_GetIterNext(iter, NULL); if (iternext == NULL) { - NpyIter_Close(iter); NpyIter_Deallocate(iter); return -1; } @@ -1787,9 +1614,7 @@ execute_fancy_ufunc_loop(PyUFuncObject *ufunc, NPY_AUXDATA_FREE(innerloopdata); } - retval = NpyIter_Close(iter); - NpyIter_Deallocate(iter); - return retval; + return NpyIter_Deallocate(iter); } static npy_bool @@ -2300,7 +2125,7 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc, int nin, nout; int i, j, idim, nop; const char *ufunc_name; - int retval = 0, subok = 1; + int retval, subok = 1; int needs_api = 0; PyArray_Descr *dtypes[NPY_MAXARGS]; @@ -2809,16 +2634,11 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc, goto fail; } - /* Write back any temporary data from PyArray_SetWritebackIfCopyBase */ - if (NpyIter_Close(iter) < 0) { - goto fail; - } - PyArray_free(inner_strides); - if (NpyIter_Close(iter) < 0) { - goto fail; + if (NpyIter_Deallocate(iter) < 0) { + retval = -1; } - NpyIter_Deallocate(iter); + /* The caller takes ownership of all the references in op */ for (i = 0; i < nop; ++i) { Py_XDECREF(dtypes[i]); @@ -2831,14 +2651,13 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc, Py_XDECREF(full_args.in); Py_XDECREF(full_args.out); - NPY_UF_DBG_PRINT("Returning Success\n"); + NPY_UF_DBG_PRINT1("Returning code %d\n", reval); - return 0; + return retval; fail: NPY_UF_DBG_PRINT1("Returning failure code %d\n", retval); PyArray_free(inner_strides); - NpyIter_Close(iter); NpyIter_Deallocate(iter); for (i = 0; i < nop; ++i) { Py_XDECREF(op[i]); @@ -3031,7 +2850,7 @@ PyUFunc_GenericFunction(PyUFuncObject *ufunc, Py_XDECREF(full_args.out); Py_XDECREF(wheremask); - NPY_UF_DBG_PRINT("Returning Success\n"); + NPY_UF_DBG_PRINT("Returning success code 0\n"); return 0; @@ -3722,12 +3541,6 @@ PyUFunc_Accumulate(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *out, } finish: - if (NpyIter_Close(iter) < 0) { - goto fail; - } - if (NpyIter_Close(iter_inner) < 0) { - goto fail; - } Py_XDECREF(op_dtypes[0]); NpyIter_Deallocate(iter); NpyIter_Deallocate(iter_inner); @@ -4110,9 +3923,6 @@ PyUFunc_Reduceat(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *ind, } finish: - if (NpyIter_Close(iter) < 0) { - goto fail; - } Py_XDECREF(op_dtypes[0]); NpyIter_Deallocate(iter); @@ -4507,22 +4317,7 @@ ufunc_generic_call(PyUFuncObject *ufunc, PyObject *args, PyObject *kwds) errval = PyUFunc_GenericFunction(ufunc, args, kwds, mps); if (errval < 0) { - if (errval == -1) { - return NULL; - } - else if (ufunc->nin == 2 && ufunc->nout == 1) { - /* - * For array_richcompare's benefit -- see the long comment in - * get_ufunc_arguments. - */ - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - else { - PyErr_SetString(PyExc_TypeError, - "XX can't happen, please report a bug XX"); - return NULL; - } + return NULL; } /* Free the input references */ @@ -5544,7 +5339,6 @@ ufunc_at(PyUFuncObject *ufunc, PyObject *args) iternext = NpyIter_GetIterNext(iter_buffer, NULL); if (iternext == NULL) { - NpyIter_Close(iter_buffer); NpyIter_Deallocate(iter_buffer); goto fail; } @@ -5614,7 +5408,6 @@ ufunc_at(PyUFuncObject *ufunc, PyObject *args) PyErr_SetString(PyExc_ValueError, err_msg); } - NpyIter_Close(iter_buffer); NpyIter_Deallocate(iter_buffer); Py_XDECREF(op2_array); @@ -5632,7 +5425,7 @@ ufunc_at(PyUFuncObject *ufunc, PyObject *args) } fail: - /* iter_buffer has already been deallocated, don't use NpyIter_Close */ + /* iter_buffer has already been deallocated, don't use NpyIter_Dealloc */ if (op1_array != (PyArrayObject*)op1) { PyArray_DiscardWritebackIfCopy(op1_array); } diff --git a/numpy/core/tests/test_deprecations.py b/numpy/core/tests/test_deprecations.py index 285b2de3c..8eb258666 100644 --- a/numpy/core/tests/test_deprecations.py +++ b/numpy/core/tests/test_deprecations.py @@ -190,10 +190,10 @@ class TestComparisonDeprecations(_DeprecationTestCase): b = np.array(['a', 'b', 'c']) assert_raises(ValueError, lambda x, y: x == y, a, b) - # The empty list is not cast to string, as 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 == [] + # 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(object): diff --git a/numpy/core/tests/test_nditer.py b/numpy/core/tests/test_nditer.py index a0096efdb..13bc6b34a 100644 --- a/numpy/core/tests/test_nditer.py +++ b/numpy/core/tests/test_nditer.py @@ -2830,10 +2830,6 @@ def test_writebacks(): x[:] = 123 # x.data still valid assert_equal(au, 6) # but not connected to au - do_close = 1 - # test like above, only in C, and with an option to skip the NpyIter_Close - _multiarray_tests.test_nditer_writeback(3, do_close, au, op_dtypes=[np.dtype('f4')]) - assert_equal(au, 3) it = nditer(au, [], [['readwrite', 'updateifcopy']], casting='equiv', op_dtypes=[np.dtype('f4')]) @@ -2862,7 +2858,7 @@ def test_writebacks(): x[...] = 123 # make sure we cannot reenter the closed iterator enter = it.__enter__ - assert_raises(ValueError, enter) + assert_raises(RuntimeError, enter) def test_close_equivalent(): ''' using a context amanger and using nditer.close are equivalent @@ -2897,12 +2893,13 @@ def test_close_raises(): assert_raises(StopIteration, next, it) assert_raises(ValueError, getattr, it, 'operands') +@pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts") def test_warn_noclose(): a = np.arange(6, dtype='f4') au = a.byteswap().newbyteorder() - do_close = 0 with suppress_warnings() as sup: sup.record(RuntimeWarning) - # test like above, only in C, and with an option to skip the NpyIter_Close - _multiarray_tests.test_nditer_writeback(3, do_close, au, op_dtypes=[np.dtype('f4')]) + it = np.nditer(au, [], [['readwrite', 'updateifcopy']], + casting='equiv', op_dtypes=[np.dtype('f4')]) + del it assert len(sup.log) == 1 diff --git a/numpy/core/tests/test_numerictypes.py b/numpy/core/tests/test_numerictypes.py index cdf1b0490..4c3cc6c9e 100644 --- a/numpy/core/tests/test_numerictypes.py +++ b/numpy/core/tests/test_numerictypes.py @@ -406,3 +406,9 @@ class TestIsSubDType(object): for w1, w2 in itertools.product(self.wrappers, repeat=2): assert_(not np.issubdtype(w1(np.float32), w2(np.float64))) assert_(not np.issubdtype(w1(np.float64), w2(np.float32))) + + +def TestSctypeDict(object): + def test_longdouble(self): + assert_(np.sctypeDict['f8'] is not np.longdouble) + assert_(np.sctypeDict['c16'] is not np.clongdouble) diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py index f8f75d9ea..ba4413138 100644 --- a/numpy/core/tests/test_regression.py +++ b/numpy/core/tests/test_regression.py @@ -2375,3 +2375,19 @@ class TestRegression(object): structure = np.array([1], dtype=[(('x', 'X'), np.object_)]) structure[0]['x'] = np.array([2]) gc.collect() + + def test_dtype_scalar_squeeze(self): + # gh-11384 + values = { + 'S': b"a", + 'M': "2018-06-20", + } + for ch in np.typecodes['All']: + if ch in 'O': + continue + sctype = np.dtype(ch).type + scvalue = sctype(values.get(ch, 3)) + for axis in [None, ()]: + squeezed = scvalue.squeeze(axis=axis) + assert_equal(squeezed, scvalue) + assert_equal(type(squeezed), type(scvalue)) diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py index ef9ced354..0e564e305 100644 --- a/numpy/core/tests/test_ufunc.py +++ b/numpy/core/tests/test_ufunc.py @@ -1643,6 +1643,16 @@ class TestUfunc(object): target = np.array([ True, False, False, False], dtype=bool) assert_equal(np.all(target == (mra == ra[0])), True) + def test_scalar_equal(self): + # Scalar comparisons should always work, without deprecation warnings. + # even when the ufunc fails. + a = np.array(0.) + b = np.array('a') + assert_(a != b) + assert_(b != a) + assert_(not (a == b)) + assert_(not (b == a)) + def test_NotImplemented_not_returned(self): # See gh-5964 and gh-2091. Some of these functions are not operator # related and were fixed for other reasons in the past. @@ -1652,17 +1662,16 @@ class TestUfunc(object): np.bitwise_xor, np.left_shift, np.right_shift, np.fmax, np.fmin, np.fmod, np.hypot, np.logaddexp, np.logaddexp2, np.logical_and, np.logical_or, np.logical_xor, np.maximum, - np.minimum, np.mod - ] - - # These functions still return NotImplemented. Will be fixed in - # future. - # bad = [np.greater, np.greater_equal, np.less, np.less_equal, np.not_equal] + np.minimum, np.mod, + np.greater, np.greater_equal, np.less, np.less_equal, + np.equal, np.not_equal] a = np.array('1') b = 1 + c = np.array([1., 2.]) for f in binary_funcs: assert_raises(TypeError, f, a, b) + assert_raises(TypeError, f, c, a) def test_reduce_noncontig_output(self): # Check that reduction deals with non-contiguous output arrays |