Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit e5c4cce

Browse filesBrowse files
ahaldanejaimefrio
authored andcommitted
BUG: recarrays viewed as subarrays don't convert to np.record type
Record array views were updated in numpy#5943 to return np.record dtype where possible, but forgot about the case of sub-arrays. That's fixed here, so accessing subarray fields by attribute or index works sensibly, as well as viewing a record array as a subarray dtype, and printing subarrays. This also happens to fix numpy#6459, since it affects the same lines. Fixes numpy#6497 numpy#6459
1 parent 6f1840b commit e5c4cce
Copy full SHA for e5c4cce

File tree

Expand file treeCollapse file tree

2 files changed

+42
-11
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+42
-11
lines changed

‎numpy/core/records.py

Copy file name to clipboardExpand all lines: numpy/core/records.py
+19-11Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -448,12 +448,14 @@ def __getattribute__(self, attr):
448448

449449
# At this point obj will always be a recarray, since (see
450450
# PyArray_GetField) the type of obj is inherited. Next, if obj.dtype is
451-
# non-structured, convert it to an ndarray. If obj is structured leave
452-
# it as a recarray, but make sure to convert to the same dtype.type (eg
453-
# to preserve numpy.record type if present), since nested structured
454-
# fields do not inherit type.
451+
# non-structured, convert it to an ndarray. Then if obj is structured
452+
# with void type convert it to the same dtype.type (eg to preserve
453+
# numpy.record type if present), since nested structured fields do not
454+
# inherit type. Don't do this for non-void structures though.
455455
if obj.dtype.fields:
456-
return obj.view(dtype=(self.dtype.type, obj.dtype.fields))
456+
if issubclass(obj.dtype.type, nt.void):
457+
return obj.view(dtype=(self.dtype.type, obj.dtype))
458+
return obj
457459
else:
458460
return obj.view(ndarray)
459461

@@ -463,8 +465,9 @@ def __getattribute__(self, attr):
463465
# Thus, you can't create attributes on-the-fly that are field names.
464466
def __setattr__(self, attr, val):
465467

466-
# Automatically convert (void) dtypes to records.
467-
if attr == 'dtype' and issubclass(val.type, nt.void):
468+
# Automatically convert (void) structured types to records
469+
# (but not non-void structures, subarrays, or non-structured voids)
470+
if attr == 'dtype' and issubclass(val.type, nt.void) and val.fields:
468471
val = sb.dtype((record, val))
469472

470473
newattr = attr not in self.__dict__
@@ -499,7 +502,9 @@ def __getitem__(self, indx):
499502
# we might also be returning a single element
500503
if isinstance(obj, ndarray):
501504
if obj.dtype.fields:
502-
return obj.view(dtype=(self.dtype.type, obj.dtype.fields))
505+
if issubclass(obj.dtype.type, nt.void):
506+
return obj.view(dtype=(self.dtype.type, obj.dtype))
507+
return obj
503508
else:
504509
return obj.view(type=ndarray)
505510
else:
@@ -519,11 +524,14 @@ def __repr__(self):
519524
# If this is a full record array (has numpy.record dtype),
520525
# or if it has a scalar (non-void) dtype with no records,
521526
# represent it using the rec.array function. Since rec.array
522-
# converts dtype to a numpy.record for us, use only dtype.descr,
523-
# not repr(dtype).
527+
# converts dtype to a numpy.record for us, convert back
528+
# to non-record before printing
529+
plain_dtype = self.dtype
530+
if plain_dtype.type is record:
531+
plain_dtype = sb.dtype((nt.void, plain_dtype))
524532
lf = '\n'+' '*len("rec.array(")
525533
return ('rec.array(%s, %sdtype=%s)' %
526-
(lst, lf, repr(self.dtype.descr)))
534+
(lst, lf, plain_dtype))
527535
else:
528536
# otherwise represent it using np.array plus a view
529537
# This should only happen if the user is playing

‎numpy/core/tests/test_records.py

Copy file name to clipboardExpand all lines: numpy/core/tests/test_records.py
+23Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,23 @@ def test_recarray_views(self):
121121
assert_equal(type(rv), np.recarray)
122122
assert_equal(rv.dtype.type, np.record)
123123

124+
# check that accessing nested structures keep record type, but
125+
# not for subarrays, non-void structures, non-structured voids
126+
test_dtype = [('a', 'f4,f4'), ('b', 'V8'), ('c', ('f4',2)),
127+
('d', ('i8', 'i4,i4'))]
128+
r = np.rec.array([((1,1), b'11111111', [1,1], 1),
129+
((1,1), b'11111111', [1,1], 1)], dtype=test_dtype)
130+
assert_equal(r.a.dtype.type, np.record)
131+
assert_equal(r.b.dtype.type, np.void)
132+
assert_equal(r.c.dtype.type, np.float32)
133+
assert_equal(r.d.dtype.type, np.int64)
134+
# check the same, but for views
135+
r = np.rec.array(np.ones(4, dtype='i4,i4'))
136+
assert_equal(r.view('f4,f4').dtype.type, np.record)
137+
assert_equal(r.view(('i4',2)).dtype.type, np.int32)
138+
assert_equal(r.view('V8').dtype.type, np.void)
139+
assert_equal(r.view(('i8', 'i4,i4')).dtype.type, np.int64)
140+
124141
#check that we can undo the view
125142
arrs = [np.ones(4, dtype='f4,i4'), np.ones(4, dtype='f8')]
126143
for arr in arrs:
@@ -135,6 +152,12 @@ def test_recarray_repr(self):
135152
a = np.array(np.ones(4, dtype='f8'))
136153
assert_(repr(np.rec.array(a)).startswith('rec.array'))
137154

155+
# check that the 'np.record' part of the dtype isn't shown
156+
a = np.rec.array(np.ones(3, dtype='i4,i4'))
157+
assert_equal(repr(a).find('numpy.record'), -1)
158+
a = np.rec.array(np.ones(3, dtype='i4'))
159+
assert_(repr(a).find('dtype=int32') != -1)
160+
138161
def test_recarray_from_names(self):
139162
ra = np.rec.array([
140163
(1, 'abc', 3.7000002861022949, 0),

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.