summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/release/1.10.0-notes.rst15
-rw-r--r--numpy/build_utils/src/apple_sgemv_fix.c12
-rw-r--r--numpy/core/_internal.py75
-rw-r--r--numpy/core/src/multiarray/arraytypes.c.src38
-rw-r--r--numpy/core/src/multiarray/mapping.c179
-rw-r--r--numpy/core/src/multiarray/nditer_pywrap.c14
-rw-r--r--numpy/core/src/npysort/heapsort.c.src25
-rw-r--r--numpy/core/src/npysort/mergesort.c.src16
-rw-r--r--numpy/core/src/npysort/quicksort.c.src25
-rw-r--r--numpy/core/src/private/npy_sort.h324
-rw-r--r--numpy/core/tests/test_indexing.py4
-rw-r--r--numpy/core/tests/test_multiarray.py72
-rw-r--r--numpy/core/tests/test_records.py5
-rw-r--r--numpy/ma/core.py260
-rw-r--r--numpy/ma/tests/test_core.py35
-rw-r--r--numpy/ma/tests/test_subclassing.py40
16 files changed, 654 insertions, 485 deletions
diff --git a/doc/release/1.10.0-notes.rst b/doc/release/1.10.0-notes.rst
index 50b1aa0b8..2318e522e 100644
--- a/doc/release/1.10.0-notes.rst
+++ b/doc/release/1.10.0-notes.rst
@@ -94,6 +94,16 @@ provided in the 'out' keyword argument, and it would be used as the first
output for ufuncs with multiple outputs, is deprecated, and will result in a
`DeprecationWarning` now and an error in the future.
+byte-array indices now raises an IndexError
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Indexing an ndarray using a byte-string in Python 3 now raises an IndexError
+instead of a ValueError.
+
+Masked arrays containing objects with arrays
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+For such (rare) masked arrays, getting a single masked item no longer returns a
+corrupted masked array, but a fully masked version of the item.
+
New Features
============
@@ -252,8 +262,9 @@ object arrays that were generated on Python 2.
MaskedArray support for more complicated base classes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Built-in assumptions that the baseclass behaved like a plain array are being
-removed. In particalur, setting and getting elements and ranges will respect
-baseclass overrides of ``__setitem__`` and ``__getitem__``.
+removed. In particular, setting and getting elements and ranges will respect
+baseclass overrides of ``__setitem__`` and ``__getitem__``, and arithmetic
+will respect overrides of ``__add__``, ``__sub__``, etc.
Changes
=======
diff --git a/numpy/build_utils/src/apple_sgemv_fix.c b/numpy/build_utils/src/apple_sgemv_fix.c
index 558343477..ffdfb81f7 100644
--- a/numpy/build_utils/src/apple_sgemv_fix.c
+++ b/numpy/build_utils/src/apple_sgemv_fix.c
@@ -97,29 +97,27 @@ static void loadlib()
veclib = dlopen(VECLIB_FILE, RTLD_LOCAL | RTLD_FIRST);
if (!veclib) {
veclib = NULL;
- sprintf(errormsg,"Failed to open vecLib from location '%s'.", VECLIB_FILE);
+ snprintf(errormsg, sizeof(errormsg),
+ "Failed to open vecLib from location '%s'.", VECLIB_FILE);
Py_FatalError(errormsg); /* calls abort() and dumps core */
}
/* resolve Fortran SGEMV from Accelerate */
accelerate_sgemv = (fortran_sgemv_t*) dlsym(veclib, "sgemv_");
if (!accelerate_sgemv) {
unloadlib();
- sprintf(errormsg,"Failed to resolve symbol 'sgemv_'.");
- Py_FatalError(errormsg);
+ Py_FatalError("Failed to resolve symbol 'sgemv_'.");
}
/* resolve cblas_sgemv from Accelerate */
accelerate_cblas_sgemv = (cblas_sgemv_t*) dlsym(veclib, "cblas_sgemv");
if (!accelerate_cblas_sgemv) {
unloadlib();
- sprintf(errormsg,"Failed to resolve symbol 'cblas_sgemv'.");
- Py_FatalError(errormsg);
+ Py_FatalError("Failed to resolve symbol 'cblas_sgemv'.");
}
/* resolve cblas_sgemm from Accelerate */
accelerate_cblas_sgemm = (cblas_sgemm_t*) dlsym(veclib, "cblas_sgemm");
if (!accelerate_cblas_sgemm) {
unloadlib();
- sprintf(errormsg,"Failed to resolve symbol 'cblas_sgemm'.");
- Py_FatalError(errormsg);
+ Py_FatalError("Failed to resolve symbol 'cblas_sgemm'.");
}
}
diff --git a/numpy/core/_internal.py b/numpy/core/_internal.py
index e80c22dfe..a20bf10e4 100644
--- a/numpy/core/_internal.py
+++ b/numpy/core/_internal.py
@@ -10,7 +10,10 @@ import re
import sys
import warnings
-from numpy.compat import asbytes, bytes
+from numpy.compat import asbytes, bytes, basestring
+from .multiarray import dtype, array, ndarray
+import ctypes
+from .numerictypes import object_
if (sys.byteorder == 'little'):
_nbo = asbytes('<')
@@ -18,7 +21,6 @@ else:
_nbo = asbytes('>')
def _makenames_list(adict, align):
- from .multiarray import dtype
allfields = []
fnames = list(adict.keys())
for fname in fnames:
@@ -52,7 +54,6 @@ def _makenames_list(adict, align):
# a dictionary without "names" and "formats"
# fields is used as a data-type descriptor.
def _usefields(adict, align):
- from .multiarray import dtype
try:
names = adict[-1]
except KeyError:
@@ -130,7 +131,6 @@ def _array_descr(descriptor):
# so don't remove the name here, or you'll
# break backward compatibilty.
def _reconstruct(subtype, shape, dtype):
- from .multiarray import ndarray
return ndarray.__new__(subtype, shape, dtype)
@@ -194,12 +194,10 @@ def _commastring(astr):
return result
def _getintp_ctype():
- from .multiarray import dtype
val = _getintp_ctype.cache
if val is not None:
return val
char = dtype('p').char
- import ctypes
if (char == 'i'):
val = ctypes.c_int
elif char == 'l':
@@ -224,7 +222,6 @@ class _missing_ctypes(object):
class _ctypes(object):
def __init__(self, array, ptr=None):
try:
- import ctypes
self._ctypes = ctypes
except ImportError:
self._ctypes = _missing_ctypes()
@@ -287,23 +284,55 @@ def _newnames(datatype, order):
return tuple(list(order) + nameslist)
raise ValueError("unsupported order value: %s" % (order,))
-# Given an array with fields and a sequence of field names
-# construct a new array with just those fields copied over
-def _index_fields(ary, fields):
- from .multiarray import empty, dtype, array
+def _index_fields(ary, names):
+ """ Given a structured array and a sequence of field names
+ construct new array with just those fields.
+
+ Parameters
+ ----------
+ ary : ndarray
+ Structured array being subscripted
+ names : string or list of strings
+ Either a single field name, or a list of field names
+
+ Returns
+ -------
+ sub_ary : ndarray
+ If `names` is a single field name, the return value is identical to
+ ary.getfield, a writeable view into `ary`. If `names` is a list of
+ field names the return value is a copy of `ary` containing only those
+ fields. This is planned to return a view in the future.
+
+ Raises
+ ------
+ ValueError
+ If `ary` does not contain a field given in `names`.
+
+ """
dt = ary.dtype
- names = [name for name in fields if name in dt.names]
- formats = [dt.fields[name][0] for name in fields if name in dt.names]
- offsets = [dt.fields[name][1] for name in fields if name in dt.names]
+ #use getfield to index a single field
+ if isinstance(names, basestring):
+ try:
+ return ary.getfield(dt.fields[names][0], dt.fields[names][1])
+ except KeyError:
+ raise ValueError("no field of name %s" % names)
+
+ for name in names:
+ if name not in dt.fields:
+ raise ValueError("no field of name %s" % name)
- view_dtype = {'names':names, 'formats':formats, 'offsets':offsets, 'itemsize':dt.itemsize}
- view = ary.view(dtype=view_dtype)
+ formats = [dt.fields[name][0] for name in names]
+ offsets = [dt.fields[name][1] for name in names]
+
+ view_dtype = {'names': names, 'formats': formats,
+ 'offsets': offsets, 'itemsize': dt.itemsize}
+
+ # return copy for now (future plan to return ary.view(dtype=view_dtype))
+ copy_dtype = {'names': view_dtype['names'],
+ 'formats': view_dtype['formats']}
+ return array(ary.view(dtype=view_dtype), dtype=copy_dtype, copy=True)
- # Return a copy for now until behavior is fully deprecated
- # in favor of returning view
- copy_dtype = {'names':view_dtype['names'], 'formats':view_dtype['formats']}
- return array(view, dtype=copy_dtype, copy=True)
def _get_all_field_offsets(dtype, base_offset=0):
""" Returns the types and offsets of all fields in a (possibly structured)
@@ -363,8 +392,6 @@ def _check_field_overlap(new_fields, old_fields):
If the new fields are incompatible with the old fields
"""
- from .numerictypes import object_
- from .multiarray import dtype
#first go byte by byte and check we do not access bytes not in old_fields
new_bytes = set()
@@ -527,8 +554,6 @@ _pep3118_standard_map = {
_pep3118_standard_typechars = ''.join(_pep3118_standard_map.keys())
def _dtype_from_pep3118(spec, byteorder='@', is_subdtype=False):
- from numpy.core.multiarray import dtype
-
fields = {}
offset = 0
explicit_name = False
@@ -694,8 +719,6 @@ def _dtype_from_pep3118(spec, byteorder='@', is_subdtype=False):
def _add_trailing_padding(value, padding):
"""Inject the specified number of padding bytes at the end of a dtype"""
- from numpy.core.multiarray import dtype
-
if value.fields is None:
vfields = {'f0': (value, 0)}
else:
diff --git a/numpy/core/src/multiarray/arraytypes.c.src b/numpy/core/src/multiarray/arraytypes.c.src
index c19d31a0d..307f9a0c0 100644
--- a/numpy/core/src/multiarray/arraytypes.c.src
+++ b/numpy/core/src/multiarray/arraytypes.c.src
@@ -726,7 +726,7 @@ VOID_setitem(PyObject *op, char *ip, PyArrayObject *ap)
PyObject *tup;
int savedflags;
- res = -1;
+ res = 0;
/* get the names from the fields dictionary*/
names = descr->names;
n = PyTuple_GET_SIZE(names);
@@ -2297,9 +2297,13 @@ STRING_nonzero (char *ip, PyArrayObject *ap)
int len = PyArray_DESCR(ap)->elsize;
int i;
npy_bool nonz = NPY_FALSE;
+ npy_bool seen_null = NPY_FALSE;
for (i = 0; i < len; i++) {
- if (!Py_STRING_ISSPACE(*ip)) {
+ if (*ip == '\0') {
+ seen_null = NPY_TRUE;
+ }
+ else if (seen_null || !Py_STRING_ISSPACE(*ip)) {
nonz = NPY_TRUE;
break;
}
@@ -2320,6 +2324,7 @@ UNICODE_nonzero (npy_ucs4 *ip, PyArrayObject *ap)
int len = PyArray_DESCR(ap)->elsize >> 2;
int i;
npy_bool nonz = NPY_FALSE;
+ npy_bool seen_null = NPY_FALSE;
char *buffer = NULL;
if ((!PyArray_ISNOTSWAPPED(ap)) || (!PyArray_ISALIGNED(ap))) {
@@ -2335,7 +2340,10 @@ UNICODE_nonzero (npy_ucs4 *ip, PyArrayObject *ap)
}
for (i = 0; i < len; i++) {
- if (!PyArray_UCS4_ISSPACE(*ip)) {
+ if (*ip == '\0') {
+ seen_null = NPY_TRUE;
+ }
+ else if (seen_null || !PyArray_UCS4_ISSPACE(*ip)) {
nonz = NPY_TRUE;
break;
}
@@ -3964,14 +3972,14 @@ static PyArray_ArrFuncs _Py@NAME@_ArrFuncs = {
(PyArray_FillWithScalarFunc*)NULL,
#if @sort@
{
- (PyArray_SortFunc *)quicksort_@suff@,
- (PyArray_SortFunc *)heapsort_@suff@,
- (PyArray_SortFunc *)mergesort_@suff@
+ quicksort_@suff@,
+ heapsort_@suff@,
+ mergesort_@suff@
},
{
- (PyArray_ArgSortFunc *)aquicksort_@suff@,
- (PyArray_ArgSortFunc *)aheapsort_@suff@,
- (PyArray_ArgSortFunc *)amergesort_@suff@
+ aquicksort_@suff@,
+ aheapsort_@suff@,
+ amergesort_@suff@
},
#else
{
@@ -4106,14 +4114,14 @@ static PyArray_ArrFuncs _Py@NAME@_ArrFuncs = {
(PyArray_FillWithScalarFunc*)@from@_fillwithscalar,
#if @sort@
{
- (PyArray_SortFunc *)quicksort_@suff@,
- (PyArray_SortFunc *)heapsort_@suff@,
- (PyArray_SortFunc *)mergesort_@suff@
+ quicksort_@suff@,
+ heapsort_@suff@,
+ mergesort_@suff@
},
{
- (PyArray_ArgSortFunc *)aquicksort_@suff@,
- (PyArray_ArgSortFunc *)aheapsort_@suff@,
- (PyArray_ArgSortFunc *)amergesort_@suff@
+ aquicksort_@suff@,
+ aheapsort_@suff@,
+ amergesort_@suff@
},
#else
{
diff --git a/numpy/core/src/multiarray/mapping.c b/numpy/core/src/multiarray/mapping.c
index 604f5390f..de9a2d444 100644
--- a/numpy/core/src/multiarray/mapping.c
+++ b/numpy/core/src/multiarray/mapping.c
@@ -215,6 +215,7 @@ prepare_index(PyArrayObject *self, PyObject *index,
}
for (i = 0; i < n; i++) {
PyObject *tmp_obj = PySequence_GetItem(index, i);
+ /* if getitem fails (unusual) treat this as a single index */
if (tmp_obj == NULL) {
PyErr_Clear();
make_tuple = 0;
@@ -772,8 +773,8 @@ prepare_index(PyArrayObject *self, PyObject *index,
if (indices[i].value != PyArray_DIM(self, used_ndim)) {
static PyObject *warning;
- char *err_msg[174];
- sprintf(err_msg,
+ char err_msg[174];
+ PyOS_snprintf(err_msg, sizeof(err_msg),
"boolean index did not match indexed array along "
"dimension %d; dimension is %" NPY_INTP_FMT
" but corresponding boolean dimension is %" NPY_INTP_FMT,
@@ -1361,6 +1362,52 @@ array_subscript_asarray(PyArrayObject *self, PyObject *op)
return PyArray_EnsureAnyArray(array_subscript(self, op));
}
+NPY_NO_EXPORT int
+obj_is_string_or_stringlist(PyObject *op)
+{
+#if defined(NPY_PY3K)
+ if (PyUnicode_Check(op)) {
+#else
+ if (PyString_Check(op) || PyUnicode_Check(op)) {
+#endif
+ return 1;
+ }
+ else if (PySequence_Check(op) && !PyTuple_Check(op)) {
+ int seqlen, i;
+ PyObject *obj = NULL;
+ seqlen = PySequence_Size(op);
+
+ /* quit if we come across a 0-d array (seqlen==-1) or a 0-len array */
+ if (seqlen == -1) {
+ PyErr_Clear();
+ return 0;
+ }
+ if (seqlen == 0) {
+ return 0;
+ }
+
+ for (i = 0; i < seqlen; i++) {
+ obj = PySequence_GetItem(op, i);
+ if (obj == NULL) {
+ /* only happens for strange sequence objects. Silently fail */
+ PyErr_Clear();
+ return 0;
+ }
+
+#if defined(NPY_PY3K)
+ if (!PyUnicode_Check(obj)) {
+#else
+ if (!PyString_Check(obj) && !PyUnicode_Check(obj)) {
+#endif
+ Py_DECREF(obj);
+ return 0;
+ }
+ Py_DECREF(obj);
+ }
+ return 1;
+ }
+ return 0;
+}
/*
* General function for indexing a NumPy array with a Python object.
@@ -1382,76 +1429,26 @@ array_subscript(PyArrayObject *self, PyObject *op)
PyArrayMapIterObject * mit = NULL;
- /* Check for multiple field access */
- if (PyDataType_HASFIELDS(PyArray_DESCR(self))) {
- /* Check for single field access */
- /*
- * TODO: Moving this code block into the HASFIELDS, means that
- * string integers temporarily work as indices.
- */
- if (PyString_Check(op) || PyUnicode_Check(op)) {
- PyObject *temp, *obj;
-
- if (PyDataType_HASFIELDS(PyArray_DESCR(self))) {
- obj = PyDict_GetItem(PyArray_DESCR(self)->fields, op);
- if (obj != NULL) {
- PyArray_Descr *descr;
- int offset;
- PyObject *title;
-
- if (PyArg_ParseTuple(obj, "Oi|O", &descr, &offset, &title)) {
- Py_INCREF(descr);
- return PyArray_GetField(self, descr, offset);
- }
- }
- }
+ /* return fields if op is a string index */
+ if (PyDataType_HASFIELDS(PyArray_DESCR(self)) &&
+ obj_is_string_or_stringlist(op)) {
+ PyObject *obj;
+ static PyObject *indexfunc = NULL;
+ npy_cache_pyfunc("numpy.core._internal", "_index_fields", &indexfunc);
+ if (indexfunc == NULL) {
+ return NULL;
+ }
- temp = op;
- if (PyUnicode_Check(op)) {
- temp = PyUnicode_AsUnicodeEscapeString(op);
- }
- PyErr_Format(PyExc_ValueError,
- "field named %s not found",
- PyBytes_AsString(temp));
- if (temp != op) {
- Py_DECREF(temp);
- }
+ obj = PyObject_CallFunction(indexfunc, "OO", self, op);
+ if (obj == NULL) {
return NULL;
}
- else if (PySequence_Check(op) && !PyTuple_Check(op)) {
- int seqlen, i;
- PyObject *obj;
- seqlen = PySequence_Size(op);
- for (i = 0; i < seqlen; i++) {
- obj = PySequence_GetItem(op, i);
- if (!PyString_Check(obj) && !PyUnicode_Check(obj)) {
- Py_DECREF(obj);
- break;
- }
- Py_DECREF(obj);
- }
- /*
- * Extract multiple fields if all elements in sequence
- * are either string or unicode (i.e. no break occurred).
- */
- fancy = ((seqlen > 0) && (i == seqlen));
- if (fancy) {
- PyObject *_numpy_internal;
- _numpy_internal = PyImport_ImportModule("numpy.core._internal");
- if (_numpy_internal == NULL) {
- return NULL;
- }
- obj = PyObject_CallMethod(_numpy_internal,
- "_index_fields", "OO", self, op);
- Py_DECREF(_numpy_internal);
- if (obj == NULL) {
- return NULL;
- }
- PyArray_ENABLEFLAGS((PyArrayObject*)obj, NPY_ARRAY_WARN_ON_WRITE);
- return obj;
- }
+ /* warn if writing to a copy. copies will have no base */
+ if (PyArray_BASE((PyArrayObject*)obj) == NULL) {
+ PyArray_ENABLEFLAGS((PyArrayObject*)obj, NPY_ARRAY_WARN_ON_WRITE);
}
+ return obj;
}
/* Prepare the indices */
@@ -1783,35 +1780,39 @@ array_assign_subscript(PyArrayObject *self, PyObject *ind, PyObject *op)
return -1;
}
- /* Single field access */
- if (PyDataType_HASFIELDS(PyArray_DESCR(self))) {
- if (PyString_Check(ind) || PyUnicode_Check(ind)) {
- PyObject *obj;
-
- obj = PyDict_GetItem(PyArray_DESCR(self)->fields, ind);
- if (obj != NULL) {
- PyArray_Descr *descr;
- int offset;
- PyObject *title;
+ /* field access */
+ if (PyDataType_HASFIELDS(PyArray_DESCR(self)) &&
+ obj_is_string_or_stringlist(ind)) {
+ PyObject *obj;
+ static PyObject *indexfunc = NULL;
- if (PyArg_ParseTuple(obj, "Oi|O", &descr, &offset, &title)) {
- Py_INCREF(descr);
- return PyArray_SetField(self, descr, offset, op);
- }
- }
#if defined(NPY_PY3K)
- PyErr_Format(PyExc_ValueError,
- "field named %S not found",
- ind);
+ if (!PyUnicode_Check(ind)) {
#else
- PyErr_Format(PyExc_ValueError,
- "field named %s not found",
- PyString_AsString(ind));
+ if (!PyString_Check(ind) && !PyUnicode_Check(ind)) {
#endif
+ PyErr_SetString(PyExc_ValueError,
+ "multi-field assignment is not supported");
+ }
+
+ npy_cache_pyfunc("numpy.core._internal", "_index_fields", &indexfunc);
+ if (indexfunc == NULL) {
+ return -1;
+ }
+
+ obj = PyObject_CallFunction(indexfunc, "OO", self, ind);
+ if (obj == NULL) {
return -1;
}
- }
+ if (PyArray_CopyObject((PyArrayObject*)obj, op) < 0) {
+ Py_DECREF(obj);
+ return -1;
+ }
+ Py_DECREF(obj);
+
+ return 0;
+ }
/* Prepare the indices */
index_type = prepare_index(self, ind, indices, &index_num,
diff --git a/numpy/core/src/multiarray/nditer_pywrap.c b/numpy/core/src/multiarray/nditer_pywrap.c
index 77c45434f..25e48ba05 100644
--- a/numpy/core/src/multiarray/nditer_pywrap.c
+++ b/numpy/core/src/multiarray/nditer_pywrap.c
@@ -2227,6 +2227,14 @@ npyiter_seq_ass_slice(NewNpyArrayIterObject *self, Py_ssize_t ilow,
return 0;
}
+/* Py3 changes PySlice_GetIndices' first argument's type to PyObject* */
+#ifdef NPY_PY3K
+# define slice_getindices PySlice_GetIndices
+#else
+# define slice_getindices(op, nop, start, end, step) \
+ PySlice_GetIndices((PySliceObject *)op, nop, start, end, step)
+#endif
+
static PyObject *
npyiter_subscript(NewNpyArrayIterObject *self, PyObject *op)
{
@@ -2253,8 +2261,7 @@ npyiter_subscript(NewNpyArrayIterObject *self, PyObject *op)
}
else if (PySlice_Check(op)) {
Py_ssize_t istart = 0, iend = 0, istep = 0;
- if (PySlice_GetIndices((PySliceObject *)op,
- NpyIter_GetNOp(self->iter),
+ if (slice_getindices(op, NpyIter_GetNOp(self->iter),
&istart, &iend, &istep) < 0) {
return NULL;
}
@@ -2303,8 +2310,7 @@ npyiter_ass_subscript(NewNpyArrayIterObject *self, PyObject *op,
}
else if (PySlice_Check(op)) {
Py_ssize_t istart = 0, iend = 0, istep = 0;
- if (PySlice_GetIndices((PySliceObject *)op,
- NpyIter_GetNOp(self->iter),
+ if (slice_getindices(op, NpyIter_GetNOp(self->iter),
&istart, &iend, &istep) < 0) {
return -1;
}
diff --git a/numpy/core/src/npysort/heapsort.c.src b/numpy/core/src/npysort/heapsort.c.src
index 88f7978cc..c2e3b63cb 100644
--- a/numpy/core/src/npysort/heapsort.c.src
+++ b/numpy/core/src/npysort/heapsort.c.src
@@ -61,13 +61,13 @@
*/
int
-heapsort_@suff@(@type@ *start, npy_intp n, void *NOT_USED)
+heapsort_@suff@(void *start, npy_intp n, void *NOT_USED)
{
@type@ tmp, *a;
npy_intp i,j,l;
/* The array needs to be offset by one for heapsort indexing */
- a = start - 1;
+ a = (@type@ *)start - 1;
for (l = n>>1; l > 0; --l) {
tmp = a[l];
@@ -112,8 +112,9 @@ heapsort_@suff@(@type@ *start, npy_intp n, void *NOT_USED)
int
-aheapsort_@suff@(@type@ *v, npy_intp *tosort, npy_intp n, void *NOT_USED)
+aheapsort_@suff@(void *vv, npy_intp *tosort, npy_intp n, void *NOT_USED)
{
+ @type@ *v = vv;
npy_intp *a, i,j,l, tmp;
/* The arrays need to be offset by one for heapsort indexing */
a = tosort - 1;
@@ -177,11 +178,12 @@ aheapsort_@suff@(@type@ *v, npy_intp *tosort, npy_intp n, void *NOT_USED)
*/
int
-heapsort_@suff@(@type@ *start, npy_intp n, PyArrayObject *arr)
+heapsort_@suff@(void *start, npy_intp n, void *varr)
{
+ PyArrayObject *arr = varr;
size_t len = PyArray_ITEMSIZE(arr)/sizeof(@type@);
@type@ *tmp = malloc(PyArray_ITEMSIZE(arr));
- @type@ *a = start - len;
+ @type@ *a = (@type@ *)start - len;
npy_intp i, j, l;
if (tmp == NULL) {
@@ -230,8 +232,10 @@ heapsort_@suff@(@type@ *start, npy_intp n, PyArrayObject *arr)
int
-aheapsort_@suff@(@type@ *v, npy_intp *tosort, npy_intp n, PyArrayObject *arr)
+aheapsort_@suff@(void *vv, npy_intp *tosort, npy_intp n, void *varr)
{
+ @type@ *v = vv;
+ PyArrayObject *arr = varr;
size_t len = PyArray_ITEMSIZE(arr)/sizeof(@type@);
npy_intp *a, i,j,l, tmp;
@@ -288,12 +292,13 @@ aheapsort_@suff@(@type@ *v, npy_intp *tosort, npy_intp n, PyArrayObject *arr)
int
-npy_heapsort(char *start, npy_intp num, PyArrayObject *arr)
+npy_heapsort(void *start, npy_intp num, void *varr)
{
+ PyArrayObject *arr = varr;
npy_intp elsize = PyArray_ITEMSIZE(arr);
PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare;
char *tmp = malloc(elsize);
- char *a = start - elsize;
+ char *a = (char *)start - elsize;
npy_intp i, j, l;
if (tmp == NULL) {
@@ -344,8 +349,10 @@ npy_heapsort(char *start, npy_intp num, PyArrayObject *arr)
int
-npy_aheapsort(char *v, npy_intp *tosort, npy_intp n, PyArrayObject *arr)
+npy_aheapsort(void *vv, npy_intp *tosort, npy_intp n, void *varr)
{
+ char *v = vv;
+ PyArrayObject *arr = varr;
npy_intp elsize = PyArray_ITEMSIZE(arr);
PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare;
npy_intp *a, i, j, l, tmp;
diff --git a/numpy/core/src/npysort/mergesort.c.src b/numpy/core/src/npysort/mergesort.c.src
index 406be66d0..fc82e2135 100644
--- a/numpy/core/src/npysort/mergesort.c.src
+++ b/numpy/core/src/npysort/mergesort.c.src
@@ -104,7 +104,7 @@ mergesort0_@suff@(@type@ *pl, @type@ *pr, @type@ *pw)
int
-mergesort_@suff@(@type@ *start, npy_intp num, void *NOT_USED)
+mergesort_@suff@(void *start, npy_intp num, void *NOT_USED)
{
@type@ *pl, *pr, *pw;
@@ -167,7 +167,7 @@ amergesort0_@suff@(npy_intp *pl, npy_intp *pr, @type@ *v, npy_intp *pw)
int
-amergesort_@suff@(@type@ *v, npy_intp *tosort, npy_intp num, void *NOT_USED)
+amergesort_@suff@(void *v, npy_intp *tosort, npy_intp num, void *NOT_USED)
{
npy_intp *pl, *pr, *pw;
@@ -246,8 +246,9 @@ mergesort0_@suff@(@type@ *pl, @type@ *pr, @type@ *pw, @type@ *vp, size_t len)
int
-mergesort_@suff@(@type@ *start, npy_intp num, PyArrayObject *arr)
+mergesort_@suff@(void *start, npy_intp num, void *varr)
{
+ PyArrayObject *arr = varr;
size_t elsize = PyArray_ITEMSIZE(arr);
size_t len = elsize / sizeof(@type@);
@type@ *pl, *pr, *pw, *vp;
@@ -321,8 +322,9 @@ amergesort0_@suff@(npy_intp *pl, npy_intp *pr, @type@ *v, npy_intp *pw, size_t l
int
-amergesort_@suff@(@type@ *v, npy_intp *tosort, npy_intp num, PyArrayObject *arr)
+amergesort_@suff@(void *v, npy_intp *tosort, npy_intp num, void *varr)
{
+ PyArrayObject *arr = varr;
size_t elsize = PyArray_ITEMSIZE(arr);
size_t len = elsize / sizeof(@type@);
npy_intp *pl, *pr, *pw;
@@ -396,8 +398,9 @@ npy_mergesort0(char *pl, char *pr, char *pw, char *vp, npy_intp elsize,
int
-npy_mergesort(char *start, npy_intp num, PyArrayObject *arr)
+npy_mergesort(void *start, npy_intp num, void *varr)
{
+ PyArrayObject *arr = varr;
npy_intp elsize = PyArray_ITEMSIZE(arr);
PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare;
char *pl = start;
@@ -465,8 +468,9 @@ npy_amergesort0(npy_intp *pl, npy_intp *pr, char *v, npy_intp *pw,
int
-npy_amergesort(char *v, npy_intp *tosort, npy_intp num, PyArrayObject *arr)
+npy_amergesort(void *v, npy_intp *tosort, npy_intp num, void *varr)
{
+ PyArrayObject *arr = varr;
npy_intp elsize = PyArray_ITEMSIZE(arr);
PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare;
npy_intp *pl, *pr, *pw;
diff --git a/numpy/core/src/npysort/quicksort.c.src b/numpy/core/src/npysort/quicksort.c.src
index 5334aca76..91b5e67f5 100644
--- a/numpy/core/src/npysort/quicksort.c.src
+++ b/numpy/core/src/npysort/quicksort.c.src
@@ -61,11 +61,11 @@
*/
int
-quicksort_@suff@(@type@ *start, npy_intp num, void *NOT_USED)
+quicksort_@suff@(void *start, npy_intp num, void *NOT_USED)
{
@type@ vp;
@type@ *pl = start;
- @type@ *pr = start + num - 1;
+ @type@ *pr = pl + num - 1;
@type@ *stack[PYA_QS_STACK];
@type@ **sptr = stack;
@type@ *pm, *pi, *pj, *pk;
@@ -126,8 +126,9 @@ quicksort_@suff@(@type@ *start, npy_intp num, void *NOT_USED)
int
-aquicksort_@suff@(@type@ *v, npy_intp* tosort, npy_intp num, void *NOT_USED)
+aquicksort_@suff@(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
+ @type@ *v = vv;
@type@ vp;
npy_intp *pl = tosort;
npy_intp *pr = tosort + num - 1;
@@ -208,12 +209,13 @@ aquicksort_@suff@(@type@ *v, npy_intp* tosort, npy_intp num, void *NOT_USED)
*/
int
-quicksort_@suff@(@type@ *start, npy_intp num, PyArrayObject *arr)
+quicksort_@suff@(void *start, npy_intp num, void *varr)
{
+ PyArrayObject *arr = varr;
const size_t len = PyArray_ITEMSIZE(arr)/sizeof(@type@);
@type@ *vp = malloc(PyArray_ITEMSIZE(arr));
@type@ *pl = start;
- @type@ *pr = start + (num - 1)*len;
+ @type@ *pr = pl + (num - 1)*len;
@type@ *stack[PYA_QS_STACK], **sptr = stack, *pm, *pi, *pj, *pk;
if (vp == NULL) {
@@ -279,8 +281,10 @@ quicksort_@suff@(@type@ *start, npy_intp num, PyArrayObject *arr)
int
-aquicksort_@suff@(@type@ *v, npy_intp* tosort, npy_intp num, PyArrayObject *arr)
+aquicksort_@suff@(void *vv, npy_intp* tosort, npy_intp num, void *varr)
{
+ @type@ *v = vv;
+ PyArrayObject *arr = varr;
size_t len = PyArray_ITEMSIZE(arr)/sizeof(@type@);
@type@ *vp;
npy_intp *pl = tosort;
@@ -355,13 +359,14 @@ aquicksort_@suff@(@type@ *v, npy_intp* tosort, npy_intp num, PyArrayObject *arr)
int
-npy_quicksort(char *start, npy_intp num, PyArrayObject *arr)
+npy_quicksort(void *start, npy_intp num, void *varr)
{
+ PyArrayObject *arr = varr;
npy_intp elsize = PyArray_ITEMSIZE(arr);
PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare;
char *vp = malloc(elsize);
char *pl = start;
- char *pr = start + (num - 1)*elsize;
+ char *pr = pl + (num - 1)*elsize;
char *stack[PYA_QS_STACK];
char **sptr = stack;
char *pm, *pi, *pj, *pk;
@@ -439,8 +444,10 @@ npy_quicksort(char *start, npy_intp num, PyArrayObject *arr)
int
-npy_aquicksort(char *v, npy_intp* tosort, npy_intp num, PyArrayObject *arr)
+npy_aquicksort(void *vv, npy_intp* tosort, npy_intp num, void *varr)
{
+ char *v = vv;
+ PyArrayObject *arr = varr;
npy_intp elsize = PyArray_ITEMSIZE(arr);
PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare;
char *vp;
diff --git a/numpy/core/src/private/npy_sort.h b/numpy/core/src/private/npy_sort.h
index 85630b2df..511d71b01 100644
--- a/numpy/core/src/private/npy_sort.h
+++ b/numpy/core/src/private/npy_sort.h
@@ -10,187 +10,187 @@
#define NPY_ECOMP 2
-int quicksort_bool(npy_bool *vec, npy_intp cnt, void *null);
-int heapsort_bool(npy_bool *vec, npy_intp cnt, void *null);
-int mergesort_bool(npy_bool *vec, npy_intp cnt, void *null);
-int aquicksort_bool(npy_bool *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_bool(npy_bool *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_bool(npy_bool *vec, npy_intp *ind, npy_intp cnt, void *null);
+int quicksort_bool(void *vec, npy_intp cnt, void *null);
+int heapsort_bool(void *vec, npy_intp cnt, void *null);
+int mergesort_bool(void *vec, npy_intp cnt, void *null);
+int aquicksort_bool(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int aheapsort_bool(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int amergesort_bool(void *vec, npy_intp *ind, npy_intp cnt, void *null);
-int quicksort_byte(npy_byte *vec, npy_intp cnt, void *null);
-int heapsort_byte(npy_byte *vec, npy_intp cnt, void *null);
-int mergesort_byte(npy_byte *vec, npy_intp cnt, void *null);
-int aquicksort_byte(npy_byte *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_byte(npy_byte *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_byte(npy_byte *vec, npy_intp *ind, npy_intp cnt, void *null);
-
-
-int quicksort_ubyte(npy_ubyte *vec, npy_intp cnt, void *null);
-int heapsort_ubyte(npy_ubyte *vec, npy_intp cnt, void *null);
-int mergesort_ubyte(npy_ubyte *vec, npy_intp cnt, void *null);
-int aquicksort_ubyte(npy_ubyte *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_ubyte(npy_ubyte *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_ubyte(npy_ubyte *vec, npy_intp *ind, npy_intp cnt, void *null);
+int quicksort_byte(void *vec, npy_intp cnt, void *null);
+int heapsort_byte(void *vec, npy_intp cnt, void *null);
+int mergesort_byte(void *vec, npy_intp cnt, void *null);
+int aquicksort_byte(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int aheapsort_byte(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int amergesort_byte(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+
+
+int quicksort_ubyte(void *vec, npy_intp cnt, void *null);
+int heapsort_ubyte(void *vec, npy_intp cnt, void *null);
+int mergesort_ubyte(void *vec, npy_intp cnt, void *null);
+int aquicksort_ubyte(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int aheapsort_ubyte(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int amergesort_ubyte(void *vec, npy_intp *ind, npy_intp cnt, void *null);
-int quicksort_short(npy_short *vec, npy_intp cnt, void *null);
-int heapsort_short(npy_short *vec, npy_intp cnt, void *null);
-int mergesort_short(npy_short *vec, npy_intp cnt, void *null);
-int aquicksort_short(npy_short *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_short(npy_short *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_short(npy_short *vec, npy_intp *ind, npy_intp cnt, void *null);
-
-
-int quicksort_ushort(npy_ushort *vec, npy_intp cnt, void *null);
-int heapsort_ushort(npy_ushort *vec, npy_intp cnt, void *null);
-int mergesort_ushort(npy_ushort *vec, npy_intp cnt, void *null);
-int aquicksort_ushort(npy_ushort *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_ushort(npy_ushort *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_ushort(npy_ushort *vec, npy_intp *ind, npy_intp cnt, void *null);
+int quicksort_short(void *vec, npy_intp cnt, void *null);
+int heapsort_short(void *vec, npy_intp cnt, void *null);
+int mergesort_short(void *vec, npy_intp cnt, void *null);
+int aquicksort_short(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int aheapsort_short(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int amergesort_short(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+
+
+int quicksort_ushort(void *vec, npy_intp cnt, void *null);
+int heapsort_ushort(void *vec, npy_intp cnt, void *null);
+int mergesort_ushort(void *vec, npy_intp cnt, void *null);
+int aquicksort_ushort(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int aheapsort_ushort(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int amergesort_ushort(void *vec, npy_intp *ind, npy_intp cnt, void *null);
-int quicksort_int(npy_int *vec, npy_intp cnt, void *null);
-int heapsort_int(npy_int *vec, npy_intp cnt, void *null);
-int mergesort_int(npy_int *vec, npy_intp cnt, void *null);
-int aquicksort_int(npy_int *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_int(npy_int *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_int(npy_int *vec, npy_intp *ind, npy_intp cnt, void *null);
-
-
-int quicksort_uint(npy_uint *vec, npy_intp cnt, void *null);
-int heapsort_uint(npy_uint *vec, npy_intp cnt, void *null);
-int mergesort_uint(npy_uint *vec, npy_intp cnt, void *null);
-int aquicksort_uint(npy_uint *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_uint(npy_uint *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_uint(npy_uint *vec, npy_intp *ind, npy_intp cnt, void *null);
+int quicksort_int(void *vec, npy_intp cnt, void *null);
+int heapsort_int(void *vec, npy_intp cnt, void *null);
+int mergesort_int(void *vec, npy_intp cnt, void *null);
+int aquicksort_int(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int aheapsort_int(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int amergesort_int(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+
+
+int quicksort_uint(void *vec, npy_intp cnt, void *null);
+int heapsort_uint(void *vec, npy_intp cnt, void *null);
+int mergesort_uint(void *vec, npy_intp cnt, void *null);
+int aquicksort_uint(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int aheapsort_uint(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int amergesort_uint(void *vec, npy_intp *ind, npy_intp cnt, void *null);
-int quicksort_long(npy_long *vec, npy_intp cnt, void *null);
-int heapsort_long(npy_long *vec, npy_intp cnt, void *null);
-int mergesort_long(npy_long *vec, npy_intp cnt, void *null);
-int aquicksort_long(npy_long *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_long(npy_long *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_long(npy_long *vec, npy_intp *ind, npy_intp cnt, void *null);
-
-
-int quicksort_ulong(npy_ulong *vec, npy_intp cnt, void *null);
-int heapsort_ulong(npy_ulong *vec, npy_intp cnt, void *null);
-int mergesort_ulong(npy_ulong *vec, npy_intp cnt, void *null);
-int aquicksort_ulong(npy_ulong *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_ulong(npy_ulong *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_ulong(npy_ulong *vec, npy_intp *ind, npy_intp cnt, void *null);
+int quicksort_long(void *vec, npy_intp cnt, void *null);
+int heapsort_long(void *vec, npy_intp cnt, void *null);
+int mergesort_long(void *vec, npy_intp cnt, void *null);
+int aquicksort_long(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int aheapsort_long(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int amergesort_long(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+
+
+int quicksort_ulong(void *vec, npy_intp cnt, void *null);
+int heapsort_ulong(void *vec, npy_intp cnt, void *null);
+int mergesort_ulong(void *vec, npy_intp cnt, void *null);
+int aquicksort_ulong(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int aheapsort_ulong(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int amergesort_ulong(void *vec, npy_intp *ind, npy_intp cnt, void *null);
-int quicksort_longlong(npy_longlong *vec, npy_intp cnt, void *null);
-int heapsort_longlong(npy_longlong *vec, npy_intp cnt, void *null);
-int mergesort_longlong(npy_longlong *vec, npy_intp cnt, void *null);
-int aquicksort_longlong(npy_longlong *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_longlong(npy_longlong *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_longlong(npy_longlong *vec, npy_intp *ind, npy_intp cnt, void *null);
-
-
-int quicksort_ulonglong(npy_ulonglong *vec, npy_intp cnt, void *null);
-int heapsort_ulonglong(npy_ulonglong *vec, npy_intp cnt, void *null);
-int mergesort_ulonglong(npy_ulonglong *vec, npy_intp cnt, void *null);
-int aquicksort_ulonglong(npy_ulonglong *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_ulonglong(npy_ulonglong *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_ulonglong(npy_ulonglong *vec, npy_intp *ind, npy_intp cnt, void *null);
-
-
-int quicksort_half(npy_ushort *vec, npy_intp cnt, void *null);
-int heapsort_half(npy_ushort *vec, npy_intp cnt, void *null);
-int mergesort_half(npy_ushort *vec, npy_intp cnt, void *null);
-int aquicksort_half(npy_ushort *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_half(npy_ushort *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_half(npy_ushort *vec, npy_intp *ind, npy_intp cnt, void *null);
-
-
-int quicksort_float(npy_float *vec, npy_intp cnt, void *null);
-int heapsort_float(npy_float *vec, npy_intp cnt, void *null);
-int mergesort_float(npy_float *vec, npy_intp cnt, void *null);
-int aquicksort_float(npy_float *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_float(npy_float *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_float(npy_float *vec, npy_intp *ind, npy_intp cnt, void *null);
-
-
-int quicksort_double(npy_double *vec, npy_intp cnt, void *null);
-int heapsort_double(npy_double *vec, npy_intp cnt, void *null);
-int mergesort_double(npy_double *vec, npy_intp cnt, void *null);
-int aquicksort_double(npy_double *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_double(npy_double *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_double(npy_double *vec, npy_intp *ind, npy_intp cnt, void *null);
+int quicksort_longlong(void *vec, npy_intp cnt, void *null);
+int heapsort_longlong(void *vec, npy_intp cnt, void *null);
+int mergesort_longlong(void *vec, npy_intp cnt, void *null);
+int aquicksort_longlong(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int aheapsort_longlong(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int amergesort_longlong(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+
+
+int quicksort_ulonglong(void *vec, npy_intp cnt, void *null);
+int heapsort_ulonglong(void *vec, npy_intp cnt, void *null);
+int mergesort_ulonglong(void *vec, npy_intp cnt, void *null);
+int aquicksort_ulonglong(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int aheapsort_ulonglong(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int amergesort_ulonglong(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+
+
+int quicksort_half(void *vec, npy_intp cnt, void *null);
+int heapsort_half(void *vec, npy_intp cnt, void *null);
+int mergesort_half(void *vec, npy_intp cnt, void *null);
+int aquicksort_half(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int aheapsort_half(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int amergesort_half(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+
+
+int quicksort_float(void *vec, npy_intp cnt, void *null);
+int heapsort_float(void *vec, npy_intp cnt, void *null);
+int mergesort_float(void *vec, npy_intp cnt, void *null);
+int aquicksort_float(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int aheapsort_float(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int amergesort_float(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+
+
+int quicksort_double(void *vec, npy_intp cnt, void *null);
+int heapsort_double(void *vec, npy_intp cnt, void *null);
+int mergesort_double(void *vec, npy_intp cnt, void *null);
+int aquicksort_double(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int aheapsort_double(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int amergesort_double(void *vec, npy_intp *ind, npy_intp cnt, void *null);
-int quicksort_longdouble(npy_longdouble *vec, npy_intp cnt, void *null);
-int heapsort_longdouble(npy_longdouble *vec, npy_intp cnt, void *null);
-int mergesort_longdouble(npy_longdouble *vec, npy_intp cnt, void *null);
-int aquicksort_longdouble(npy_longdouble *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_longdouble(npy_longdouble *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_longdouble(npy_longdouble *vec, npy_intp *ind, npy_intp cnt, void *null);
-
-
-int quicksort_cfloat(npy_cfloat *vec, npy_intp cnt, void *null);
-int heapsort_cfloat(npy_cfloat *vec, npy_intp cnt, void *null);
-int mergesort_cfloat(npy_cfloat *vec, npy_intp cnt, void *null);
-int aquicksort_cfloat(npy_cfloat *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_cfloat(npy_cfloat *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_cfloat(npy_cfloat *vec, npy_intp *ind, npy_intp cnt, void *null);
+int quicksort_longdouble(void *vec, npy_intp cnt, void *null);
+int heapsort_longdouble(void *vec, npy_intp cnt, void *null);
+int mergesort_longdouble(void *vec, npy_intp cnt, void *null);
+int aquicksort_longdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int aheapsort_longdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int amergesort_longdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+
+
+int quicksort_cfloat(void *vec, npy_intp cnt, void *null);
+int heapsort_cfloat(void *vec, npy_intp cnt, void *null);
+int mergesort_cfloat(void *vec, npy_intp cnt, void *null);
+int aquicksort_cfloat(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int aheapsort_cfloat(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int amergesort_cfloat(void *vec, npy_intp *ind, npy_intp cnt, void *null);
-int quicksort_cdouble(npy_cdouble *vec, npy_intp cnt, void *null);
-int heapsort_cdouble(npy_cdouble *vec, npy_intp cnt, void *null);
-int mergesort_cdouble(npy_cdouble *vec, npy_intp cnt, void *null);
-int aquicksort_cdouble(npy_cdouble *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_cdouble(npy_cdouble *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_cdouble(npy_cdouble *vec, npy_intp *ind, npy_intp cnt, void *null);
-
-
-int quicksort_clongdouble(npy_clongdouble *vec, npy_intp cnt, void *null);
-int heapsort_clongdouble(npy_clongdouble *vec, npy_intp cnt, void *null);
-int mergesort_clongdouble(npy_clongdouble *vec, npy_intp cnt, void *null);
-int aquicksort_clongdouble(npy_clongdouble *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_clongdouble(npy_clongdouble *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_clongdouble(npy_clongdouble *vec, npy_intp *ind, npy_intp cnt, void *null);
+int quicksort_cdouble(void *vec, npy_intp cnt, void *null);
+int heapsort_cdouble(void *vec, npy_intp cnt, void *null);
+int mergesort_cdouble(void *vec, npy_intp cnt, void *null);
+int aquicksort_cdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int aheapsort_cdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int amergesort_cdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+
+
+int quicksort_clongdouble(void *vec, npy_intp cnt, void *null);
+int heapsort_clongdouble(void *vec, npy_intp cnt, void *null);
+int mergesort_clongdouble(void *vec, npy_intp cnt, void *null);
+int aquicksort_clongdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int aheapsort_clongdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int amergesort_clongdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null);
-int quicksort_string(npy_char *vec, npy_intp cnt, PyArrayObject *arr);
-int heapsort_string(npy_char *vec, npy_intp cnt, PyArrayObject *arr);
-int mergesort_string(npy_char *vec, npy_intp cnt, PyArrayObject *arr);
-int aquicksort_string(npy_char *vec, npy_intp *ind, npy_intp cnt, PyArrayObject *arr);
-int aheapsort_string(npy_char *vec, npy_intp *ind, npy_intp cnt, PyArrayObject *arr);
-int amergesort_string(npy_char *vec, npy_intp *ind, npy_intp cnt, PyArrayObject *arr);
-
-
-int quicksort_unicode(npy_ucs4 *vec, npy_intp cnt, PyArrayObject *arr);
-int heapsort_unicode(npy_ucs4 *vec, npy_intp cnt, PyArrayObject *arr);
-int mergesort_unicode(npy_ucs4 *vec, npy_intp cnt, PyArrayObject *arr);
-int aquicksort_unicode(npy_ucs4 *vec, npy_intp *ind, npy_intp cnt, PyArrayObject *arr);
-int aheapsort_unicode(npy_ucs4 *vec, npy_intp *ind, npy_intp cnt, PyArrayObject *arr);
-int amergesort_unicode(npy_ucs4 *vec, npy_intp *ind, npy_intp cnt, PyArrayObject *arr);
+int quicksort_string(void *vec, npy_intp cnt, void *arr);
+int heapsort_string(void *vec, npy_intp cnt, void *arr);
+int mergesort_string(void *vec, npy_intp cnt, void *arr);
+int aquicksort_string(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
+int aheapsort_string(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
+int amergesort_string(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
+
+
+int quicksort_unicode(void *vec, npy_intp cnt, void *arr);
+int heapsort_unicode(void *vec, npy_intp cnt, void *arr);
+int mergesort_unicode(void *vec, npy_intp cnt, void *arr);
+int aquicksort_unicode(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
+int aheapsort_unicode(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
+int amergesort_unicode(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
-int quicksort_datetime(npy_datetime *vec, npy_intp cnt, void *null);
-int heapsort_datetime(npy_datetime *vec, npy_intp cnt, void *null);
-int mergesort_datetime(npy_datetime *vec, npy_intp cnt, void *null);
-int aquicksort_datetime(npy_datetime *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_datetime(npy_datetime *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_datetime(npy_datetime *vec, npy_intp *ind, npy_intp cnt, void *null);
-
-
-int quicksort_timedelta(npy_timedelta *vec, npy_intp cnt, void *null);
-int heapsort_timedelta(npy_timedelta *vec, npy_intp cnt, void *null);
-int mergesort_timedelta(npy_timedelta *vec, npy_intp cnt, void *null);
-int aquicksort_timedelta(npy_timedelta *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_timedelta(npy_timedelta *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_timedelta(npy_timedelta *vec, npy_intp *ind, npy_intp cnt, void *null);
+int quicksort_datetime(void *vec, npy_intp cnt, void *null);
+int heapsort_datetime(void *vec, npy_intp cnt, void *null);
+int mergesort_datetime(void *vec, npy_intp cnt, void *null);
+int aquicksort_datetime(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int aheapsort_datetime(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int amergesort_datetime(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+
+
+int quicksort_timedelta(void *vec, npy_intp cnt, void *null);
+int heapsort_timedelta(void *vec, npy_intp cnt, void *null);
+int mergesort_timedelta(void *vec, npy_intp cnt, void *null);
+int aquicksort_timedelta(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int aheapsort_timedelta(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+int amergesort_timedelta(void *vec, npy_intp *ind, npy_intp cnt, void *null);
-int npy_quicksort(char *vec, npy_intp cnt, PyArrayObject *arr);
-int npy_heapsort(char *vec, npy_intp cnt, PyArrayObject *arr);
-int npy_mergesort(char *vec, npy_intp cnt, PyArrayObject *arr);
-int npy_aquicksort(char *vec, npy_intp *ind, npy_intp cnt, PyArrayObject *arr);
-int npy_aheapsort(char *vec, npy_intp *ind, npy_intp cnt, PyArrayObject *arr);
-int npy_amergesort(char *vec, npy_intp *ind, npy_intp cnt, PyArrayObject *arr);
+int npy_quicksort(void *vec, npy_intp cnt, void *arr);
+int npy_heapsort(void *vec, npy_intp cnt, void *arr);
+int npy_mergesort(void *vec, npy_intp cnt, void *arr);
+int npy_aquicksort(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
+int npy_aheapsort(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
+int npy_amergesort(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
#endif
diff --git a/numpy/core/tests/test_indexing.py b/numpy/core/tests/test_indexing.py
index e55c212b7..d412c44fb 100644
--- a/numpy/core/tests/test_indexing.py
+++ b/numpy/core/tests/test_indexing.py
@@ -409,6 +409,10 @@ class TestIndexing(TestCase):
arr = np.arange(10)
assert_array_equal(arr[SequenceLike()], arr[SequenceLike(),])
+ # also test that field indexing does not segfault
+ # for a similar reason, by indexing a structured array
+ arr = np.zeros((1,), dtype=[('f1', 'i8'), ('f2', 'i8')])
+ assert_array_equal(arr[SequenceLike()], arr[SequenceLike(),])
class TestFieldIndexing(TestCase):
def test_scalar_return_type(self):
diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py
index e6911d0e3..ac645f013 100644
--- a/numpy/core/tests/test_multiarray.py
+++ b/numpy/core/tests/test_multiarray.py
@@ -3484,7 +3484,7 @@ class TestRecord(TestCase):
assert_raises(ValueError, dt.__getitem__, asbytes('a'))
x = np.array([(1,), (2,), (3,)], dtype=dt)
- assert_raises(ValueError, x.__getitem__, asbytes('a'))
+ assert_raises(IndexError, x.__getitem__, asbytes('a'))
y = x[0]
assert_raises(IndexError, y.__getitem__, asbytes('a'))
@@ -3517,8 +3517,8 @@ class TestRecord(TestCase):
if is_py3:
funcs = (str,)
# byte string indexing fails gracefully
- assert_raises(ValueError, a.__setitem__, asbytes('f1'), 1)
- assert_raises(ValueError, a.__getitem__, asbytes('f1'))
+ assert_raises(IndexError, a.__setitem__, asbytes('f1'), 1)
+ assert_raises(IndexError, a.__getitem__, asbytes('f1'))
assert_raises(IndexError, a['f1'].__setitem__, asbytes('sf1'), 1)
assert_raises(IndexError, a['f1'].__getitem__, asbytes('sf1'))
else:
@@ -3564,7 +3564,7 @@ class TestRecord(TestCase):
def test_field_names_deprecation(self):
- def collect_warning_types(f, *args, **kwargs):
+ def collect_warnings(f, *args, **kwargs):
with warnings.catch_warnings(record=True) as log:
warnings.simplefilter("always")
f(*args, **kwargs)
@@ -3585,20 +3585,19 @@ class TestRecord(TestCase):
# All the different functions raise a warning, but not an error, and
# 'a' is not modified:
- assert_equal(collect_warning_types(a[['f1', 'f2']].__setitem__, 0, (10, 20)),
+ assert_equal(collect_warnings(a[['f1', 'f2']].__setitem__, 0, (10, 20)),
[FutureWarning])
assert_equal(a, b)
# Views also warn
subset = a[['f1', 'f2']]
subset_view = subset.view()
- assert_equal(collect_warning_types(subset_view['f1'].__setitem__, 0, 10),
+ assert_equal(collect_warnings(subset_view['f1'].__setitem__, 0, 10),
[FutureWarning])
# But the write goes through:
assert_equal(subset['f1'][0], 10)
- # Only one warning per multiple field indexing, though (even if there are
- # multiple views involved):
- assert_equal(collect_warning_types(subset['f1'].__setitem__, 0, 10),
- [])
+ # Only one warning per multiple field indexing, though (even if there
+ # are multiple views involved):
+ assert_equal(collect_warnings(subset['f1'].__setitem__, 0, 10), [])
def test_record_hash(self):
a = np.array([(1, 2), (1, 2)], dtype='i1,i2')
@@ -3616,11 +3615,18 @@ class TestRecord(TestCase):
a = np.array([(1, 2), (1, 2)], dtype='i1,i2')
self.assertRaises(TypeError, hash, a[0])
+ def test_empty_structure_creation(self):
+ # make sure these do not raise errors (gh-5631)
+ array([()], dtype={'names': [], 'formats': [],
+ 'offsets': [], 'itemsize': 12})
+ array([(), (), (), (), ()], dtype={'names': [], 'formats': [],
+ 'offsets': [], 'itemsize': 12})
+
class TestView(TestCase):
def test_basic(self):
x = np.array([(1, 2, 3, 4), (5, 6, 7, 8)],
- dtype=[('r', np.int8), ('g', np.int8),
- ('b', np.int8), ('a', np.int8)])
+ dtype=[('r', np.int8), ('g', np.int8),
+ ('b', np.int8), ('a', np.int8)])
# We must be specific about the endianness here:
y = x.view(dtype='<i4')
# ... and again without the keyword.
@@ -5731,5 +5737,47 @@ class TestArrayPriority(TestCase):
assert_(isinstance(f(b, a), self.Other), msg)
+class TestBytestringArrayNonzero(TestCase):
+
+ def test_empty_bstring_array_is_falsey(self):
+ self.assertFalse(np.array([''], dtype=np.str))
+
+ def test_whitespace_bstring_array_is_falsey(self):
+ a = np.array(['spam'], dtype=np.str)
+ a[0] = ' \0\0'
+ self.assertFalse(a)
+
+ def test_all_null_bstring_array_is_falsey(self):
+ a = np.array(['spam'], dtype=np.str)
+ a[0] = '\0\0\0\0'
+ self.assertFalse(a)
+
+ def test_null_inside_bstring_array_is_truthy(self):
+ a = np.array(['spam'], dtype=np.str)
+ a[0] = ' \0 \0'
+ self.assertTrue(a)
+
+
+class TestUnicodeArrayNonzero(TestCase):
+
+ def test_empty_ustring_array_is_falsey(self):
+ self.assertFalse(np.array([''], dtype=np.unicode))
+
+ def test_whitespace_ustring_array_is_falsey(self):
+ a = np.array(['eggs'], dtype=np.unicode)
+ a[0] = ' \0\0'
+ self.assertFalse(a)
+
+ def test_all_null_ustring_array_is_falsey(self):
+ a = np.array(['eggs'], dtype=np.unicode)
+ a[0] = '\0\0\0\0'
+ self.assertFalse(a)
+
+ def test_null_inside_ustring_array_is_truthy(self):
+ a = np.array(['eggs'], dtype=np.unicode)
+ a[0] = ' \0 \0'
+ self.assertTrue(a)
+
+
if __name__ == "__main__":
run_module_suite()
diff --git a/numpy/core/tests/test_records.py b/numpy/core/tests/test_records.py
index 52cfd1868..4924d4471 100644
--- a/numpy/core/tests/test_records.py
+++ b/numpy/core/tests/test_records.py
@@ -235,6 +235,11 @@ class TestRecord(TestCase):
rec[0].x = 1
assert_equal(rec[0].x, np.ones(5))
+ def test_missing_field(self):
+ # https://github.com/numpy/numpy/issues/4806
+ arr = np.zeros((3,), dtype=[('x', int), ('y', int)])
+ assert_raises(ValueError, lambda: arr[['nofield']])
+
def test_find_duplicate():
l1 = [1, 2, 3, 4, 5, 6]
assert_(np.rec.find_duplicate(l1) == [])
diff --git a/numpy/ma/core.py b/numpy/ma/core.py
index 877d07e02..703580d27 100644
--- a/numpy/ma/core.py
+++ b/numpy/ma/core.py
@@ -880,14 +880,10 @@ class _MaskedUnaryOperation:
except TypeError:
pass
# Transform to
- if isinstance(a, MaskedArray):
- subtype = type(a)
- else:
- subtype = MaskedArray
- result = result.view(subtype)
- result._mask = m
- result._update_from(a)
- return result
+ masked_result = result.view(get_masked_subclass(a))
+ masked_result._mask = m
+ masked_result._update_from(result)
+ return masked_result
#
def __str__ (self):
return "Masked version of %s. [Invalid values are masked]" % str(self.f)
@@ -928,8 +924,12 @@ class _MaskedBinaryOperation:
def __call__ (self, a, b, *args, **kwargs):
"Execute the call behavior."
# Get the data, as ndarray
- (da, db) = (getdata(a, subok=False), getdata(b, subok=False))
- # Get the mask
+ (da, db) = (getdata(a), getdata(b))
+ # Get the result
+ with np.errstate():
+ np.seterr(divide='ignore', invalid='ignore')
+ result = self.f(da, db, *args, **kwargs)
+ # Get the mask for the result
(ma, mb) = (getmask(a), getmask(b))
if ma is nomask:
if mb is nomask:
@@ -940,12 +940,6 @@ class _MaskedBinaryOperation:
m = umath.logical_or(ma, getmaskarray(b))
else:
m = umath.logical_or(ma, mb)
- # Get the result
- with np.errstate(divide='ignore', invalid='ignore'):
- result = self.f(da, db, *args, **kwargs)
- # check it worked
- if result is NotImplemented:
- return NotImplemented
# Case 1. : scalar
if not result.ndim:
if m:
@@ -953,28 +947,26 @@ class _MaskedBinaryOperation:
return result
# Case 2. : array
# Revert result to da where masked
- if m is not nomask:
- np.copyto(result, da, casting='unsafe', where=m)
+ if m is not nomask and m.any():
+ # any errors, just abort; impossible to guarantee masked values
+ try:
+ np.copyto(result, 0, casting='unsafe', where=m)
+ # avoid using "*" since this may be overlaid
+ masked_da = umath.multiply(m, da)
+ # only add back if it can be cast safely
+ if np.can_cast(masked_da.dtype, result.dtype, casting='safe'):
+ result += masked_da
+ except:
+ pass
# Transforms to a (subclass of) MaskedArray
- result = result.view(get_masked_subclass(a, b))
- result._mask = m
- # Update the optional info from the inputs
- if isinstance(b, MaskedArray):
- if isinstance(a, MaskedArray):
- result._update_from(a)
- else:
- result._update_from(b)
- elif isinstance(a, MaskedArray):
- result._update_from(a)
- return result
-
+ masked_result = result.view(get_masked_subclass(a, b))
+ masked_result._mask = m
+ masked_result._update_from(result)
+ return masked_result
def reduce(self, target, axis=0, dtype=None):
"""Reduce `target` along the given `axis`."""
- if isinstance(target, MaskedArray):
- tclass = type(target)
- else:
- tclass = MaskedArray
+ tclass = get_masked_subclass(target)
m = getmask(target)
t = filled(target, self.filly)
if t.shape == ():
@@ -982,24 +974,30 @@ class _MaskedBinaryOperation:
if m is not nomask:
m = make_mask(m, copy=1)
m.shape = (1,)
+
if m is nomask:
- return self.f.reduce(t, axis).view(tclass)
- t = t.view(tclass)
- t._mask = m
- tr = self.f.reduce(getdata(t), axis, dtype=dtype or t.dtype)
- mr = umath.logical_and.reduce(m, axis)
- tr = tr.view(tclass)
- if mr.ndim > 0:
- tr._mask = mr
- return tr
- elif mr:
- return masked
- return tr
+ tr = self.f.reduce(t, axis)
+ mr = nomask
+ else:
+ tr = self.f.reduce(t, axis, dtype=dtype or t.dtype)
+ mr = umath.logical_and.reduce(m, axis)
- def outer (self, a, b):
+ if not tr.shape:
+ if mr:
+ return masked
+ else:
+ return tr
+ masked_tr = tr.view(tclass)
+ masked_tr._mask = mr
+ masked_tr._update_from(tr)
+ return masked_tr
+
+ def outer(self, a, b):
"""Return the function applied to the outer product of a and b.
"""
+ (da, db) = (getdata(a), getdata(b))
+ d = self.f.outer(da, db)
ma = getmask(a)
mb = getmask(b)
if ma is nomask and mb is nomask:
@@ -1010,31 +1008,28 @@ class _MaskedBinaryOperation:
m = umath.logical_or.outer(ma, mb)
if (not m.ndim) and m:
return masked
- (da, db) = (getdata(a), getdata(b))
- d = self.f.outer(da, db)
- # check it worked
- if d is NotImplemented:
- return NotImplemented
if m is not nomask:
np.copyto(d, da, where=m)
- if d.shape:
- d = d.view(get_masked_subclass(a, b))
- d._mask = m
- return d
+ if not d.shape:
+ return d
+ masked_d = d.view(get_masked_subclass(a, b))
+ masked_d._mask = m
+ masked_d._update_from(d)
+ return masked_d
- def accumulate (self, target, axis=0):
+ def accumulate(self, target, axis=0):
"""Accumulate `target` along `axis` after filling with y fill
value.
"""
- if isinstance(target, MaskedArray):
- tclass = type(target)
- else:
- tclass = MaskedArray
+ tclass = get_masked_subclass(target)
t = filled(target, self.filly)
- return self.f.accumulate(t, axis).view(tclass)
+ result = self.f.accumulate(t, axis)
+ masked_result = result.view(tclass)
+ masked_result._update_from(result)
+ return masked_result
- def __str__ (self):
+ def __str__(self):
return "Masked version of " + str(self.f)
@@ -1074,19 +1069,15 @@ class _DomainedBinaryOperation:
def __call__(self, a, b, *args, **kwargs):
"Execute the call behavior."
- # Get the data and the mask
- (da, db) = (getdata(a, subok=False), getdata(b, subok=False))
- (ma, mb) = (getmask(a), getmask(b))
+ # Get the data
+ (da, db) = (getdata(a), getdata(b))
# Get the result
with np.errstate(divide='ignore', invalid='ignore'):
result = self.f(da, db, *args, **kwargs)
- # check it worked
- if result is NotImplemented:
- return NotImplemented
- # Get the mask as a combination of ma, mb and invalid
+ # Get the mask as a combination of the source masks and invalid
m = ~umath.isfinite(result)
- m |= ma
- m |= mb
+ m |= getmask(a)
+ m |= getmask(b)
# Apply the domain
domain = ufunc_domain.get(self.f, None)
if domain is not None:
@@ -1097,18 +1088,23 @@ class _DomainedBinaryOperation:
return masked
else:
return result
- # When the mask is True, put back da
- np.copyto(result, da, casting='unsafe', where=m)
- result = result.view(get_masked_subclass(a, b))
- result._mask = m
- if isinstance(b, MaskedArray):
- if isinstance(a, MaskedArray):
- result._update_from(a)
- else:
- result._update_from(b)
- elif isinstance(a, MaskedArray):
- result._update_from(a)
- return result
+ # When the mask is True, put back da if possible
+ # any errors, just abort; impossible to guarantee masked values
+ try:
+ np.copyto(result, 0, casting='unsafe', where=m)
+ # avoid using "*" since this may be overlaid
+ masked_da = umath.multiply(m, da)
+ # only add back if it can be cast safely
+ if np.can_cast(masked_da.dtype, result.dtype, casting='safe'):
+ result += masked_da
+ except:
+ pass
+
+ # Transforms to a (subclass of) MaskedArray
+ masked_result = result.view(get_masked_subclass(a, b))
+ masked_result._mask = m
+ masked_result._update_from(result)
+ return masked_result
def __str__ (self):
return "Masked version of " + str(self.f)
@@ -1361,7 +1357,7 @@ def getmaskarray(arr):
"""
mask = getmask(arr)
if mask is nomask:
- mask = make_mask_none(np.shape(arr), getdata(arr).dtype)
+ mask = make_mask_none(np.shape(arr), getattr(arr, 'dtype', None))
return mask
def is_mask(m):
@@ -3050,6 +3046,7 @@ class MaskedArray(ndarray):
# mask of being reshaped if it hasn't been set up properly yet...
# So it's easier to stick to the current version
_mask = self._mask
+ # Did we extract a single item?
if not getattr(dout, 'ndim', False):
# A record ................
if isinstance(dout, np.void):
@@ -3061,6 +3058,11 @@ class MaskedArray(ndarray):
# Just a scalar............
elif _mask is not nomask and _mask[indx]:
return masked
+ elif self.dtype.type is np.object_ and self.dtype is not dout.dtype:
+ # self contains an object array of arrays (yes, that happens).
+ # If masked, turn into a MaskedArray, with everything masked.
+ if _mask is not nomask and _mask[indx]:
+ return MaskedArray(dout, mask=True)
else:
# Force dout to MA ........
dout = dout.view(type(self))
@@ -3179,8 +3181,8 @@ class MaskedArray(ndarray):
"""Set the mask.
"""
- idtype = ndarray.__getattribute__(self, 'dtype')
- current_mask = ndarray.__getattribute__(self, '_mask')
+ idtype = self.dtype
+ current_mask = self._mask
if mask is masked:
mask = True
# Make sure the mask is set
@@ -3258,7 +3260,7 @@ class MaskedArray(ndarray):
A record is masked when all the fields are masked.
"""
- _mask = ndarray.__getattribute__(self, '_mask').view(ndarray)
+ _mask = self._mask.view(ndarray)
if _mask.dtype.names is None:
return _mask
return np.all(flatten_structured_array(_mask), axis= -1)
@@ -3695,7 +3697,7 @@ class MaskedArray(ndarray):
return masked
omask = getattr(other, '_mask', nomask)
if omask is nomask:
- check = ndarray.__eq__(self.filled(0), other)
+ check = self.filled(0).__eq__(other)
try:
check = check.view(type(self))
check._mask = self._mask
@@ -3704,7 +3706,7 @@ class MaskedArray(ndarray):
return check
else:
odata = filled(other, 0)
- check = ndarray.__eq__(self.filled(0), odata).view(type(self))
+ check = self.filled(0).__eq__(odata).view(type(self))
if self._mask is nomask:
check._mask = omask
else:
@@ -3728,7 +3730,7 @@ class MaskedArray(ndarray):
return masked
omask = getattr(other, '_mask', nomask)
if omask is nomask:
- check = ndarray.__ne__(self.filled(0), other)
+ check = self.filled(0).__ne__(other)
try:
check = check.view(type(self))
check._mask = self._mask
@@ -3737,7 +3739,7 @@ class MaskedArray(ndarray):
return check
else:
odata = filled(other, 0)
- check = ndarray.__ne__(self.filled(0), odata).view(type(self))
+ check = self.filled(0).__ne__(odata).view(type(self))
if self._mask is nomask:
check._mask = omask
else:
@@ -3756,34 +3758,38 @@ class MaskedArray(ndarray):
return check
#
def __add__(self, other):
- "Add other to self, and return a new masked array."
+ "Add self to other, and return a new masked array."
if self._delegate_binop(other):
return NotImplemented
return add(self, other)
#
def __radd__(self, other):
"Add other to self, and return a new masked array."
- return add(self, other)
+ # In analogy with __rsub__ and __rdiv__, use original order:
+ # we get here from `other + self`.
+ return add(other, self)
#
def __sub__(self, other):
- "Subtract other to self, and return a new masked array."
+ "Subtract other from self, and return a new masked array."
if self._delegate_binop(other):
return NotImplemented
return subtract(self, other)
#
def __rsub__(self, other):
- "Subtract other to self, and return a new masked array."
+ "Subtract self from other, and return a new masked array."
return subtract(other, self)
#
def __mul__(self, other):
- "Multiply other by self, and return a new masked array."
+ "Multiply self by other, and return a new masked array."
if self._delegate_binop(other):
return NotImplemented
return multiply(self, other)
#
def __rmul__(self, other):
"Multiply other by self, and return a new masked array."
- return multiply(self, other)
+ # In analogy with __rsub__ and __rdiv__, use original order:
+ # we get here from `other * self`.
+ return multiply(other, self)
#
def __div__(self, other):
"Divide other into self, and return a new masked array."
@@ -3798,7 +3804,7 @@ class MaskedArray(ndarray):
return true_divide(self, other)
#
def __rtruediv__(self, other):
- "Divide other into self, and return a new masked array."
+ "Divide self into other, and return a new masked array."
return true_divide(other, self)
#
def __floordiv__(self, other):
@@ -3808,7 +3814,7 @@ class MaskedArray(ndarray):
return floor_divide(self, other)
#
def __rfloordiv__(self, other):
- "Divide other into self, and return a new masked array."
+ "Divide self into other, and return a new masked array."
return floor_divide(other, self)
#
def __pow__(self, other):
@@ -3818,7 +3824,7 @@ class MaskedArray(ndarray):
return power(self, other)
#
def __rpow__(self, other):
- "Raise self to the power other, masking the potential NaNs/Infs"
+ "Raise other to the power self, masking the potential NaNs/Infs"
return power(other, self)
#............................................
def __iadd__(self, other):
@@ -3831,10 +3837,8 @@ class MaskedArray(ndarray):
else:
if m is not nomask:
self._mask += m
- ndarray.__iadd__(
- self._data,
- np.where(self._mask, self.dtype.type(0), getdata(other))
- )
+ self._data.__iadd__(np.where(self._mask, self.dtype.type(0),
+ getdata(other)))
return self
#....
def __isub__(self, other):
@@ -3846,10 +3850,8 @@ class MaskedArray(ndarray):
self._mask += m
elif m is not nomask:
self._mask += m
- ndarray.__isub__(
- self._data,
- np.where(self._mask, self.dtype.type(0), getdata(other))
- )
+ self._data.__isub__(np.where(self._mask, self.dtype.type(0),
+ getdata(other)))
return self
#....
def __imul__(self, other):
@@ -3861,10 +3863,8 @@ class MaskedArray(ndarray):
self._mask += m
elif m is not nomask:
self._mask += m
- ndarray.__imul__(
- self._data,
- np.where(self._mask, self.dtype.type(1), getdata(other))
- )
+ self._data.__imul__(np.where(self._mask, self.dtype.type(1),
+ getdata(other)))
return self
#....
def __idiv__(self, other):
@@ -3879,10 +3879,8 @@ class MaskedArray(ndarray):
other_data = np.where(dom_mask, fval, other_data)
# self._mask = mask_or(self._mask, new_mask)
self._mask |= new_mask
- ndarray.__idiv__(
- self._data,
- np.where(self._mask, self.dtype.type(1), other_data)
- )
+ self._data.__idiv__(np.where(self._mask, self.dtype.type(1),
+ other_data))
return self
#....
def __ifloordiv__(self, other):
@@ -3897,10 +3895,8 @@ class MaskedArray(ndarray):
other_data = np.where(dom_mask, fval, other_data)
# self._mask = mask_or(self._mask, new_mask)
self._mask |= new_mask
- ndarray.__ifloordiv__(
- self._data,
- np.where(self._mask, self.dtype.type(1), other_data)
- )
+ self._data.__ifloordiv__(np.where(self._mask, self.dtype.type(1),
+ other_data))
return self
#....
def __itruediv__(self, other):
@@ -3915,10 +3911,8 @@ class MaskedArray(ndarray):
other_data = np.where(dom_mask, fval, other_data)
# self._mask = mask_or(self._mask, new_mask)
self._mask |= new_mask
- ndarray.__itruediv__(
- self._data,
- np.where(self._mask, self.dtype.type(1), other_data)
- )
+ self._data.__itruediv__(np.where(self._mask, self.dtype.type(1),
+ other_data))
return self
#...
def __ipow__(self, other):
@@ -3926,10 +3920,8 @@ class MaskedArray(ndarray):
other_data = getdata(other)
other_mask = getmask(other)
with np.errstate(divide='ignore', invalid='ignore'):
- ndarray.__ipow__(
- self._data,
- np.where(self._mask, self.dtype.type(1), other_data)
- )
+ self._data.__ipow__(np.where(self._mask, self.dtype.type(1),
+ other_data))
invalid = np.logical_not(np.isfinite(self._data))
if invalid.any():
if self._mask is not nomask:
@@ -4614,7 +4606,7 @@ class MaskedArray(ndarray):
<type 'numpy.int64'>
"""
- _mask = ndarray.__getattribute__(self, '_mask')
+ _mask = self._mask
newmask = _check_mask_axis(_mask, axis)
# No explicit output
if out is None:
@@ -4742,7 +4734,7 @@ class MaskedArray(ndarray):
array([ 2., 12.])
"""
- _mask = ndarray.__getattribute__(self, '_mask')
+ _mask = self._mask
newmask = _check_mask_axis(_mask, axis)
# No explicit output
if out is None:
@@ -5258,7 +5250,7 @@ class MaskedArray(ndarray):
Returns the minimum filling value for a given datatype.
"""
- _mask = ndarray.__getattribute__(self, '_mask')
+ _mask = self._mask
newmask = _check_mask_axis(_mask, axis)
if fill_value is None:
fill_value = minimum_fill_value(self)
@@ -5357,7 +5349,7 @@ class MaskedArray(ndarray):
Returns the maximum filling value for a given datatype.
"""
- _mask = ndarray.__getattribute__(self, '_mask')
+ _mask = self._mask
newmask = _check_mask_axis(_mask, axis)
if fill_value is None:
fill_value = maximum_fill_value(self)
@@ -5682,7 +5674,7 @@ class MaskedArray(ndarray):
"""
(_, shp, typ, isf, raw, msk, flv) = state
- ndarray.__setstate__(self, (shp, typ, isf, raw))
+ super(MaskedArray, self).__setstate__((shp, typ, isf, raw))
self._mask.__setstate__((shp, make_mask_descr(typ), isf, msk))
self.fill_value = flv
#
diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py
index 909c27c90..2bf782724 100644
--- a/numpy/ma/tests/test_core.py
+++ b/numpy/ma/tests/test_core.py
@@ -685,6 +685,18 @@ class TestMaskedArray(TestCase):
finally:
masked_print_option.set_display(ini_display)
+ def test_object_with_array(self):
+ mx1 = masked_array([1.], mask=[True])
+ mx2 = masked_array([1., 2.])
+ mx = masked_array([mx1, mx2], mask=[False, True])
+ assert mx[0] is mx1
+ assert mx[1] is not mx2
+ assert np.all(mx[1].data == mx2.data)
+ assert np.all(mx[1].mask)
+ # check that we return a view.
+ mx[1].data[0] = 0.
+ assert mx2[0] == 0.
+
#------------------------------------------------------------------------------
class TestMaskedArrayArithmetic(TestCase):
@@ -1754,6 +1766,29 @@ class TestUfuncs(TestCase):
assert_(me * a == "My mul")
assert_(a * me == "My rmul")
+ # and that __array_priority__ is respected
+ class MyClass2(object):
+ __array_priority__ = 100
+
+ def __mul__(self, other):
+ return "Me2mul"
+
+ def __rmul__(self, other):
+ return "Me2rmul"
+
+ def __rdiv__(self, other):
+ return "Me2rdiv"
+
+ __rtruediv__ = __rdiv__
+
+ me_too = MyClass2()
+ assert_(a.__mul__(me_too) is NotImplemented)
+ assert_(all(multiply.outer(a, me_too) == "Me2rmul"))
+ assert_(a.__truediv__(me_too) is NotImplemented)
+ assert_(me_too * a == "Me2mul")
+ assert_(a * me_too == "Me2rmul")
+ assert_(a / me_too == "Me2rdiv")
+
#------------------------------------------------------------------------------
class TestMaskedArrayInPlaceArithmetics(TestCase):
diff --git a/numpy/ma/tests/test_subclassing.py b/numpy/ma/tests/test_subclassing.py
index 07fc8fdd6..2e98348e6 100644
--- a/numpy/ma/tests/test_subclassing.py
+++ b/numpy/ma/tests/test_subclassing.py
@@ -24,18 +24,27 @@ class SubArray(np.ndarray):
# in the dictionary `info`.
def __new__(cls,arr,info={}):
x = np.asanyarray(arr).view(cls)
- x.info = info
+ x.info = info.copy()
return x
def __array_finalize__(self, obj):
- self.info = getattr(obj, 'info', {})
+ if callable(getattr(super(SubArray, self),
+ '__array_finalize__', None)):
+ super(SubArray, self).__array_finalize__(obj)
+ self.info = getattr(obj, 'info', {}).copy()
return
def __add__(self, other):
- result = np.ndarray.__add__(self, other)
- result.info.update({'added':result.info.pop('added', 0)+1})
+ result = super(SubArray, self).__add__(other)
+ result.info['added'] = result.info.get('added', 0) + 1
return result
+ def __iadd__(self, other):
+ result = super(SubArray, self).__iadd__(other)
+ result.info['iadded'] = result.info.get('iadded', 0) + 1
+ return result
+
+
subarray = SubArray
@@ -47,11 +56,6 @@ class MSubArray(SubArray, MaskedArray):
_data.info = subarr.info
return _data
- def __array_finalize__(self, obj):
- MaskedArray.__array_finalize__(self, obj)
- SubArray.__array_finalize__(self, obj)
- return
-
def _get_series(self):
_view = self.view(MaskedArray)
_view._sharedmask = False
@@ -82,8 +86,11 @@ class MMatrix(MaskedArray, np.matrix,):
mmatrix = MMatrix
-# also a subclass that overrides __str__, __repr__ and __setitem__, disallowing
+# Also a subclass that overrides __str__, __repr__ and __setitem__, disallowing
# setting to non-class values (and thus np.ma.core.masked_print_option)
+# and overrides __array_wrap__, updating the info dict, to check that this
+# doesn't get destroyed by MaskedArray._update_from. But this one also needs
+# its own iterator...
class CSAIterator(object):
"""
Flat iterator object that uses its own setter/getter
@@ -150,6 +157,13 @@ class ComplicatedSubArray(SubArray):
y = self.ravel()
y[:] = value
+ def __array_wrap__(self, obj, context=None):
+ obj = super(ComplicatedSubArray, self).__array_wrap__(obj, context)
+ if context is not None and context[0] is np.multiply:
+ obj.info['multiplied'] = obj.info.get('multiplied', 0) + 1
+
+ return obj
+
class TestSubclassing(TestCase):
# Test suite for masked subclasses of ndarray.
@@ -218,6 +232,12 @@ class TestSubclassing(TestCase):
self.assertTrue(isinstance(z, MSubArray))
self.assertTrue(isinstance(z._data, SubArray))
self.assertTrue(z._data.info['added'] > 0)
+ # Test that inplace methods from data get used (gh-4617)
+ ym += 1
+ self.assertTrue(isinstance(ym, MaskedArray))
+ self.assertTrue(isinstance(ym, MSubArray))
+ self.assertTrue(isinstance(ym._data, SubArray))
+ self.assertTrue(ym._data.info['iadded'] > 0)
#
ym._set_mask([1, 0, 0, 0, 1])
assert_equal(ym._mask, [1, 0, 0, 0, 1])