Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
test_format.py1055 linesDownload Raw Back to tests
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 
codekingpro/portable-devtools · Team Ai