summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Wieser <wieser.eric@gmail.com>2019-08-16 16:50:30 -0700
committerEric Wieser <wieser.eric@gmail.com>2019-08-19 17:24:54 -0500
commit5fbce6d395a6bfd1ec25022dcee4eef8c5bbad17 (patch)
tree146c93655ae2d59e4520b9f9f46e2a6831e80709
parentf07a38da97a6a36eb12b203f6c1ffa4bf2b2cb87 (diff)
downloadnumpy-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.py14
-rw-r--r--numpy/core/tests/test_records.py27
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]