diff options
Diffstat (limited to 'numpy/core')
-rw-r--r-- | numpy/core/records.py | 44 | ||||
-rw-r--r-- | numpy/core/src/multiarray/getset.c | 2 | ||||
-rw-r--r-- | numpy/core/src/multiarray/mapping.c | 6 | ||||
-rw-r--r-- | numpy/core/src/multiarray/methods.c | 2 | ||||
-rw-r--r-- | numpy/core/src/multiarray/multiarraymodule.c | 2 | ||||
-rw-r--r-- | numpy/core/src/multiarray/number.c | 2 | ||||
-rw-r--r-- | numpy/core/src/private/npy_import.h | 6 | ||||
-rw-r--r-- | numpy/core/tests/test_records.py | 39 |
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), |