codekingpro/portable-devtools
114k
1# doctest
2r''' Test the .npy file format.
3
4Set up:
5
6 >>> import sys
7 >>> from io import BytesIO
8 >>> from numpy.lib import format
9 >>>
10 >>> scalars = [
11 ... np.uint8,
12 ... np.int8,
13 ... np.uint16,
14 ... np.int16,
15 ... np.uint32,
16 ... np.int32,
17 ... np.uint64,
18 ... np.int64,
19 ... np.float32,
20 ... np.float64,
21 ... np.complex64,
22 ... np.complex128,
23 ... object,
24 ... ]
25 >>>
26 >>> basic_arrays = []
27 >>>
28 >>> for scalar in scalars:
29 ... for endian in '<>':
30 ... dtype = np.dtype(scalar).newbyteorder(endian)
31 ... basic = np.arange(15).astype(dtype)
32 ... basic_arrays.extend([
33 ... np.array([], dtype=dtype),
34 ... np.array(10, dtype=dtype),
35 ... basic,
36 ... basic.reshape((3,5)),
37 ... basic.reshape((3,5)).T,
38 ... basic.reshape((3,5))[::-1,::2],
39 ... ])
40 ...
41 >>>
42 >>> Pdescr = [
43 ... ('x', 'i4', (2,)),
44 ... ('y', 'f8', (2, 2)),
45 ... ('z', 'u1')]
46 >>>
47 >>>
48 >>> PbufferT = [
49 ... ([3,2], [[6.,4.],[6.,4.]], 8),
50 ... ([4,3], [[7.,5.],[7.,5.]], 9),
51 ... ]
52 >>>
53 >>>
54 >>> Ndescr = [
55 ... ('x', 'i4', (2,)),
56 ... ('Info', [
57 ... ('value', 'c16'),
58 ... ('y2', 'f8'),
59 ... ('Info2', [
60 ... ('name', 'S2'),
61 ... ('value', 'c16', (2,)),
62 ... ('y3', 'f8', (2,)),
63 ... ('z3', 'u4', (2,))]),
64 ... ('name', 'S2'),
65 ... ('z2', 'b1')]),
66 ... ('color', 'S2'),
67 ... ('info', [
68 ... ('Name', 'U8'),
69 ... ('Value', 'c16')]),
70 ... ('y', 'f8', (2, 2)),
71 ... ('z', 'u1')]
72 >>>
73 >>>
74 >>> NbufferT = [
75 ... ([3,2], (6j, 6., ('nn', [6j,4j], [6.,4.], [1,2]), 'NN', True), 'cc', ('NN', 6j), [[6.,4.],[6.,4.]], 8),
76 ... ([4,3], (7j, 7., ('oo', [7j,5j], [7.,5.], [2,1]), 'OO', False), 'dd', ('OO', 7j), [[7.,5.],[7.,5.]], 9),
77 ... ]
78 >>>
79 >>>
80 >>> record_arrays = [
81 ... np.array(PbufferT, dtype=np.dtype(Pdescr).newbyteorder('<')),
82 ... np.array(NbufferT, dtype=np.dtype(Ndescr).newbyteorder('<')),
83 ... np.array(PbufferT, dtype=np.dtype(Pdescr).newbyteorder('>')),
84 ... np.array(NbufferT, dtype=np.dtype(Ndescr).newbyteorder('>')),
85 ... ]
86
87Test the magic string writing.
88
89 >>> format.magic(1, 0)
90 '\x93NUMPY\x01\x00'
91 >>> format.magic(0, 0)
92 '\x93NUMPY\x00\x00'
93 >>> format.magic(255, 255)
94 '\x93NUMPY\xff\xff'
95 >>> format.magic(2, 5)
96 '\x93NUMPY\x02\x05'
97
98Test the magic string reading.
99
100 >>> format.read_magic(BytesIO(format.magic(1, 0)))
101 (1, 0)
102 >>> format.read_magic(BytesIO(format.magic(0, 0)))
103 (0, 0)
104 >>> format.read_magic(BytesIO(format.magic(255, 255)))
105 (255, 255)
106 >>> format.read_magic(BytesIO(format.magic(2, 5)))
107 (2, 5)
108
109Test the header writing.
110
111 >>> for arr in basic_arrays + record_arrays:
112 ... f = BytesIO()
113 ... format.write_array_header_1_0(f, arr) # XXX: arr is not a dict, items gets called on it
114 ... print(repr(f.getvalue()))
115 ...
116 "F\x00{'descr': '|u1', 'fortran_order': False, 'shape': (0,)} \n"
117 "F\x00{'descr': '|u1', 'fortran_order': False, 'shape': ()} \n"
118 "F\x00{'descr': '|u1', 'fortran_order': False, 'shape': (15,)} \n"
119 "F\x00{'descr': '|u1', 'fortran_order': False, 'shape': (3, 5)} \n"
120 "F\x00{'descr': '|u1', 'fortran_order': True, 'shape': (5, 3)} \n"
121 "F\x00{'descr': '|u1', 'fortran_order': False, 'shape': (3, 3)} \n"
122 "F\x00{'descr': '|u1', 'fortran_order': False, 'shape': (0,)} \n"
123 "F\x00{'descr': '|u1', 'fortran_order': False, 'shape': ()} \n"
124 "F\x00{'descr': '|u1', 'fortran_order': False, 'shape': (15,)} \n"
125 "F\x00{'descr': '|u1', 'fortran_order': False, 'shape': (3, 5)} \n"
126 "F\x00{'descr': '|u1', 'fortran_order': True, 'shape': (5, 3)} \n"
127 "F\x00{'descr': '|u1', 'fortran_order': False, 'shape': (3, 3)} \n"
128 "F\x00{'descr': '|i1', 'fortran_order': False, 'shape': (0,)} \n"
129 "F\x00{'descr': '|i1', 'fortran_order': False, 'shape': ()} \n"
130 "F\x00{'descr': '|i1', 'fortran_order': False, 'shape': (15,)} \n"
131 "F\x00{'descr': '|i1', 'fortran_order': False, 'shape': (3, 5)} \n"
132 "F\x00{'descr': '|i1', 'fortran_order': True, 'shape': (5, 3)} \n"
133 "F\x00{'descr': '|i1', 'fortran_order': False, 'shape': (3, 3)} \n"
134 "F\x00{'descr': '|i1', 'fortran_order': False, 'shape': (0,)} \n"
135 "F\x00{'descr': '|i1', 'fortran_order': False, 'shape': ()} \n"
136 "F\x00{'descr': '|i1', 'fortran_order': False, 'shape': (15,)} \n"
137 "F\x00{'descr': '|i1', 'fortran_order': False, 'shape': (3, 5)} \n"
138 "F\x00{'descr': '|i1', 'fortran_order': True, 'shape': (5, 3)} \n"
139 "F\x00{'descr': '|i1', 'fortran_order': False, 'shape': (3, 3)} \n"
140 "F\x00{'descr': '<u2', 'fortran_order': False, 'shape': (0,)} \n"
141 "F\x00{'descr': '<u2', 'fortran_order': False, 'shape': ()} \n"
142 "F\x00{'descr': '<u2', 'fortran_order': False, 'shape': (15,)} \n"
143 "F\x00{'descr': '<u2', 'fortran_order': False, 'shape': (3, 5)} \n"
144 "F\x00{'descr': '<u2', 'fortran_order': True, 'shape': (5, 3)} \n"
145 "F\x00{'descr': '<u2', 'fortran_order': False, 'shape': (3, 3)} \n"
146 "F\x00{'descr': '>u2', 'fortran_order': False, 'shape': (0,)} \n"
147 "F\x00{'descr': '>u2', 'fortran_order': False, 'shape': ()} \n"
148 "F\x00{'descr': '>u2', 'fortran_order': False, 'shape': (15,)} \n"
149 "F\x00{'descr': '>u2', 'fortran_order': False, 'shape': (3, 5)} \n"
150 "F\x00{'descr': '>u2', 'fortran_order': True, 'shape': (5, 3)} \n"
151 "F\x00{'descr': '>u2', 'fortran_order': False, 'shape': (3, 3)} \n"
152 "F\x00{'descr': '<i2', 'fortran_order': False, 'shape': (0,)} \n"
153 "F\x00{'descr': '<i2', 'fortran_order': False, 'shape': ()} \n"
154 "F\x00{'descr': '<i2', 'fortran_order': False, 'shape': (15,)} \n"
155 "F\x00{'descr': '<i2', 'fortran_order': False, 'shape': (3, 5)} \n"
156 "F\x00{'descr': '<i2', 'fortran_order': True, 'shape': (5, 3)} \n"
157 "F\x00{'descr': '<i2', 'fortran_order': False, 'shape': (3, 3)} \n"
158 "F\x00{'descr': '>i2', 'fortran_order': False, 'shape': (0,)} \n"
159 "F\x00{'descr': '>i2', 'fortran_order': False, 'shape': ()} \n"
160 "F\x00{'descr': '>i2', 'fortran_order': False, 'shape': (15,)} \n"
161 "F\x00{'descr': '>i2', 'fortran_order': False, 'shape': (3, 5)} \n"
162 "F\x00{'descr': '>i2', 'fortran_order': True, 'shape': (5, 3)} \n"
163 "F\x00{'descr': '>i2', 'fortran_order': False, 'shape': (3, 3)} \n"
164 "F\x00{'descr': '<u4', 'fortran_order': False, 'shape': (0,)} \n"
165 "F\x00{'descr': '<u4', 'fortran_order': False, 'shape': ()} \n"
166 "F\x00{'descr': '<u4', 'fortran_order': False, 'shape': (15,)} \n"
167 "F\x00{'descr': '<u4', 'fortran_order': False, 'shape': (3, 5)} \n"
168 "F\x00{'descr': '<u4', 'fortran_order': True, 'shape': (5, 3)} \n"
169 "F\x00{'descr': '<u4', 'fortran_order': False, 'shape': (3, 3)} \n"
170 "F\x00{'descr': '>u4', 'fortran_order': False, 'shape': (0,)} \n"
171 "F\x00{'descr': '>u4', 'fortran_order': False, 'shape': ()} \n"
172 "F\x00{'descr': '>u4', 'fortran_order': False, 'shape': (15,)} \n"
173 "F\x00{'descr': '>u4', 'fortran_order': False, 'shape': (3, 5)} \n"
174 "F\x00{'descr': '>u4', 'fortran_order': True, 'shape': (5, 3)} \n"
175 "F\x00{'descr': '>u4', 'fortran_order': False, 'shape': (3, 3)} \n"
176 "F\x00{'descr': '<i4', 'fortran_order': False, 'shape': (0,)} \n"
177 "F\x00{'descr': '<i4', 'fortran_order': False, 'shape': ()} \n"
178 "F\x00{'descr': '<i4', 'fortran_order': False, 'shape': (15,)} \n"
179 "F\x00{'descr': '<i4', 'fortran_order': False, 'shape': (3, 5)} \n"
180 "F\x00{'descr': '<i4', 'fortran_order': True, 'shape': (5, 3)} \n"
181 "F\x00{'descr': '<i4', 'fortran_order': False, 'shape': (3, 3)} \n"
182 "F\x00{'descr': '>i4', 'fortran_order': False, 'shape': (0,)} \n"
183 "F\x00{'descr': '>i4', 'fortran_order': False, 'shape': ()} \n"
184 "F\x00{'descr': '>i4', 'fortran_order': False, 'shape': (15,)} \n"
185 "F\x00{'descr': '>i4', 'fortran_order': False, 'shape': (3, 5)} \n"
186 "F\x00{'descr': '>i4', 'fortran_order': True, 'shape': (5, 3)} \n"
187 "F\x00{'descr': '>i4', 'fortran_order': False, 'shape': (3, 3)} \n"
188 "F\x00{'descr': '<u8', 'fortran_order': False, 'shape': (0,)} \n"
189 "F\x00{'descr': '<u8', 'fortran_order': False, 'shape': ()} \n"
190 "F\x00{'descr': '<u8', 'fortran_order': False, 'shape': (15,)} \n"
191 "F\x00{'descr': '<u8', 'fortran_order': False, 'shape': (3, 5)} \n"
192 "F\x00{'descr': '<u8', 'fortran_order': True, 'shape': (5, 3)} \n"
193 "F\x00{'descr': '<u8', 'fortran_order': False, 'shape': (3, 3)} \n"
194 "F\x00{'descr': '>u8', 'fortran_order': False, 'shape': (0,)} \n"
195 "F\x00{'descr': '>u8', 'fortran_order': False, 'shape': ()} \n"
196 "F\x00{'descr': '>u8', 'fortran_order': False, 'shape': (15,)} \n"
197 "F\x00{'descr': '>u8', 'fortran_order': False, 'shape': (3, 5)} \n"
198 "F\x00{'descr': '>u8', 'fortran_order': True, 'shape': (5, 3)} \n"
199 "F\x00{'descr': '>u8', 'fortran_order': False, 'shape': (3, 3)} \n"
200 "F\x00{'descr': '<i8', 'fortran_order': False, 'shape': (0,)} \n"
201 "F\x00{'descr': '<i8', 'fortran_order': False, 'shape': ()} \n"
202 "F\x00{'descr': '<i8', 'fortran_order': False, 'shape': (15,)} \n"
203 "F\x00{'descr': '<i8', 'fortran_order': False, 'shape': (3, 5)} \n"
204 "F\x00{'descr': '<i8', 'fortran_order': True, 'shape': (5, 3)} \n"
205 "F\x00{'descr': '<i8', 'fortran_order': False, 'shape': (3, 3)} \n"
206 "F\x00{'descr': '>i8', 'fortran_order': False, 'shape': (0,)} \n"
207 "F\x00{'descr': '>i8', 'fortran_order': False, 'shape': ()} \n"
208 "F\x00{'descr': '>i8', 'fortran_order': False, 'shape': (15,)} \n"
209 "F\x00{'descr': '>i8', 'fortran_order': False, 'shape': (3, 5)} \n"
210 "F\x00{'descr': '>i8', 'fortran_order': True, 'shape': (5, 3)} \n"
211 "F\x00{'descr': '>i8', 'fortran_order': False, 'shape': (3, 3)} \n"
212 "F\x00{'descr': '<f4', 'fortran_order': False, 'shape': (0,)} \n"
213 "F\x00{'descr': '<f4', 'fortran_order': False, 'shape': ()} \n"
214 "F\x00{'descr': '<f4', 'fortran_order': False, 'shape': (15,)} \n"
215 "F\x00{'descr': '<f4', 'fortran_order': False, 'shape': (3, 5)} \n"
216 "F\x00{'descr': '<f4', 'fortran_order': True, 'shape': (5, 3)} \n"
217 "F\x00{'descr': '<f4', 'fortran_order': False, 'shape': (3, 3)} \n"
218 "F\x00{'descr': '>f4', 'fortran_order': False, 'shape': (0,)} \n"
219 "F\x00{'descr': '>f4', 'fortran_order': False, 'shape': ()} \n"
220 "F\x00{'descr': '>f4', 'fortran_order': False, 'shape': (15,)} \n"
221 "F\x00{'descr': '>f4', 'fortran_order': False, 'shape': (3, 5)} \n"
222 "F\x00{'descr': '>f4', 'fortran_order': True, 'shape': (5, 3)} \n"
223 "F\x00{'descr': '>f4', 'fortran_order': False, 'shape': (3, 3)} \n"
224 "F\x00{'descr': '<f8', 'fortran_order': False, 'shape': (0,)} \n"
225 "F\x00{'descr': '<f8', 'fortran_order': False, 'shape': ()} \n"
226 "F\x00{'descr': '<f8', 'fortran_order': False, 'shape': (15,)} \n"
227 "F\x00{'descr': '<f8', 'fortran_order': False, 'shape': (3, 5)} \n"
228 "F\x00{'descr': '<f8', 'fortran_order': True, 'shape': (5, 3)} \n"
229 "F\x00{'descr': '<f8', 'fortran_order': False, 'shape': (3, 3)} \n"
230 "F\x00{'descr': '>f8', 'fortran_order': False, 'shape': (0,)} \n"
231 "F\x00{'descr': '>f8', 'fortran_order': False, 'shape': ()} \n"
232 "F\x00{'descr': '>f8', 'fortran_order': False, 'shape': (15,)} \n"
233 "F\x00{'descr': '>f8', 'fortran_order': False, 'shape': (3, 5)} \n"
234 "F\x00{'descr': '>f8', 'fortran_order': True, 'shape': (5, 3)} \n"
235 "F\x00{'descr': '>f8', 'fortran_order': False, 'shape': (3, 3)} \n"
236 "F\x00{'descr': '<c8', 'fortran_order': False, 'shape': (0,)} \n"
237 "F\x00{'descr': '<c8', 'fortran_order': False, 'shape': ()} \n"
238 "F\x00{'descr': '<c8', 'fortran_order': False, 'shape': (15,)} \n"
239 "F\x00{'descr': '<c8', 'fortran_order': False, 'shape': (3, 5)} \n"
240 "F\x00{'descr': '<c8', 'fortran_order': True, 'shape': (5, 3)} \n"
241 "F\x00{'descr': '<c8', 'fortran_order': False, 'shape': (3, 3)} \n"
242 "F\x00{'descr': '>c8', 'fortran_order': False, 'shape': (0,)} \n"
243 "F\x00{'descr': '>c8', 'fortran_order': False, 'shape': ()} \n"
244 "F\x00{'descr': '>c8', 'fortran_order': False, 'shape': (15,)} \n"
245 "F\x00{'descr': '>c8', 'fortran_order': False, 'shape': (3, 5)} \n"
246 "F\x00{'descr': '>c8', 'fortran_order': True, 'shape': (5, 3)} \n"
247 "F\x00{'descr': '>c8', 'fortran_order': False, 'shape': (3, 3)} \n"
248 "F\x00{'descr': '<c16', 'fortran_order': False, 'shape': (0,)} \n"
249 "F\x00{'descr': '<c16', 'fortran_order': False, 'shape': ()} \n"
250 "F\x00{'descr': '<c16', 'fortran_order': False, 'shape': (15,)} \n"
251 "F\x00{'descr': '<c16', 'fortran_order': False, 'shape': (3, 5)} \n"
252 "F\x00{'descr': '<c16', 'fortran_order': True, 'shape': (5, 3)} \n"
253 "F\x00{'descr': '<c16', 'fortran_order': False, 'shape': (3, 3)} \n"
254 "F\x00{'descr': '>c16', 'fortran_order': False, 'shape': (0,)} \n"
255 "F\x00{'descr': '>c16', 'fortran_order': False, 'shape': ()} \n"
256 "F\x00{'descr': '>c16', 'fortran_order': False, 'shape': (15,)} \n"
257 "F\x00{'descr': '>c16', 'fortran_order': False, 'shape': (3, 5)} \n"
258 "F\x00{'descr': '>c16', 'fortran_order': True, 'shape': (5, 3)} \n"
259 "F\x00{'descr': '>c16', 'fortran_order': False, 'shape': (3, 3)} \n"
260 "F\x00{'descr': 'O', 'fortran_order': False, 'shape': (0,)} \n"
261 "F\x00{'descr': 'O', 'fortran_order': False, 'shape': ()} \n"
262 "F\x00{'descr': 'O', 'fortran_order': False, 'shape': (15,)} \n"
263 "F\x00{'descr': 'O', 'fortran_order': False, 'shape': (3, 5)} \n"
264 "F\x00{'descr': 'O', 'fortran_order': True, 'shape': (5, 3)} \n"
265 "F\x00{'descr': 'O', 'fortran_order': False, 'shape': (3, 3)} \n"
266 "F\x00{'descr': 'O', 'fortran_order': False, 'shape': (0,)} \n"
267 "F\x00{'descr': 'O', 'fortran_order': False, 'shape': ()} \n"
268 "F\x00{'descr': 'O', 'fortran_order': False, 'shape': (15,)} \n"
269 "F\x00{'descr': 'O', 'fortran_order': False, 'shape': (3, 5)} \n"
270 "F\x00{'descr': 'O', 'fortran_order': True, 'shape': (5, 3)} \n"
271 "F\x00{'descr': 'O', 'fortran_order': False, 'shape': (3, 3)} \n"
272 "v\x00{'descr': [('x', '<i4', (2,)), ('y', '<f8', (2, 2)), ('z', '|u1')],\n 'fortran_order': False,\n 'shape': (2,)} \n"
273 "\x16\x02{'descr': [('x', '<i4', (2,)),\n ('Info',\n [('value', '<c16'),\n ('y2', '<f8'),\n ('Info2',\n [('name', '|S2'),\n ('value', '<c16', (2,)),\n ('y3', '<f8', (2,)),\n ('z3', '<u4', (2,))]),\n ('name', '|S2'),\n ('z2', '|b1')]),\n ('color', '|S2'),\n ('info', [('Name', '<U8'), ('Value', '<c16')]),\n ('y', '<f8', (2, 2)),\n ('z', '|u1')],\n 'fortran_order': False,\n 'shape': (2,)} \n"
274 "v\x00{'descr': [('x', '>i4', (2,)), ('y', '>f8', (2, 2)), ('z', '|u1')],\n 'fortran_order': False,\n 'shape': (2,)} \n"
275 "\x16\x02{'descr': [('x', '>i4', (2,)),\n ('Info',\n [('value', '>c16'),\n ('y2', '>f8'),\n ('Info2',\n [('name', '|S2'),\n ('value', '>c16', (2,)),\n ('y3', '>f8', (2,)),\n ('z3', '>u4', (2,))]),\n ('name', '|S2'),\n ('z2', '|b1')]),\n ('color', '|S2'),\n ('info', [('Name', '>U8'), ('Value', '>c16')]),\n ('y', '>f8', (2, 2)),\n ('z', '|u1')],\n 'fortran_order': False,\n 'shape': (2,)} \n"
276'''
277import os
278import sys
279import warnings
280from io import BytesIO
281
282import pytest
283
284import numpy as np
285from numpy.lib import format
286from numpy.testing import (
287 IS_64BIT,
288 IS_PYPY,
289 IS_WASM,
290 assert_,
291 assert_array_equal,
292 assert_raises,
293 assert_raises_regex,
294)
295from numpy.testing._private.utils import requires_memory
296
297# Generate some basic arrays to test with.
298scalars = [
299 np.uint8,
300 np.int8,
301 np.uint16,
302 np.int16,
303 np.uint32,
304 np.int32,
305 np.uint64,
306 np.int64,
307 np.float32,
308 np.float64,
309 np.complex64,
310 np.complex128,
311 object,
312]
313basic_arrays = []
314for scalar in scalars:
315 for endian in '<>':
316 dtype = np.dtype(scalar).newbyteorder(endian)
317 basic = np.arange(1500).astype(dtype)
318 basic_arrays.extend([
319 # Empty
320 np.array([], dtype=dtype),
321 # Rank-0
322 np.array(10, dtype=dtype),
323 # 1-D
324 basic,
325 # 2-D C-contiguous
326 basic.reshape((30, 50)),
327 # 2-D F-contiguous
328 basic.reshape((30, 50)).T,
329 # 2-D non-contiguous
330 basic.reshape((30, 50))[::-1, ::2],
331 ])
332
333# More complicated record arrays.
334# This is the structure of the table used for plain objects:
335#
336# +-+-+-+
337# |x|y|z|
338# +-+-+-+
339
340# Structure of a plain array description:
341Pdescr = [
342 ('x', 'i4', (2,)),
343 ('y', 'f8', (2, 2)),
344 ('z', 'u1')]
345
346# A plain list of tuples with values for testing:
347PbufferT = [
348 # x y z
349 ([3, 2], [[6., 4.], [6., 4.]], 8),
350 ([4, 3], [[7., 5.], [7., 5.]], 9),
351 ]
352
353
354# This is the structure of the table used for nested objects (DON'T PANIC!):
355#
356# +-+---------------------------------+-----+----------+-+-+
357# |x|Info |color|info |y|z|
358# | +-----+--+----------------+----+--+ +----+-----+ | |
359# | |value|y2|Info2 |name|z2| |Name|Value| | |
360# | | | +----+-----+--+--+ | | | | | | |
361# | | | |name|value|y3|z3| | | | | | | |
362# +-+-----+--+----+-----+--+--+----+--+-----+----+-----+-+-+
363#
364
365# The corresponding nested array description:
366Ndescr = [
367 ('x', 'i4', (2,)),
368 ('Info', [
369 ('value', 'c16'),
370 ('y2', 'f8'),
371 ('Info2', [
372 ('name', 'S2'),
373 ('value', 'c16', (2,)),
374 ('y3', 'f8', (2,)),
375 ('z3', 'u4', (2,))]),
376 ('name', 'S2'),
377 ('z2', 'b1')]),
378 ('color', 'S2'),
379 ('info', [
380 ('Name', 'U8'),
381 ('Value', 'c16')]),
382 ('y', 'f8', (2, 2)),
383 ('z', 'u1')]
384
385NbufferT = [
386 ([3, 2], (6j, 6., ('nn', [6j, 4j], [6., 4.], [1, 2]), 'NN', True),
387 'cc', ('NN', 6j), [[6., 4.], [6., 4.]], 8),
388 ([4, 3], (7j, 7., ('oo', [7j, 5j], [7., 5.], [2, 1]), 'OO', False),
389 'dd', ('OO', 7j), [[7., 5.], [7., 5.]], 9),
390 ]
391
392record_arrays = [
393 np.array(PbufferT, dtype=np.dtype(Pdescr).newbyteorder('<')),
394 np.array(NbufferT, dtype=np.dtype(Ndescr).newbyteorder('<')),
395 np.array(PbufferT, dtype=np.dtype(Pdescr).newbyteorder('>')),
396 np.array(NbufferT, dtype=np.dtype(Ndescr).newbyteorder('>')),
397 np.zeros(1, dtype=[('c', ('<f8', (5,)), (2,))])
398]
399
400
401# BytesIO that reads a random number of bytes at a time
402class BytesIOSRandomSize(BytesIO):
403 def read(self, size=None):
404 import random
405 size = random.randint(1, size)
406 return super().read(size)
407
408
409def roundtrip(arr):
410 f = BytesIO()
411 format.write_array(f, arr)
412 f2 = BytesIO(f.getvalue())
413 arr2 = format.read_array(f2, allow_pickle=True)
414 return arr2
415
416
417def roundtrip_randsize(arr):
418 f = BytesIO()
419 format.write_array(f, arr)
420 f2 = BytesIOSRandomSize(f.getvalue())
421 arr2 = format.read_array(f2)
422 return arr2
423
424
425def roundtrip_truncated(arr):
426 f = BytesIO()
427 format.write_array(f, arr)
428 # BytesIO is one byte short
429 f2 = BytesIO(f.getvalue()[0:-1])
430 arr2 = format.read_array(f2)
431 return arr2
432
433def assert_equal_(o1, o2):
434 assert_(o1 == o2)
435
436
437def test_roundtrip():
438 for arr in basic_arrays + record_arrays:
439 arr2 = roundtrip(arr)
440 assert_array_equal(arr, arr2)
441
442
443def test_roundtrip_randsize():
444 for arr in basic_arrays + record_arrays:
445 if arr.dtype != object:
446 arr2 = roundtrip_randsize(arr)
447 assert_array_equal(arr, arr2)
448
449
450def test_roundtrip_truncated():
451 for arr in basic_arrays:
452 if arr.dtype != object:
453 assert_raises(ValueError, roundtrip_truncated, arr)
454
455def test_file_truncated(tmp_path):
456 path = tmp_path / "a.npy"
457 for arr in basic_arrays:
458 if arr.dtype != object:
459 with open(path, 'wb') as f:
460 format.write_array(f, arr)
461 # truncate the file by one byte
462 with open(path, 'rb+') as f:
463 f.seek(-1, os.SEEK_END)
464 f.truncate()
465 with open(path, 'rb') as f:
466 with pytest.raises(
467 ValueError,
468 match=(
469 r"EOF: reading array header, "
470 r"expected (\d+) bytes got (\d+)"
471 ) if arr.size == 0 else (
472 r"Failed to read all data for array\. "
473 r"Expected \(.*?\) = (\d+) elements, "
474 r"could only read (\d+) elements\. "
475 r"\(file seems not fully written\?\)"
476 )
477 ):
478 _ = format.read_array(f)
479
480def test_long_str():
481 # check items larger than internal buffer size, gh-4027
482 long_str_arr = np.ones(1, dtype=np.dtype((str, format.BUFFER_SIZE + 1)))
483 long_str_arr2 = roundtrip(long_str_arr)
484 assert_array_equal(long_str_arr, long_str_arr2)
485
486
487@pytest.mark.skipif(IS_WASM, reason="memmap doesn't work correctly")
488@pytest.mark.slow
489def test_memmap_roundtrip(tmpdir):
490 for i, arr in enumerate(basic_arrays + record_arrays):
491 if arr.dtype.hasobject:
492 # Skip these since they can't be mmap'ed.
493 continue
494 # Write it out normally and through mmap.
495 nfn = os.path.join(tmpdir, f'normal{i}.npy')
496 mfn = os.path.join(tmpdir, f'memmap{i}.npy')
497 with open(nfn, 'wb') as fp:
498 format.write_array(fp, arr)
499
500 fortran_order = (
501 arr.flags.f_contiguous and not arr.flags.c_contiguous)
502 ma = format.open_memmap(mfn, mode='w+', dtype=arr.dtype,
503 shape=arr.shape, fortran_order=fortran_order)
504 ma[...] = arr
505 ma.flush()
506
507 # Check that both of these files' contents are the same.
508 with open(nfn, 'rb') as fp:
509 normal_bytes = fp.read()
510 with open(mfn, 'rb') as fp:
511 memmap_bytes = fp.read()
512 assert_equal_(normal_bytes, memmap_bytes)
513
514 # Check that reading the file using memmap works.
515 ma = format.open_memmap(nfn, mode='r')
516 ma.flush()
517
518
519def test_compressed_roundtrip(tmpdir):
520 arr = np.random.rand(200, 200)
521 npz_file = os.path.join(tmpdir, 'compressed.npz')
522 np.savez_compressed(npz_file, arr=arr)
523 with np.load(npz_file) as npz:
524 arr1 = npz['arr']
525 assert_array_equal(arr, arr1)
526
527
528# aligned
529dt1 = np.dtype('i1, i4, i1', align=True)
530# non-aligned, explicit offsets
531dt2 = np.dtype({'names': ['a', 'b'], 'formats': ['i4', 'i4'],
532 'offsets': [1, 6]})
533# nested struct-in-struct
534dt3 = np.dtype({'names': ['c', 'd'], 'formats': ['i4', dt2]})
535# field with '' name
536dt4 = np.dtype({'names': ['a', '', 'b'], 'formats': ['i4'] * 3})
537# titles
538dt5 = np.dtype({'names': ['a', 'b'], 'formats': ['i4', 'i4'],
539 'offsets': [1, 6], 'titles': ['aa', 'bb']})
540# empty
541dt6 = np.dtype({'names': [], 'formats': [], 'itemsize': 8})
542
543@pytest.mark.parametrize("dt", [dt1, dt2, dt3, dt4, dt5, dt6])
544def test_load_padded_dtype(tmpdir, dt):
545 arr = np.zeros(3, dt)
546 for i in range(3):
547 arr[i] = i + 5
548 npz_file = os.path.join(tmpdir, 'aligned.npz')
549 np.savez(npz_file, arr=arr)
550 with np.load(npz_file) as npz:
551 arr1 = npz['arr']
552 assert_array_equal(arr, arr1)
553
554
555@pytest.mark.skipif(sys.version_info >= (3, 12), reason="see gh-23988")
556@pytest.mark.xfail(IS_WASM, reason="Emscripten NODEFS has a buggy dup")
557def test_python2_python3_interoperability():
558 fname = 'win64python2.npy'
559 path = os.path.join(os.path.dirname(__file__), 'data', fname)
560 with pytest.warns(UserWarning, match="Reading.*this warning\\."):
561 data = np.load(path)
562 assert_array_equal(data, np.ones(2))
563
564
565@pytest.mark.filterwarnings(
566 "ignore:.*align should be passed:numpy.exceptions.VisibleDeprecationWarning")
567def test_pickle_python2_python3():
568 # Test that loading object arrays saved on Python 2 works both on
569 # Python 2 and Python 3 and vice versa
570 data_dir = os.path.join(os.path.dirname(__file__), 'data')
571
572 expected = np.array([None, range, '\u512a\u826f',
573 b'\xe4\xb8\x8d\xe8\x89\xaf'],
574 dtype=object)
575
576 for fname in ['py2-np0-objarr.npy', 'py2-objarr.npy', 'py2-objarr.npz',
577 'py3-objarr.npy', 'py3-objarr.npz']:
578 path = os.path.join(data_dir, fname)
579
580 for encoding in ['bytes', 'latin1']:
581 data_f = np.load(path, allow_pickle=True, encoding=encoding)
582 if fname.endswith('.npz'):
583 data = data_f['x']
584 data_f.close()
585 else:
586 data = data_f
587
588 if encoding == 'latin1' and fname.startswith('py2'):
589 assert_(isinstance(data[3], str))
590 assert_array_equal(data[:-1], expected[:-1])
591 # mojibake occurs
592 assert_array_equal(data[-1].encode(encoding), expected[-1])
593 else:
594 assert_(isinstance(data[3], bytes))
595 assert_array_equal(data, expected)
596
597 if fname.startswith('py2'):
598 if fname.endswith('.npz'):
599 data = np.load(path, allow_pickle=True)
600 assert_raises(UnicodeError, data.__getitem__, 'x')
601 data.close()
602 data = np.load(path, allow_pickle=True, fix_imports=False,
603 encoding='latin1')
604 assert_raises(ImportError, data.__getitem__, 'x')
605 data.close()
606 else:
607 assert_raises(UnicodeError, np.load, path,
608 allow_pickle=True)
609 assert_raises(ImportError, np.load, path,
610 allow_pickle=True, fix_imports=False,
611 encoding='latin1')
612
613
614def test_pickle_disallow(tmpdir):
615 data_dir = os.path.join(os.path.dirname(__file__), 'data')
616
617 path = os.path.join(data_dir, 'py2-objarr.npy')
618 assert_raises(ValueError, np.load, path,
619 allow_pickle=False, encoding='latin1')
620
621 path = os.path.join(data_dir, 'py2-objarr.npz')
622 with np.load(path, allow_pickle=False, encoding='latin1') as f:
623 assert_raises(ValueError, f.__getitem__, 'x')
624
625 path = os.path.join(tmpdir, 'pickle-disabled.npy')
626 assert_raises(ValueError, np.save, path, np.array([None], dtype=object),
627 allow_pickle=False)
628
629@pytest.mark.parametrize('dt', [
630 # Not testing a subarray only dtype, because it cannot be attached to an array
631 # (and would fail the test as of writing this.)
632 np.dtype([('a', np.int8),
633 ('b', np.int16),
634 ('c', np.int32),
635 ], align=True),
636 np.dtype([('x', np.dtype(({'names': ['a', 'b'],
637 'formats': ['i1', 'i1'],
638 'offsets': [0, 4],
639 'itemsize': 8,
640 },
641 (3,))),
642 (4,),
643 )]),
644 np.dtype([('x',
645 ('<f8', (5,)),
646 (2,),
647 )]),
648 np.dtype([('x', np.dtype((
649 np.dtype((
650 np.dtype({'names': ['a', 'b'],
651 'formats': ['i1', 'i1'],
652 'offsets': [0, 4],
653 'itemsize': 8}),
654 (3,)
655 )),
656 (4,)
657 )))
658 ]),
659 np.dtype([
660 ('a', np.dtype((
661 np.dtype((
662 np.dtype((
663 np.dtype([
664 ('a', int),
665 ('b', np.dtype({'names': ['a', 'b'],
666 'formats': ['i1', 'i1'],
667 'offsets': [0, 4],
668 'itemsize': 8})),
669 ]),
670 (3,),
671 )),
672 (4,),
673 )),
674 (5,),
675 )))
676 ]),
677 ])
678def test_descr_to_dtype(dt):
679 dt1 = format.descr_to_dtype(dt.descr)
680 assert_equal_(dt1, dt)
681 arr1 = np.zeros(3, dt)
682 arr2 = roundtrip(arr1)
683 assert_array_equal(arr1, arr2)
684
685def test_version_2_0():
686 f = BytesIO()
687 # requires more than 2 byte for header
688 dt = [(("%d" % i) * 100, float) for i in range(500)]
689 d = np.ones(1000, dtype=dt)
690
691 format.write_array(f, d, version=(2, 0))
692 with warnings.catch_warnings(record=True) as w:
693 warnings.filterwarnings('always', '', UserWarning)
694 format.write_array(f, d)
695 assert_(w[0].category is UserWarning)
696
697 # check alignment of data portion
698 f.seek(0)
699 header = f.readline()
700 assert_(len(header) % format.ARRAY_ALIGN == 0)
701
702 f.seek(0)
703 n = format.read_array(f, max_header_size=200000)
704 assert_array_equal(d, n)
705
706 # 1.0 requested but data cannot be saved this way
707 assert_raises(ValueError, format.write_array, f, d, (1, 0))
708
709
710@pytest.mark.skipif(IS_WASM, reason="memmap doesn't work correctly")
711def test_version_2_0_memmap(tmpdir):
712 # requires more than 2 byte for header
713 dt = [(("%d" % i) * 100, float) for i in range(500)]
714 d = np.ones(1000, dtype=dt)
715 tf1 = os.path.join(tmpdir, 'version2_01.npy')
716 tf2 = os.path.join(tmpdir, 'version2_02.npy')
717
718 # 1.0 requested but data cannot be saved this way
719 assert_raises(ValueError, format.open_memmap, tf1, mode='w+', dtype=d.dtype,
720 shape=d.shape, version=(1, 0))
721
722 ma = format.open_memmap(tf1, mode='w+', dtype=d.dtype,
723 shape=d.shape, version=(2, 0))
724 ma[...] = d
725 ma.flush()
726 ma = format.open_memmap(tf1, mode='r', max_header_size=200000)
727 assert_array_equal(ma, d)
728
729 with warnings.catch_warnings(record=True) as w:
730 warnings.filterwarnings('always', '', UserWarning)
731 ma = format.open_memmap(tf2, mode='w+', dtype=d.dtype,
732 shape=d.shape, version=None)
733 assert_(w[0].category is UserWarning)
734 ma[...] = d
735 ma.flush()
736
737 ma = format.open_memmap(tf2, mode='r', max_header_size=200000)
738
739 assert_array_equal(ma, d)
740
741@pytest.mark.parametrize("mmap_mode", ["r", None])
742def test_huge_header(tmpdir, mmap_mode):
743 f = os.path.join(tmpdir, 'large_header.npy')
744 arr = np.array(1, dtype="i," * 10000 + "i")
745
746 with pytest.warns(UserWarning, match=".*format 2.0"):
747 np.save(f, arr)
748
749 with pytest.raises(ValueError, match="Header.*large"):
750 np.load(f, mmap_mode=mmap_mode)
751
752 with pytest.raises(ValueError, match="Header.*large"):
753 np.load(f, mmap_mode=mmap_mode, max_header_size=20000)
754
755 res = np.load(f, mmap_mode=mmap_mode, allow_pickle=True)
756 assert_array_equal(res, arr)
757
758 res = np.load(f, mmap_mode=mmap_mode, max_header_size=180000)
759 assert_array_equal(res, arr)
760
761def test_huge_header_npz(tmpdir):
762 f = os.path.join(tmpdir, 'large_header.npz')
763 arr = np.array(1, dtype="i," * 10000 + "i")
764
765 with pytest.warns(UserWarning, match=".*format 2.0"):
766 np.savez(f, arr=arr)
767
768 # Only getting the array from the file actually reads it
769 with pytest.raises(ValueError, match="Header.*large"):
770 np.load(f)["arr"]
771
772 with pytest.raises(ValueError, match="Header.*large"):
773 np.load(f, max_header_size=20000)["arr"]
774
775 res = np.load(f, allow_pickle=True)["arr"]
776 assert_array_equal(res, arr)
777
778 res = np.load(f, max_header_size=180000)["arr"]
779 assert_array_equal(res, arr)
780
781def test_write_version():
782 f = BytesIO()
783 arr = np.arange(1)
784 # These should pass.
785 format.write_array(f, arr, version=(1, 0))
786 format.write_array(f, arr)
787
788 format.write_array(f, arr, version=None)
789 format.write_array(f, arr)
790
791 format.write_array(f, arr, version=(2, 0))
792 format.write_array(f, arr)
793
794 # These should all fail.
795 bad_versions = [
796 (1, 1),
797 (0, 0),
798 (0, 1),
799 (2, 2),
800 (255, 255),
801 ]
802 for version in bad_versions:
803 with assert_raises_regex(ValueError,
804 'we only support format version.*'):
805 format.write_array(f, arr, version=version)
806
807
808bad_version_magic = [
809 b'\x93NUMPY\x01\x01',
810 b'\x93NUMPY\x00\x00',
811 b'\x93NUMPY\x00\x01',
812 b'\x93NUMPY\x02\x00',
813 b'\x93NUMPY\x02\x02',
814 b'\x93NUMPY\xff\xff',
815]
816malformed_magic = [
817 b'\x92NUMPY\x01\x00',
818 b'\x00NUMPY\x01\x00',
819 b'\x93numpy\x01\x00',
820 b'\x93MATLB\x01\x00',
821 b'\x93NUMPY\x01',
822 b'\x93NUMPY',
823 b'',
824]
825
826def test_read_magic():
827 s1 = BytesIO()
828 s2 = BytesIO()
829
830 arr = np.ones((3, 6), dtype=float)
831
832 format.write_array(s1, arr, version=(1, 0))
833 format.write_array(s2, arr, version=(2, 0))
834
835 s1.seek(0)
836 s2.seek(0)
837
838 version1 = format.read_magic(s1)
839 version2 = format.read_magic(s2)
840
841 assert_(version1 == (1, 0))
842 assert_(version2 == (2, 0))
843
844 assert_(s1.tell() == format.MAGIC_LEN)
845 assert_(s2.tell() == format.MAGIC_LEN)
846
847def test_read_magic_bad_magic():
848 for magic in malformed_magic:
849 f = BytesIO(magic)
850 assert_raises(ValueError, format.read_array, f)
851
852
853def test_read_version_1_0_bad_magic():
854 for magic in bad_version_magic + malformed_magic:
855 f = BytesIO(magic)
856 assert_raises(ValueError, format.read_array, f)
857
858
859def test_bad_magic_args():
860 assert_raises(ValueError, format.magic, -1, 1)
861 assert_raises(ValueError, format.magic, 256, 1)
862 assert_raises(ValueError, format.magic, 1, -1)
863 assert_raises(ValueError, format.magic, 1, 256)
864
865
866def test_large_header():
867 s = BytesIO()
868 d = {'shape': (), 'fortran_order': False, 'descr': '<i8'}
869 format.write_array_header_1_0(s, d)
870
871 s = BytesIO()
872 d['descr'] = [('x' * 256 * 256, '<i8')]
873 assert_raises(ValueError, format.write_array_header_1_0, s, d)
874
875
876def test_read_array_header_1_0():
877 s = BytesIO()
878
879 arr = np.ones((3, 6), dtype=float)
880 format.write_array(s, arr, version=(1, 0))
881
882 s.seek(format.MAGIC_LEN)
883 shape, fortran, dtype = format.read_array_header_1_0(s)
884
885 assert_(s.tell() % format.ARRAY_ALIGN == 0)
886 assert_((shape, fortran, dtype) == ((3, 6), False, float))
887
888
889def test_read_array_header_2_0():
890 s = BytesIO()
891
892 arr = np.ones((3, 6), dtype=float)
893 format.write_array(s, arr, version=(2, 0))
894
895 s.seek(format.MAGIC_LEN)
896 shape, fortran, dtype = format.read_array_header_2_0(s)
897
898 assert_(s.tell() % format.ARRAY_ALIGN == 0)
899 assert_((shape, fortran, dtype) == ((3, 6), False, float))
900
901
902def test_bad_header():
903 # header of length less than 2 should fail
904 s = BytesIO()
905 assert_raises(ValueError, format.read_array_header_1_0, s)
906 s = BytesIO(b'1')
907 assert_raises(ValueError, format.read_array_header_1_0, s)
908
909 # header shorter than indicated size should fail
910 s = BytesIO(b'\x01\x00')
911 assert_raises(ValueError, format.read_array_header_1_0, s)
912
913 # headers without the exact keys required should fail
914 # d = {"shape": (1, 2),
915 # "descr": "x"}
916 s = BytesIO(
917 b"\x93NUMPY\x01\x006\x00{'descr': 'x', 'shape': (1, 2), }"
918 b" \n"
919 )
920 assert_raises(ValueError, format.read_array_header_1_0, s)
921
922 d = {"shape": (1, 2),
923 "fortran_order": False,
924 "descr": "x",
925 "extrakey": -1}
926 s = BytesIO()
927 format.write_array_header_1_0(s, d)
928 assert_raises(ValueError, format.read_array_header_1_0, s)
929
930
931def test_large_file_support(tmpdir):
932 if (sys.platform == 'win32' or sys.platform == 'cygwin'):
933 pytest.skip("Unknown if Windows has sparse filesystems")
934 # try creating a large sparse file
935 tf_name = os.path.join(tmpdir, 'sparse_file')
936 try:
937 # seek past end would work too, but linux truncate somewhat
938 # increases the chances that we have a sparse filesystem and can
939 # avoid actually writing 5GB
940 import subprocess as sp
941 sp.check_call(["truncate", "-s", "5368709120", tf_name])
942 except Exception:
943 pytest.skip("Could not create 5GB large file")
944 # write a small array to the end
945 with open(tf_name, "wb") as f:
946 f.seek(5368709120)
947 d = np.arange(5)
948 np.save(f, d)
949 # read it back
950 with open(tf_name, "rb") as f:
951 f.seek(5368709120)
952 r = np.load(f)
953 assert_array_equal(r, d)
954
955
956@pytest.mark.skipif(IS_PYPY, reason="flaky on PyPy")
957@pytest.mark.skipif(not IS_64BIT, reason="test requires 64-bit system")
958@pytest.mark.slow
959@requires_memory(free_bytes=2 * 2**30)
960@pytest.mark.thread_unsafe(reason="crashes with low memory")
961def test_large_archive(tmpdir):
962 # Regression test for product of saving arrays with dimensions of array
963 # having a product that doesn't fit in int32. See gh-7598 for details.
964 shape = (2**30, 2)
965 try:
966 a = np.empty(shape, dtype=np.uint8)
967 except MemoryError:
968 pytest.skip("Could not create large file")
969
970 fname = os.path.join(tmpdir, "large_archive")
971
972 with open(fname, "wb") as f:
973 np.savez(f, arr=a)
974
975 del a
976
977 with open(fname, "rb") as f:
978 new_a = np.load(f)["arr"]
979
980 assert new_a.shape == shape
981
982
983def test_empty_npz(tmpdir):
984 # Test for gh-9989
985 fname = os.path.join(tmpdir, "nothing.npz")
986 np.savez(fname)
987 with np.load(fname) as nps:
988 pass
989
990
991def test_unicode_field_names(tmpdir):
992 # gh-7391
993 arr = np.array([
994 (1, 3),
995 (1, 2),
996 (1, 3),
997 (1, 2)
998 ], dtype=[
999 ('int', int),
1000 ('\N{CJK UNIFIED IDEOGRAPH-6574}\N{CJK UNIFIED IDEOGRAPH-5F62}', int)
1001 ])
1002 fname = os.path.join(tmpdir, "unicode.npy")
1003 with open(fname, 'wb') as f:
1004 format.write_array(f, arr, version=(3, 0))
1005 with open(fname, 'rb') as f:
1006 arr2 = format.read_array(f)
1007 assert_array_equal(arr, arr2)
1008
1009 # notifies the user that 3.0 is selected
1010 with open(fname, 'wb') as f:
1011 with pytest.warns(UserWarning):
1012 format.write_array(f, arr, version=None)
1013
1014def test_header_growth_axis():
1015 for is_fortran_array, dtype_space, expected_header_length in [
1016 [False, 22, 128], [False, 23, 192], [True, 23, 128], [True, 24, 192]
1017 ]:
1018 for size in [10**i for i in range(format.GROWTH_AXIS_MAX_DIGITS)]:
1019 fp = BytesIO()
1020 format.write_array_header_1_0(fp, {
1021 'shape': (2, size) if is_fortran_array else (size, 2),
1022 'fortran_order': is_fortran_array,
1023 'descr': np.dtype([(' ' * dtype_space, int)])
1024 })
1025
1026 assert len(fp.getvalue()) == expected_header_length
1027
1028@pytest.mark.parametrize('dt', [
1029 np.dtype({'names': ['a', 'b'], 'formats': [float, np.dtype('S3',
1030 metadata={'some': 'stuff'})]}),
1031 np.dtype(int, metadata={'some': 'stuff'}),
1032 np.dtype([('subarray', (int, (2,)))], metadata={'some': 'stuff'}),
1033 # recursive: metadata on the field of a dtype
1034 np.dtype({'names': ['a', 'b'], 'formats': [
1035 float, np.dtype({'names': ['c'], 'formats': [np.dtype(int, metadata={})]})
1036 ]}),
1037 ])
1038@pytest.mark.skipif(IS_PYPY and sys.implementation.version <= (7, 3, 8),
1039 reason="PyPy bug in error formatting")
1040def test_metadata_dtype(dt):
1041 # gh-14142
1042 arr = np.ones(10, dtype=dt)
1043 buf = BytesIO()
1044 with pytest.warns(UserWarning):
1045 np.save(buf, arr)
1046 buf.seek(0)
1047
1048 # Loading should work (metadata was stripped):
1049 arr2 = np.load(buf)
1050 # BUG: assert_array_equal does not check metadata
1051 from numpy.lib._utils_impl import drop_metadata
1052 assert_array_equal(arr, arr2)
1053 assert drop_metadata(arr.dtype) is not arr.dtype
1054 assert drop_metadata(arr2.dtype) is arr2.dtype
1055 