summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/multiarray/ctors.c66
-rw-r--r--numpy/lib/stride_tricks.py6
-rw-r--r--numpy/lib/tests/test_stride_tricks.py23
3 files changed, 88 insertions, 7 deletions
diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c
index 010420826..e88e17028 100644
--- a/numpy/core/src/multiarray/ctors.c
+++ b/numpy/core/src/multiarray/ctors.c
@@ -2069,6 +2069,51 @@ PyArray_FromStructInterface(PyObject *input)
return NULL;
}
+/*
+ * Checks if the object in descr is the default 'descr' member for the
+ * __array_interface__ dictionary with 'typestr' member typestr.
+ */
+NPY_NO_EXPORT int
+_is_default_descr(PyObject *descr, PyObject *typestr) {
+ PyObject *tuple, *name, *typestr2;
+#if defined(NPY_PY3K)
+ PyObject *tmp = NULL;
+#endif
+ int ret = 0;
+
+ if (!PyList_Check(descr) || PyList_GET_SIZE(descr) != 1) {
+ return 0;
+ }
+ tuple = PyList_GET_ITEM(descr, 0);
+ if (!(PyTuple_Check(tuple) && PyTuple_GET_SIZE(tuple) == 2)) {
+ return 0;
+ }
+ name = PyTuple_GET_ITEM(tuple, 0);
+ if (!(PyUString_Check(name) && PyUString_GET_SIZE(name) == 0)) {
+ return 0;
+ }
+ typestr2 = PyTuple_GET_ITEM(tuple, 1);
+#if defined(NPY_PY3K)
+ /* Allow unicode type strings */
+ if (PyUnicode_Check(typestr2)) {
+ tmp = PyUnicode_AsASCIIString(typestr2);
+ if (tmp == NULL) {
+ return 0;
+ }
+ typestr2 = tmp;
+ }
+#endif
+ if (PyBytes_Check(typestr2) &&
+ PyObject_RichCompareBool(typestr, typestr2, Py_EQ)) {
+ ret = 1;
+ }
+#if defined(NPY_PY3K)
+ Py_XDECREF(tmp);
+#endif
+
+ return ret;
+}
+
#define PyIntOrLong_Check(obj) (PyInt_Check(obj) || PyLong_Check(obj))
/*NUMPY_API*/
@@ -2087,11 +2132,6 @@ PyArray_FromInterface(PyObject *origin)
npy_intp dims[NPY_MAXDIMS], strides[NPY_MAXDIMS];
int dataflags = NPY_ARRAY_BEHAVED;
- /* Get the typestring -- ignore array_descr */
- /* Get the shape */
- /* Get the memory from __array_data__ and __array_offset__ */
- /* Get the strides */
-
iface = PyArray_GetAttrString_SuppressException(origin,
"__array_interface__");
if (iface == NULL) {
@@ -2135,6 +2175,22 @@ PyArray_FromInterface(PyObject *origin)
goto fail;
}
+ /*
+ * If the dtype is NPY_VOID, see if there is extra information in
+ * the 'descr' attribute.
+ */
+ if (dtype->type_num == NPY_VOID) {
+ PyObject *descr = PyDict_GetItemString(iface, "descr");
+ PyArray_Descr *new_dtype = NULL;
+
+ if (descr != NULL && !_is_default_descr(descr, attr) &&
+ PyArray_DescrConverter2(descr, &new_dtype) == NPY_SUCCEED &&
+ new_dtype != NULL) {
+ Py_DECREF(dtype);
+ dtype = new_dtype;
+ }
+ }
+
/* Get shape tuple from interface specification */
attr = PyDict_GetItemString(iface, "shape");
if (attr == NULL) {
diff --git a/numpy/lib/stride_tricks.py b/numpy/lib/stride_tricks.py
index a5f247abf..e7649cb60 100644
--- a/numpy/lib/stride_tricks.py
+++ b/numpy/lib/stride_tricks.py
@@ -46,9 +46,11 @@ def as_strided(x, shape=None, strides=None, subok=False):
if strides is not None:
interface['strides'] = tuple(strides)
array = np.asarray(DummyArray(interface, base=x))
- # Make sure dtype is correct in case of custom dtype
- if array.dtype.kind == 'V':
+
+ if array.dtype.fields is None and x.dtype.fields is not None:
+ # This should only happen if x.dtype is [('', 'Vx')]
array.dtype = x.dtype
+
return _maybe_view_as_subclass(x, array)
diff --git a/numpy/lib/tests/test_stride_tricks.py b/numpy/lib/tests/test_stride_tricks.py
index ef483921c..e079e0bf4 100644
--- a/numpy/lib/tests/test_stride_tricks.py
+++ b/numpy/lib/tests/test_stride_tricks.py
@@ -290,6 +290,29 @@ def test_as_strided():
expected = np.array([[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]])
assert_array_equal(a_view, expected)
+ # Regression test for gh-5081
+ dt = np.dtype([('num', 'i4'), ('obj', 'O')])
+ a = np.empty((4,), dtype=dt)
+ a['num'] = np.arange(1, 5)
+ a_view = as_strided(a, shape=(3, 4), strides=(0, a.itemsize))
+ expected_num = [[1, 2, 3, 4]] * 3
+ expected_obj = [[None]*4]*3
+ assert_equal(a_view.dtype, dt)
+ assert_array_equal(expected_num, a_view['num'])
+ assert_array_equal(expected_obj, a_view['obj'])
+
+ # Make sure that void types without fields are kept unchanged
+ a = np.empty((4,), dtype='V4')
+ a_view = as_strided(a, shape=(3, 4), strides=(0, a.itemsize))
+ assert_equal(a.dtype, a_view.dtype)
+
+ # Make sure that the only type that could fail is properly handled
+ dt = np.dtype({'names': [''], 'formats': ['V4']})
+ a = np.empty((4,), dtype=dt)
+ a_view = as_strided(a, shape=(3, 4), strides=(0, a.itemsize))
+ assert_equal(a.dtype, a_view.dtype)
+
+
class VerySimpleSubClass(np.ndarray):
def __new__(cls, *args, **kwargs):