summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--numpy/core/src/multiarray/common.c122
-rw-r--r--numpy/core/src/multiarray/common.h3
-rw-r--r--numpy/core/src/multiarray/ctors.c62
-rw-r--r--numpy/core/src/multiarray/multiarraymodule.c3
-rw-r--r--numpy/core/tests/test_api.py150
5 files changed, 275 insertions, 65 deletions
diff --git a/numpy/core/src/multiarray/common.c b/numpy/core/src/multiarray/common.c
index 01bf9cd74..4787c6482 100644
--- a/numpy/core/src/multiarray/common.c
+++ b/numpy/core/src/multiarray/common.c
@@ -27,6 +27,60 @@
* be allowed under the NPY_SAME_KIND_CASTING rules, and if not we issue a
* warning (that people's code will be broken in a future release.)
*/
+
+/*
+ * PyArray_GetAttrString_SuppressException:
+ *
+ * Stripped down version of PyObject_GetAttrString,
+ * avoids lookups for None, tuple, and List objects,
+ * and doesn't create a PyErr since this code ignores it.
+ *
+ * This can be much faster then PyObject_GetAttrString where
+ * exceptions are not used by caller.
+ *
+ * 'obj' is the object to search for attribute.
+ *
+ * 'name' is the attribute to search for.
+ *
+ * Returns attribute value on success, 0 on failure.
+ */
+PyObject *
+PyArray_GetAttrString_SuppressException(PyObject *obj, char *name)
+{
+ PyTypeObject *tp = Py_TYPE(obj);
+ PyObject *res = (PyObject *)NULL;
+ if (/* Is not trivial type */
+ obj != Py_None &&
+ !PyList_CheckExact(obj) &&
+ !PyTuple_CheckExact(obj)) {
+ /* Attribute referenced by (char *)name */
+ if (tp->tp_getattr != NULL) {
+ res = (*tp->tp_getattr)(obj, name);
+ if (res == NULL) {
+ PyErr_Clear();
+ }
+ }
+ /* Attribute referenced by (PyObject *)name */
+ else if (tp->tp_getattro != NULL) {
+#if defined(NPY_PY3K)
+ PyObject *w = PyUnicode_InternFromString(name);
+#else
+ PyObject *w = PyString_InternFromString(name);
+#endif
+ if (w == NULL)
+ return (PyObject *)NULL;
+ Py_DECREF(w);
+ res = (*tp->tp_getattro)(obj, w);
+ if (res == NULL) {
+ PyErr_Clear();
+ }
+ }
+ }
+ return res;
+}
+
+
+
NPY_NO_EXPORT NPY_CASTING NPY_DEFAULT_ASSIGN_CASTING = NPY_INTERNAL_UNSAFE_CASTING_BUT_WARN_UNLESS_SAME_KIND;
@@ -156,8 +210,17 @@ PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims,
goto promote_types;
}
+ /* See if it's a python None */
+ if (obj == Py_None) {
+ dtype = PyArray_DescrFromType(NPY_OBJECT);
+ if (dtype == NULL) {
+ goto fail;
+ }
+ Py_INCREF(dtype);
+ goto promote_types;
+ }
/* Check if it's a NumPy scalar */
- if (PyArray_IsScalar(obj, Generic)) {
+ else if (PyArray_IsScalar(obj, Generic)) {
if (!string_type) {
dtype = PyArray_DescrFromScalar(obj);
if (dtype == NULL) {
@@ -308,32 +371,35 @@ PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims,
}
/* PEP 3118 buffer interface */
- memset(&buffer_view, 0, sizeof(Py_buffer));
- if (PyObject_GetBuffer(obj, &buffer_view, PyBUF_FORMAT|PyBUF_STRIDES) == 0 ||
- PyObject_GetBuffer(obj, &buffer_view, PyBUF_FORMAT) == 0) {
-
- PyErr_Clear();
- dtype = _descriptor_from_pep3118_format(buffer_view.format);
- PyBuffer_Release(&buffer_view);
- if (dtype) {
+ if (PyObject_CheckBuffer(obj) == 1) {
+ memset(&buffer_view, 0, sizeof(Py_buffer));
+ if (PyObject_GetBuffer(obj, &buffer_view,
+ PyBUF_FORMAT|PyBUF_STRIDES) == 0 ||
+ PyObject_GetBuffer(obj, &buffer_view, PyBUF_FORMAT) == 0) {
+
+ PyErr_Clear();
+ dtype = _descriptor_from_pep3118_format(buffer_view.format);
+ PyBuffer_Release(&buffer_view);
+ if (dtype) {
+ goto promote_types;
+ }
+ }
+ else if (PyObject_GetBuffer(obj, &buffer_view, PyBUF_STRIDES) == 0 ||
+ PyObject_GetBuffer(obj, &buffer_view, PyBUF_SIMPLE) == 0) {
+
+ PyErr_Clear();
+ dtype = PyArray_DescrNewFromType(NPY_VOID);
+ dtype->elsize = buffer_view.itemsize;
+ PyBuffer_Release(&buffer_view);
goto promote_types;
}
- }
- else if (PyObject_GetBuffer(obj, &buffer_view, PyBUF_STRIDES) == 0 ||
- PyObject_GetBuffer(obj, &buffer_view, PyBUF_SIMPLE) == 0) {
-
- PyErr_Clear();
- dtype = PyArray_DescrNewFromType(NPY_VOID);
- dtype->elsize = buffer_view.itemsize;
- PyBuffer_Release(&buffer_view);
- goto promote_types;
- }
- else {
- PyErr_Clear();
+ else {
+ PyErr_Clear();
+ }
}
/* The array interface */
- ip = PyObject_GetAttrString(obj, "__array_interface__");
+ ip = PyArray_GetAttrString_SuppressException(obj, "__array_interface__");
if (ip != NULL) {
if (PyDict_Check(ip)) {
PyObject *typestr;
@@ -364,12 +430,9 @@ PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims,
}
Py_DECREF(ip);
}
- else {
- PyErr_Clear();
- }
/* The array struct interface */
- ip = PyObject_GetAttrString(obj, "__array_struct__");
+ ip = PyArray_GetAttrString_SuppressException(obj, "__array_struct__");
if (ip != NULL) {
PyArrayInterface *inter;
char buf[40];
@@ -389,9 +452,6 @@ PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims,
}
Py_DECREF(ip);
}
- else {
- PyErr_Clear();
- }
/* The old buffer interface */
#if !defined(NPY_PY3K)
@@ -407,7 +467,9 @@ PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims,
#endif
/* The __array__ attribute */
- if (PyObject_HasAttrString(obj, "__array__")) {
+ ip = PyArray_GetAttrString_SuppressException(obj, "__array__");
+ if (ip != NULL) {
+ Py_DECREF(ip);
ip = PyObject_CallMethod(obj, "__array__", NULL);
if(ip && PyArray_Check(ip)) {
dtype = PyArray_DESCR((PyArrayObject *)ip);
diff --git a/numpy/core/src/multiarray/common.h b/numpy/core/src/multiarray/common.h
index a474cf820..68f8d246d 100644
--- a/numpy/core/src/multiarray/common.h
+++ b/numpy/core/src/multiarray/common.h
@@ -25,6 +25,9 @@ NPY_NO_EXPORT int
PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims,
PyArray_Descr **out_dtype, int string_status);
+NPY_NO_EXPORT PyObject *
+PyArray_GetAttrString_SuppressException(PyObject *v, char *name);
+
/*
* Returns NULL without setting an exception if no scalar is matched, a
* new dtype reference otherwise.
diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c
index 5c692bd02..c96258417 100644
--- a/numpy/core/src/multiarray/ctors.c
+++ b/numpy/core/src/multiarray/ctors.c
@@ -646,32 +646,35 @@ discover_dimensions(PyObject *obj, int *maxndim, npy_intp *d, int check_it,
/* obj is a PEP 3118 buffer */
#if PY_VERSION_HEX >= 0x02060000
/* PEP 3118 buffer interface */
- memset(&buffer_view, 0, sizeof(Py_buffer));
- if (PyObject_GetBuffer(obj, &buffer_view, PyBUF_STRIDES) == 0 ||
- PyObject_GetBuffer(obj, &buffer_view, PyBUF_ND) == 0) {
- int nd = buffer_view.ndim;
- if (nd < *maxndim) {
- *maxndim = nd;
+ if (PyObject_CheckBuffer(obj) == 1) {
+ memset(&buffer_view, 0, sizeof(Py_buffer));
+ if (PyObject_GetBuffer(obj, &buffer_view, PyBUF_STRIDES) == 0 ||
+ PyObject_GetBuffer(obj, &buffer_view, PyBUF_ND) == 0) {
+ int nd = buffer_view.ndim;
+ if (nd < *maxndim) {
+ *maxndim = nd;
+ }
+ for (i=0; i<*maxndim; i++) {
+ d[i] = buffer_view.shape[i];
+ }
+ PyBuffer_Release(&buffer_view);
+ return 0;
}
- for (i=0; i<*maxndim; i++) {
- d[i] = buffer_view.shape[i];
+ else if (PyObject_GetBuffer(obj, &buffer_view, PyBUF_SIMPLE) == 0) {
+ d[0] = buffer_view.len;
+ *maxndim = 1;
+ PyBuffer_Release(&buffer_view);
+ return 0;
+ }
+ else {
+ PyErr_Clear();
}
- PyBuffer_Release(&buffer_view);
- return 0;
- }
- else if (PyObject_GetBuffer(obj, &buffer_view, PyBUF_SIMPLE) == 0) {
- d[0] = buffer_view.len;
- *maxndim = 1;
- PyBuffer_Release(&buffer_view);
- return 0;
- }
- else {
- PyErr_Clear();
}
#endif
/* obj has the __array_struct__ interface */
- if ((e = PyObject_GetAttrString(obj, "__array_struct__")) != NULL) {
+ e = PyArray_GetAttrString_SuppressException(obj, "__array_struct__");
+ if (e != NULL) {
int nd = -1;
if (NpyCapsule_Check(e)) {
PyArrayInterface *inter;
@@ -693,12 +696,10 @@ discover_dimensions(PyObject *obj, int *maxndim, npy_intp *d, int check_it,
return 0;
}
}
- else {
- PyErr_Clear();
- }
/* obj has the __array_interface__ interface */
- if ((e = PyObject_GetAttrString(obj, "__array_interface__")) != NULL) {
+ e = PyArray_GetAttrString_SuppressException(obj, "__array_interface__");
+ if (e != NULL) {
int nd = -1;
if (PyDict_Check(e)) {
PyObject *new;
@@ -728,9 +729,6 @@ discover_dimensions(PyObject *obj, int *maxndim, npy_intp *d, int check_it,
return 0;
}
}
- else {
- PyErr_Clear();
- }
n = PySequence_Size(obj);
@@ -1934,9 +1932,8 @@ PyArray_FromStructInterface(PyObject *input)
PyArrayObject *ret;
char endian = NPY_NATBYTE;
- attr = PyObject_GetAttrString(input, "__array_struct__");
+ attr = PyArray_GetAttrString_SuppressException(input, "__array_struct__");
if (attr == NULL) {
- PyErr_Clear();
return Py_NotImplemented;
}
if (!NpyCapsule_Check(attr)) {
@@ -2009,9 +2006,9 @@ PyArray_FromInterface(PyObject *origin)
/* Get the memory from __array_data__ and __array_offset__ */
/* Get the strides */
- iface = PyObject_GetAttrString(origin, "__array_interface__");
+ iface = PyArray_GetAttrString_SuppressException(origin,
+ "__array_interface__");
if (iface == NULL) {
- PyErr_Clear();
return Py_NotImplemented;
}
if (!PyDict_Check(iface)) {
@@ -2226,9 +2223,8 @@ PyArray_FromArrayAttr(PyObject *op, PyArray_Descr *typecode, PyObject *context)
PyObject *new;
PyObject *array_meth;
- array_meth = PyObject_GetAttrString(op, "__array__");
+ array_meth = PyArray_GetAttrString_SuppressException(op, "__array__");
if (array_meth == NULL) {
- PyErr_Clear();
return Py_NotImplemented;
}
if (context == NULL) {
diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c
index 7332a26d0..426ab695c 100644
--- a/numpy/core/src/multiarray/multiarraymodule.c
+++ b/numpy/core/src/multiarray/multiarraymodule.c
@@ -52,6 +52,7 @@ NPY_NO_EXPORT int NPY_NUMUSERTYPES = 0;
#include "shape.h"
#include "ctors.h"
#include "array_assign.h"
+#include "common.h"
/* Only here for API compatibility */
NPY_NO_EXPORT PyTypeObject PyBigArray_Type;
@@ -68,7 +69,7 @@ PyArray_GetPriority(PyObject *obj, double default_)
if (PyArray_CheckExact(obj))
return priority;
- ret = PyObject_GetAttrString(obj, "__array_priority__");
+ ret = PyArray_GetAttrString_SuppressException(obj, "__array_priority__");
if (ret != NULL) {
priority = PyFloat_AsDouble(ret);
}
diff --git a/numpy/core/tests/test_api.py b/numpy/core/tests/test_api.py
index 1f56d6cf6..c681b57ab 100644
--- a/numpy/core/tests/test_api.py
+++ b/numpy/core/tests/test_api.py
@@ -9,7 +9,155 @@ import warnings
from numpy.compat import sixu
# Switch between new behaviour when NPY_RELAXED_STRIDES_CHECKING is set.
-NPY_RELAXED_STRIDES_CHECKING = np.ones((10,1), order='C').flags.f_contiguous
+NPY_RELAXED_STRIDES_CHECKING = np.ones((10, 1), order='C').flags.f_contiguous
+
+
+def test_array_array():
+ obj = object()
+ tobj = type(object)
+ ones11 = np.ones((1, 1), np.float64)
+ tndarray = type(ones11)
+ # Test is_ndarary
+ assert_equal(np.array(ones11, dtype=np.float64), ones11)
+ old_refcount = sys.getrefcount(tndarray)
+ np.array(ones11)
+ assert_equal(old_refcount, sys.getrefcount(tndarray))
+
+ # test None
+ assert_equal(np.array(None, dtype=np.float64),
+ np.array(np.nan, dtype=np.float64))
+ old_refcount = sys.getrefcount(tobj)
+ np.array(None, dtype=np.float64)
+ assert_equal(old_refcount, sys.getrefcount(tobj))
+
+ # test scalar
+ assert_equal(np.array(1.0, dtype=np.float64),
+ np.ones((), dtype=np.float64))
+ old_refcount = sys.getrefcount(np.float64)
+ np.array(np.array(1.0, dtype=np.float64), dtype=np.float64)
+ assert_equal(old_refcount, sys.getrefcount(np.float64))
+
+ # test string
+ S2 = np.dtype((str, 2))
+ S3 = np.dtype((str, 3))
+ S5 = np.dtype((str, 5))
+ assert_equal(np.array("1.0", dtype=np.float64),
+ np.ones((), dtype=np.float64))
+ assert_equal(np.array("1.0").dtype, S3)
+ assert_equal(np.array("1.0", dtype=str).dtype, S3)
+ assert_equal(np.array("1.0", dtype=S2), np.array("1."))
+ assert_equal(np.array("1", dtype=S5), np.ones((), dtype=S5))
+
+ # test unicode
+ _unicode = globals().get("unicode")
+ if _unicode:
+ U2 = np.dtype((_unicode, 2))
+ U3 = np.dtype((_unicode, 3))
+ U5 = np.dtype((_unicode, 5))
+ assert_equal(np.array(_unicode("1.0"), dtype=np.float64),
+ np.ones((), dtype=np.float64))
+ assert_equal(np.array(_unicode("1.0")).dtype, U3)
+ assert_equal(np.array(_unicode("1.0"), dtype=_unicode).dtype, U3)
+ assert_equal(np.array(_unicode("1.0"), dtype=U2),
+ np.array(_unicode("1.")))
+ assert_equal(np.array(_unicode("1"), dtype=U5),
+ np.ones((), dtype=U5))
+
+ builtins = getattr(__builtins__, '__dict__', __builtins__)
+ assert_(isinstance(builtins, dict))
+
+ # test buffer
+ _buffer = builtins.get("buffer")
+ if _buffer:
+ assert_equal(np.array(_buffer("1.0"), dtype=np.float64),
+ np.array(1.0, dtype=np.float64))
+ assert_equal(np.array(_buffer("1.0"), dtype=np.float64).dtype,
+ np.dtype("float64"))
+ assert_equal(np.array([_buffer("1.0")], dtype=np.float64),
+ np.array([1.0], dtype=np.float64))
+
+ # test memoryview, new version of buffer
+ _memoryview = builtins.get("memoryview")
+ if _memoryview:
+ assert_equal(np.array(_memoryview(bytearray(b'1.0')),
+ dtype=np.float64),
+ np.array([49.0, 46.0, 48.0],
+ dtype=np.float64))
+ assert_equal(np.array(_memoryview(bytearray(b'1.0')),
+ dtype=np.float64).dtype,
+ np.dtype("float64"))
+ assert_equal(np.array(_memoryview(bytearray(b'1.0'))).dtype,
+ np.dtype('uint8'))
+
+ # test array interface
+ a = np.array(100.0, dtype=np.float64)
+ o = type("o", (object,),
+ dict(__array_interface__=a.__array_interface__))
+ assert_equal(np.array(o, dtype=np.float64), a)
+
+ # test array_struct interface
+ a = np.array([(1, 4.0, 'Hello'), (2, 6.0, 'World')],
+ dtype=[('f0', int), ('f1', float), ('f2', str)])
+ o = type("o", (object,),
+ dict(__array_struct__=a.__array_struct__))
+ ## wasn't what I expected... is np.array(o) supposed to equal a ?
+ ## instead we get a array([...], dtype=">V18")
+ assert_equal(str(np.array(o).data), str(a.data))
+
+ # test array
+ o = type("o", (object,),
+ dict(__array__=lambda *x: np.array(100.0, dtype=np.float64)))()
+ assert_equal(np.array(o, dtype=np.float64), np.array(100.0, np.float64))
+
+ # test recursion
+ nested = 1.5
+ for i in range(np.MAXDIMS):
+ nested = [nested]
+
+ # no error
+ np.array(nested)
+
+ # Exceeds recursion limit
+ assert_raises(ValueError, np.array, [nested], dtype=np.float64)
+
+ # Try with lists...
+ assert_equal(np.array([None] * 10, dtype=np.float64),
+ np.empty((10,), dtype=np.float64) + np.nan)
+ assert_equal(np.array([[None]] * 10, dtype=np.float64),
+ np.empty((10, 1), dtype=np.float64) + np.nan)
+ assert_equal(np.array([[None] * 10], dtype=np.float64),
+ np.empty((1, 10), dtype=np.float64) + np.nan)
+ assert_equal(np.array([[None] * 10] * 10, dtype=np.float64),
+ np.empty((10, 10), dtype=np.float64) + np.nan)
+
+ assert_equal(np.array([1.0] * 10, dtype=np.float64),
+ np.ones((10,), dtype=np.float64))
+ assert_equal(np.array([[1.0]] * 10, dtype=np.float64),
+ np.ones((10, 1), dtype=np.float64))
+ assert_equal(np.array([[1.0] * 10], dtype=np.float64),
+ np.ones((1, 10), dtype=np.float64))
+ assert_equal(np.array([[1.0] * 10] * 10, dtype=np.float64),
+ np.ones((10, 10), dtype=np.float64))
+
+ # Try with tuples
+ assert_equal(np.array((None,) * 10, dtype=np.float64),
+ np.empty((10,), dtype=np.float64) + np.nan)
+ assert_equal(np.array([(None,)] * 10, dtype=np.float64),
+ np.empty((10, 1), dtype=np.float64) + np.nan)
+ assert_equal(np.array([(None,) * 10], dtype=np.float64),
+ np.empty((1, 10), dtype=np.float64) + np.nan)
+ assert_equal(np.array([(None,) * 10] * 10, dtype=np.float64),
+ np.empty((10, 10), dtype=np.float64) + np.nan)
+
+ assert_equal(np.array((1.0,) * 10, dtype=np.float64),
+ np.ones((10,), dtype=np.float64))
+ assert_equal(np.array([(1.0,)] * 10, dtype=np.float64),
+ np.ones((10, 1), dtype=np.float64))
+ assert_equal(np.array([(1.0,) * 10], dtype=np.float64),
+ np.ones((1, 10), dtype=np.float64))
+ assert_equal(np.array([(1.0,) * 10] * 10, dtype=np.float64),
+ np.ones((10, 10), dtype=np.float64))
+
def test_fastCopyAndTranspose():
# 0D array