diff options
author | Eric Wieser <wieser.eric@gmail.com> | 2019-08-16 16:50:30 -0700 |
---|---|---|
committer | Eric Wieser <wieser.eric@gmail.com> | 2019-08-19 17:24:54 -0500 |
commit | 5fbce6d395a6bfd1ec25022dcee4eef8c5bbad17 (patch) | |
tree | 146c93655ae2d59e4520b9f9f46e2a6831e80709 | |
parent | f07a38da97a6a36eb12b203f6c1ffa4bf2b2cb87 (diff) | |
download | numpy-5fbce6d395a6bfd1ec25022dcee4eef8c5bbad17.tar.gz |
BUG: Make np.record work on structured fields with no fields
This replaces some more uses of `bool(dt.fields)` and `bool(dt.names)` with `dt.names is not None`.
`dt.fields is not None` would have worked too, but checking `.names` is more prevalent elsewhere
-rw-r--r-- | numpy/core/records.py | 14 | ||||
-rw-r--r-- | numpy/core/tests/test_records.py | 27 |
2 files changed, 34 insertions, 7 deletions
diff --git a/numpy/core/records.py b/numpy/core/records.py index 86a43306a..e3e9f8193 100644 --- a/numpy/core/records.py +++ b/numpy/core/records.py @@ -254,7 +254,7 @@ class record(nt.void): except AttributeError: #happens if field is Object type return obj - if dt.fields: + if dt.names is not None: return obj.view((self.__class__, obj.dtype.fields)) return obj else: @@ -279,7 +279,7 @@ class record(nt.void): obj = nt.void.__getitem__(self, indx) # copy behavior of record.__getattribute__, - if isinstance(obj, nt.void) and obj.dtype.fields: + if isinstance(obj, nt.void) and obj.dtype.names is not None: return obj.view((self.__class__, obj.dtype.fields)) else: # return a single element @@ -431,7 +431,7 @@ class recarray(ndarray): return self def __array_finalize__(self, obj): - if self.dtype.type is not record and self.dtype.fields: + if self.dtype.type is not record and self.dtype.names is not None: # 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 @@ -459,7 +459,7 @@ class recarray(ndarray): # with void type convert it to the same dtype.type (eg to preserve # numpy.record type if present), since nested structured fields do not # inherit type. Don't do this for non-void structures though. - if obj.dtype.fields: + if obj.dtype.names is not None: if issubclass(obj.dtype.type, nt.void): return obj.view(dtype=(self.dtype.type, obj.dtype)) return obj @@ -474,7 +474,7 @@ class recarray(ndarray): # Automatically convert (void) structured types to records # (but not non-void structures, subarrays, or non-structured voids) - if attr == 'dtype' and issubclass(val.type, nt.void) and val.fields: + if attr == 'dtype' and issubclass(val.type, nt.void) and val.names is not None: val = sb.dtype((record, val)) newattr = attr not in self.__dict__ @@ -508,7 +508,7 @@ class recarray(ndarray): # copy behavior of getattr, except that here # we might also be returning a single element if isinstance(obj, ndarray): - if obj.dtype.fields: + if obj.dtype.names is not None: obj = obj.view(type(self)) if issubclass(obj.dtype.type, nt.void): return obj.view(dtype=(self.dtype.type, obj.dtype)) @@ -564,7 +564,7 @@ class recarray(ndarray): if val is None: obj = self.getfield(*res) - if obj.dtype.fields: + if obj.dtype.names is not None: return obj return obj.view(ndarray) else: diff --git a/numpy/core/tests/test_records.py b/numpy/core/tests/test_records.py index c059ef510..5cff8d0dd 100644 --- a/numpy/core/tests/test_records.py +++ b/numpy/core/tests/test_records.py @@ -437,6 +437,33 @@ class TestRecord(object): arr = np.zeros((3,), dtype=[('x', int), ('y', int)]) assert_raises(ValueError, lambda: arr[['nofield']]) + @pytest.mark.parametrize('nfields', [0, 1, 2]) + def test_assign_dtype_attribute(self, nfields): + dt = np.dtype([('a', np.uint8), ('b', np.uint8), ('c', np.uint8)][:nfields]) + data = np.zeros(3, dt).view(np.recarray) + + # the original and resulting dtypes differ on whether they are records + assert data.dtype.type == np.record + assert dt.type != np.record + + # ensure that the dtype remains a record even when assigned + data.dtype = dt + assert data.dtype.type == np.record + + @pytest.mark.parametrize('nfields', [0, 1, 2]) + def test_nested_fields_are_records(self, nfields): + """ Test that nested structured types are treated as records too """ + dt = np.dtype([('a', np.uint8), ('b', np.uint8), ('c', np.uint8)][:nfields]) + dt_outer = np.dtype([('inner', dt)]) + + data = np.zeros(3, dt_outer).view(np.recarray) + assert isinstance(data, np.recarray) + assert isinstance(data['inner'], np.recarray) + + data0 = data[0] + assert isinstance(data0, np.record) + assert isinstance(data0['inner'], np.record) + def test_find_duplicate(): l1 = [1, 2, 3, 4, 5, 6] |