summaryrefslogtreecommitdiff
path: root/numpy/lib
diff options
context:
space:
mode:
authormattip <matti.picus@gmail.com>2018-11-09 14:28:44 -0800
committermattip <matti.picus@gmail.com>2018-11-13 06:38:22 -0800
commit1956ada852f950468e028cf108766e089f4575cc (patch)
tree3e048aa1f1f6aa985c0004ae38f48f9745701477 /numpy/lib
parentcd39348e8593dc2b41e2516fbdd8a69b0f0bda6e (diff)
downloadnumpy-1956ada852f950468e028cf108766e089f4575cc.tar.gz
BUG: test, fix loading structured dtypes with padding
Diffstat (limited to 'numpy/lib')
-rw-r--r--numpy/lib/format.py30
-rw-r--r--numpy/lib/tests/test_format.py21
2 files changed, 49 insertions, 2 deletions
diff --git a/numpy/lib/format.py b/numpy/lib/format.py
index 1ef3dca47..ad26cf46a 100644
--- a/numpy/lib/format.py
+++ b/numpy/lib/format.py
@@ -259,6 +259,33 @@ def dtype_to_descr(dtype):
else:
return dtype.str
+def descr_to_dtype(descr):
+ if isinstance(descr, str):
+ # descr was produced by dtype.str, so this always works
+ return numpy.dtype(descr)
+
+ fields = []
+ offset = 0
+ for field in descr:
+ if len(field) == 2:
+ name, descr_str = field
+ dt = descr_to_dtype(descr_str)
+ else:
+ name, descr_str, shape = field
+ dt = numpy.dtype((descr_to_dtype(descr_str), shape))
+
+ # ignore padding bytes, which will be void bytes with '' as name
+ # (once blank fieldnames are deprecated, only "if name == ''" needed)
+ is_pad = (name == '' and dt.type is numpy.void and dt.names is None)
+ if not is_pad:
+ fields.append((name, dt, offset))
+
+ offset += dt.itemsize
+
+ names, formats, offsets = zip(*fields)
+ return numpy.dtype({'names': names, 'formats': formats,
+ 'offsets': offsets, 'itemsize': offset})
+
def header_data_from_array_1_0(array):
""" Get the dictionary of header metadata from a numpy.ndarray.
@@ -523,7 +550,8 @@ def _read_array_header(fp, version):
msg = "fortran_order is not a valid bool: %r"
raise ValueError(msg % (d['fortran_order'],))
try:
- dtype = numpy.dtype(d['descr'])
+ descr = descr_to_dtype(d['descr'])
+ dtype = numpy.dtype(descr)
except TypeError as e:
msg = "descr is not a valid dtype descriptor: %r"
raise ValueError(msg % (d['descr'],))
diff --git a/numpy/lib/tests/test_format.py b/numpy/lib/tests/test_format.py
index 3185e32ac..13a12197c 100644
--- a/numpy/lib/tests/test_format.py
+++ b/numpy/lib/tests/test_format.py
@@ -524,6 +524,26 @@ def test_compressed_roundtrip():
assert_array_equal(arr, arr1)
+# aligned
+dt1 = np.dtype('i1, i4, i1', align=True)
+# non-aligned, explicit offsets
+dt2 = np.dtype({'names': ['a', 'b'], 'formats': ['i4', 'i4'],
+ 'offsets': [1, 6]})
+# nested struct-in-struct
+dt3 = np.dtype({'names': ['c', 'd'], 'formats': ['i4', dt2]})
+# field with '' name
+dt4 = np.dtype({'names': ['a', '', 'b'], 'formats': ['i4']*3})
+@pytest.mark.parametrize("dt", [dt1, dt2, dt3, dt4])
+def test_load_padded_dtype(dt):
+ arr = np.zeros(3, dt)
+ for i in range(3):
+ arr[i] = i + 5
+ npz_file = os.path.join(tempdir, 'aligned.npz')
+ np.savez(npz_file, arr=arr)
+ arr1 = np.load(npz_file)['arr']
+ assert_array_equal(arr, arr1)
+
+
def test_python2_python3_interoperability():
if sys.version_info[0] >= 3:
fname = 'win64python2.npy'
@@ -533,7 +553,6 @@ def test_python2_python3_interoperability():
data = np.load(path)
assert_array_equal(data, np.ones(2))
-
def test_pickle_python2_python3():
# Test that loading object arrays saved on Python 2 works both on
# Python 2 and Python 3 and vice versa