aboutsummaryrefslogtreecommitdiffstats
path: root/testing/py-numpy/numpy-1.10.1-backport-1.patch
blob: 77a3c010371f81a44103cb778c4274edba573b3d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
From 3a816a4db9b498eb64eb837fdcca0fa8ddbe063e Mon Sep 17 00:00:00 2001
From: Allan Haldane <allan.haldane@gmail.com>
Date: Sat, 17 Oct 2015 14:00:36 -0400
Subject: [PATCH] BUG: recarrays viewed as subarrays don't convert to np.record
 type

Record array views were updated in #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 #6459, since it affects the same lines.

Fixes #6497 #6459
---
 numpy/core/records.py            | 30 +++++++++++++++++++-----------
 numpy/core/tests/test_records.py | 23 +++++++++++++++++++++++
 2 files changed, 42 insertions(+), 11 deletions(-)

diff --git a/numpy/core/records.py b/numpy/core/records.py
index 4a99553..4ce3fe9 100644
--- a/numpy/core/records.py
+++ b/numpy/core/records.py
@@ -448,12 +448,14 @@ def __getattribute__(self, attr):
 
         # At this point obj will always be a recarray, since (see
         # PyArray_GetField) the type of obj is inherited. Next, if obj.dtype is
-        # non-structured, convert it to an ndarray. If obj is structured leave
-        # it as a recarray, but make sure to convert to the same dtype.type (eg
-        # to preserve numpy.record type if present), since nested structured
-        # fields do not inherit type.
+        # non-structured, convert it to an ndarray. Then if obj is structured
+        # 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:
-            return obj.view(dtype=(self.dtype.type, obj.dtype.fields))
+            if issubclass(obj.dtype.type, nt.void):
+                return obj.view(dtype=(self.dtype.type, obj.dtype))
+            return obj
         else:
             return obj.view(ndarray)
 
@@ -463,8 +465,9 @@ def __getattribute__(self, attr):
     # 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):
+        # 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:
             val = sb.dtype((record, val))
 
         newattr = attr not in self.__dict__
@@ -499,7 +502,9 @@ def __getitem__(self, indx):
         # we might also be returning a single element
         if isinstance(obj, ndarray):
             if obj.dtype.fields:
-                return obj.view(dtype=(self.dtype.type, obj.dtype.fields))
+                if issubclass(obj.dtype.type, nt.void):
+                    return obj.view(dtype=(self.dtype.type, obj.dtype))
+                return obj
             else:
                 return obj.view(type=ndarray)
         else:
@@ -519,11 +524,14 @@ def __repr__(self):
             # 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).
+            # converts dtype to a numpy.record for us, convert back
+            # to non-record before printing
+            plain_dtype = self.dtype
+            if plain_dtype.type is record:
+                plain_dtype = sb.dtype((nt.void, plain_dtype))
             lf = '\n'+' '*len("rec.array(")
             return ('rec.array(%s, %sdtype=%s)' %
-                          (lst, lf, repr(self.dtype.descr)))
+                          (lst, lf, plain_dtype))
         else:
             # otherwise represent it using np.array plus a view
             # This should only happen if the user is playing
diff --git a/numpy/core/tests/test_records.py b/numpy/core/tests/test_records.py
index 7a18f29..290bc4f 100644
--- a/numpy/core/tests/test_records.py
+++ b/numpy/core/tests/test_records.py
@@ -121,6 +121,23 @@ def test_recarray_views(self):
         assert_equal(type(rv), np.recarray)
         assert_equal(rv.dtype.type, np.record)
 
+        # check that accessing nested structures keep record type, but
+        # not for subarrays, non-void structures, non-structured voids
+        test_dtype = [('a', 'f4,f4'), ('b', 'V8'), ('c', ('f4',2)),
+                      ('d', ('i8', 'i4,i4'))]
+        r = np.rec.array([((1,1), b'11111111', [1,1], 1),
+                          ((1,1), b'11111111', [1,1], 1)], dtype=test_dtype)
+        assert_equal(r.a.dtype.type, np.record)
+        assert_equal(r.b.dtype.type, np.void)
+        assert_equal(r.c.dtype.type, np.float32)
+        assert_equal(r.d.dtype.type, np.int64)
+        # check the same, but for views
+        r = np.rec.array(np.ones(4, dtype='i4,i4'))
+        assert_equal(r.view('f4,f4').dtype.type, np.record)
+        assert_equal(r.view(('i4',2)).dtype.type, np.int32)
+        assert_equal(r.view('V8').dtype.type, np.void)
+        assert_equal(r.view(('i8', 'i4,i4')).dtype.type, np.int64)
+
         #check that we can undo the view
         arrs = [np.ones(4, dtype='f4,i4'), np.ones(4, dtype='f8')]
         for arr in arrs:
@@ -135,6 +152,12 @@ def test_recarray_repr(self):
         a = np.array(np.ones(4, dtype='f8'))
         assert_(repr(np.rec.array(a)).startswith('rec.array'))
 
+        # check that the 'np.record' part of the dtype isn't shown
+        a = np.rec.array(np.ones(3, dtype='i4,i4'))
+        assert_equal(repr(a).find('numpy.record'), -1)
+        a = np.rec.array(np.ones(3, dtype='i4'))
+        assert_(repr(a).find('dtype=int32') != -1)
+
     def test_recarray_from_names(self):
         ra = np.rec.array([
             (1, 'abc', 3.7000002861022949, 0),