summaryrefslogtreecommitdiff
path: root/numpy/core
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/core')
-rw-r--r--numpy/core/records.py44
-rw-r--r--numpy/core/src/multiarray/getset.c2
-rw-r--r--numpy/core/src/multiarray/mapping.c6
-rw-r--r--numpy/core/src/multiarray/methods.c2
-rw-r--r--numpy/core/src/multiarray/multiarraymodule.c2
-rw-r--r--numpy/core/src/multiarray/number.c2
-rw-r--r--numpy/core/src/private/npy_import.h6
-rw-r--r--numpy/core/tests/test_records.py39
8 files changed, 66 insertions, 37 deletions
diff --git a/numpy/core/records.py b/numpy/core/records.py
index b1ea176e4..1b3d75db6 100644
--- a/numpy/core/records.py
+++ b/numpy/core/records.py
@@ -423,6 +423,12 @@ class recarray(ndarray):
strides=strides, order=order)
return self
+ def __array_finalize__(self, obj):
+ if self.dtype.type is not record:
+ # if self.dtype is not np.record, invoke __setattr__ which will
+ # convert it to a record if it is a void dtype.
+ self.dtype = self.dtype
+
def __getattribute__(self, attr):
# See if ndarray has this attr, and return it if so. (note that this
# means a field with the same name as an ndarray attr cannot be
@@ -456,6 +462,11 @@ class recarray(ndarray):
# Undo any "setting" of the attribute and do a setfield
# Thus, you can't create attributes on-the-fly that are field names.
def __setattr__(self, attr, val):
+
+ # Automatically convert (void) dtypes to records.
+ if attr == 'dtype' and issubclass(val.type, nt.void):
+ val = sb.dtype((record, val))
+
newattr = attr not in self.__dict__
try:
ret = object.__setattr__(self, attr, val)
@@ -502,8 +513,10 @@ class recarray(ndarray):
# show zero-length shape unless it is (0,)
lst = "[], shape=%s" % (repr(self.shape),)
- if self.dtype.type is record:
+ if (self.dtype.type is record
+ or (not issubclass(self.dtype.type, nt.void)) ):
# If this is a full record array (has numpy.record dtype),
+ # or if it has a scalar (non-void) dtype with no records,
# represent it using the rec.array function. Since rec.array
# converts dtype to a numpy.record for us, use only dtype.descr,
# not repr(dtype).
@@ -512,7 +525,8 @@ class recarray(ndarray):
(lst, lf, repr(self.dtype.descr)))
else:
# otherwise represent it using np.array plus a view
- # (There is currently (v1.10) no other easy way to create it)
+ # This should only happen if the user is playing
+ # strange games with dtypes.
lf = '\n'+' '*len("array(")
return ('array(%s, %sdtype=%s).view(numpy.recarray)' %
(lst, lf, str(self.dtype)))
@@ -534,22 +548,6 @@ class recarray(ndarray):
else:
return self.setfield(val, *res)
- def view(self, dtype=None, type=None):
- if dtype is None:
- return ndarray.view(self, type)
- elif type is None:
- try:
- if issubclass(dtype, ndarray):
- return ndarray.view(self, dtype)
- except TypeError:
- pass
- dtype = sb.dtype(dtype)
- if dtype.fields is None:
- return self.__array__().view(dtype)
- return ndarray.view(self, dtype)
- else:
- return ndarray.view(self, dtype, type)
-
def fromarrays(arrayList, dtype=None, shape=None, formats=None,
names=None, titles=None, aligned=False, byteorder=None):
@@ -837,10 +835,7 @@ def array(obj, dtype=None, shape=None, offset=0, strides=None, formats=None,
new = obj
if copy:
new = new.copy()
- res = new.view(recarray)
- if issubclass(res.dtype.type, nt.void):
- res.dtype = sb.dtype((record, res.dtype))
- return res
+ return new.view(recarray)
else:
interface = getattr(obj, "__array_interface__", None)
@@ -849,7 +844,4 @@ def array(obj, dtype=None, shape=None, offset=0, strides=None, formats=None,
obj = sb.array(obj)
if dtype is not None and (obj.dtype != dtype):
obj = obj.view(dtype)
- res = obj.view(recarray)
- if issubclass(res.dtype.type, nt.void):
- res.dtype = sb.dtype((record, res.dtype))
- return res
+ return obj.view(recarray)
diff --git a/numpy/core/src/multiarray/getset.c b/numpy/core/src/multiarray/getset.c
index 9ba12b092..0b694deed 100644
--- a/numpy/core/src/multiarray/getset.c
+++ b/numpy/core/src/multiarray/getset.c
@@ -437,7 +437,7 @@ array_descr_set(PyArrayObject *self, PyObject *arg)
PyObject *safe;
static PyObject *checkfunc = NULL;
- npy_cache_pyfunc("numpy.core._internal", "_view_is_safe", &checkfunc);
+ npy_cache_import("numpy.core._internal", "_view_is_safe", &checkfunc);
if (checkfunc == NULL) {
return -1;
}
diff --git a/numpy/core/src/multiarray/mapping.c b/numpy/core/src/multiarray/mapping.c
index 49a54d6cb..f265e6b39 100644
--- a/numpy/core/src/multiarray/mapping.c
+++ b/numpy/core/src/multiarray/mapping.c
@@ -785,7 +785,7 @@ prepare_index(PyArrayObject *self, PyObject *index,
used_ndim, PyArray_DIM(self, used_ndim),
indices[i].value);
- npy_cache_pyfunc(
+ npy_cache_import(
"numpy", "VisibleDeprecationWarning", &warning);
if (warning == NULL) {
goto failed_building_indices;
@@ -1438,7 +1438,7 @@ array_subscript(PyArrayObject *self, PyObject *op)
obj_is_string_or_stringlist(op)) {
PyObject *obj;
static PyObject *indexfunc = NULL;
- npy_cache_pyfunc("numpy.core._internal", "_index_fields", &indexfunc);
+ npy_cache_import("numpy.core._internal", "_index_fields", &indexfunc);
if (indexfunc == NULL) {
return NULL;
}
@@ -1801,7 +1801,7 @@ array_assign_subscript(PyArrayObject *self, PyObject *ind, PyObject *op)
"multi-field assignment is not supported");
}
- npy_cache_pyfunc("numpy.core._internal", "_index_fields", &indexfunc);
+ npy_cache_import("numpy.core._internal", "_index_fields", &indexfunc);
if (indexfunc == NULL) {
return -1;
}
diff --git a/numpy/core/src/multiarray/methods.c b/numpy/core/src/multiarray/methods.c
index d06e4a512..fd329cb8c 100644
--- a/numpy/core/src/multiarray/methods.c
+++ b/numpy/core/src/multiarray/methods.c
@@ -362,7 +362,7 @@ PyArray_GetField(PyArrayObject *self, PyArray_Descr *typed, int offset)
PyObject *safe;
static PyObject *checkfunc = NULL;
- npy_cache_pyfunc("numpy.core._internal", "_getfield_is_safe", &checkfunc);
+ npy_cache_import("numpy.core._internal", "_getfield_is_safe", &checkfunc);
if (checkfunc == NULL) {
return NULL;
}
diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c
index fbaa0f9d8..73265c3b6 100644
--- a/numpy/core/src/multiarray/multiarraymodule.c
+++ b/numpy/core/src/multiarray/multiarraymodule.c
@@ -2395,7 +2395,7 @@ array_matmul(PyObject *NPY_UNUSED(m), PyObject *args, PyObject* kwds)
char *subscripts;
PyArrayObject *ops[2];
- npy_cache_pyfunc("numpy.core.multiarray", "matmul", &matmul);
+ npy_cache_import("numpy.core.multiarray", "matmul", &matmul);
if (matmul == NULL) {
return NULL;
}
diff --git a/numpy/core/src/multiarray/number.c b/numpy/core/src/multiarray/number.c
index fcc70d4ec..3e7521582 100644
--- a/numpy/core/src/multiarray/number.c
+++ b/numpy/core/src/multiarray/number.c
@@ -397,7 +397,7 @@ array_matrix_multiply(PyArrayObject *m1, PyObject *m2)
{
static PyObject *matmul = NULL;
- npy_cache_pyfunc("numpy.core.multiarray", "matmul", &matmul);
+ npy_cache_import("numpy.core.multiarray", "matmul", &matmul);
if (matmul == NULL) {
return NULL;
}
diff --git a/numpy/core/src/private/npy_import.h b/numpy/core/src/private/npy_import.h
index a75c59884..221e1e645 100644
--- a/numpy/core/src/private/npy_import.h
+++ b/numpy/core/src/private/npy_import.h
@@ -13,17 +13,17 @@
* exit,
*
* @param module Absolute module name.
- * @param function Function name.
+ * @param attr module attribute to cache.
* @param cache Storage location for imported function.
*/
NPY_INLINE static void
-npy_cache_pyfunc(const char *module, const char *function, PyObject **cache)
+npy_cache_import(const char *module, const char *attr, PyObject **cache)
{
if (*cache == NULL) {
PyObject *mod = PyImport_ImportModule(module);
if (mod != NULL) {
- *cache = PyObject_GetAttrString(mod, function);
+ *cache = PyObject_GetAttrString(mod, attr);
Py_DECREF(mod);
}
}
diff --git a/numpy/core/tests/test_records.py b/numpy/core/tests/test_records.py
index 4924d4471..44625adee 100644
--- a/numpy/core/tests/test_records.py
+++ b/numpy/core/tests/test_records.py
@@ -88,13 +88,50 @@ class TestFromrecords(TestCase):
assert_equal(recordarr, recordarr_r)
assert_equal(type(recarr_r), np.recarray)
- assert_equal(recarr_r.dtype.type, np.void)
+ assert_equal(recarr_r.dtype.type, np.record)
assert_equal(recarr, recarr_r)
assert_equal(type(recordview_r), np.ndarray)
assert_equal(recordview.dtype.type, np.record)
assert_equal(recordview, recordview_r)
+ def test_recarray_views(self):
+ a = np.array([(1,'ABC'), (2, "DEF")],
+ dtype=[('foo', int), ('bar', 'S4')])
+ b = np.array([1,2,3,4,5], dtype=np.int64)
+
+ #check that np.rec.array gives right dtypes
+ assert_equal(np.rec.array(a).dtype.type, np.record)
+ assert_equal(type(np.rec.array(a)), np.recarray)
+ assert_equal(np.rec.array(b).dtype.type, np.int64)
+ assert_equal(type(np.rec.array(b)), np.recarray)
+
+ #check that viewing as recarray does the same
+ assert_equal(a.view(np.recarray).dtype.type, np.record)
+ assert_equal(type(a.view(np.recarray)), np.recarray)
+ assert_equal(b.view(np.recarray).dtype.type, np.int64)
+ assert_equal(type(b.view(np.recarray)), np.recarray)
+
+ #check that view to non-structured dtype preserves type=np.recarray
+ r = np.rec.array(np.ones(4, dtype="f4,i4"))
+ rv = r.view('f8').view('f4,i4')
+ assert_equal(type(rv), np.recarray)
+ assert_equal(rv.dtype.type, np.record)
+
+ #check that we can undo the view
+ arrs = [np.ones(4, dtype='f4,i4'), np.ones(4, dtype='f8')]
+ for arr in arrs:
+ rec = np.rec.array(arr)
+ # recommended way to view as an ndarray:
+ arr2 = rec.view(rec.dtype.fields or rec.dtype, np.ndarray)
+ assert_equal(arr2.dtype.type, arr.dtype.type)
+ assert_equal(type(arr2), type(arr))
+
+ def test_recarray_repr(self):
+ # make sure non-structured dtypes also show up as rec.array
+ a = np.array(np.ones(4, dtype='f8'))
+ assert_(repr(np.rec.array(a)).startswith('rec.array'))
+
def test_recarray_from_names(self):
ra = np.rec.array([
(1, 'abc', 3.7000002861022949, 0),