Author: Brian Kearns <bdkea...@gmail.com> Branch: Changeset: r68021:a80ac0e94c7e Date: 2013-11-14 03:30 -0500 http://bitbucket.org/pypy/pypy/changeset/a80ac0e94c7e/
Log: merge numpy-newbyteorder diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -52,7 +52,7 @@ loop.setslice(space, shape, self, impl) def get_size(self): - return self.size // self.dtype.itemtype.get_element_size() + return self.size // self.dtype.get_size() def get_storage_size(self): return self.size @@ -399,7 +399,7 @@ self.storage = parent.storage self.order = parent.order self.dtype = dtype - self.size = support.product(shape) * self.dtype.itemtype.get_element_size() + self.size = support.product(shape) * self.dtype.get_size() self.start = start self.orig_arr = orig_arr diff --git a/pypy/module/micronumpy/conversion_utils.py b/pypy/module/micronumpy/conversion_utils.py --- a/pypy/module/micronumpy/conversion_utils.py +++ b/pypy/module/micronumpy/conversion_utils.py @@ -1,6 +1,27 @@ from pypy.interpreter.error import OperationError from pypy.module.micronumpy.constants import * + +def byteorder_converter(space, new_order): + endian = new_order[0] + if endian not in (NPY_BIG, NPY_LITTLE, NPY_NATIVE, NPY_IGNORE, NPY_SWAP): + ch = endian + if ch in ('b', 'B'): + endian = NPY_BIG + elif ch in ('l', 'L'): + endian = NPY_LITTLE + elif ch in ('n', 'N'): + endian = NPY_NATIVE + elif ch in ('i', 'I'): + endian = NPY_IGNORE + elif ch in ('s', 'S'): + endian = NPY_SWAP + else: + raise OperationError(space.w_ValueError, space.wrap( + "%s is an unrecognized byteorder" % new_order)) + return endian + + def clipmode_converter(space, w_mode): if space.is_none(w_mode): return NPY_RAISE @@ -19,6 +40,7 @@ raise OperationError(space.w_TypeError, space.wrap("clipmode not understood")) + def order_converter(space, w_order, default): if space.is_none(w_order): return default @@ -41,6 +63,7 @@ raise OperationError(space.w_TypeError, space.wrap( "order not understood")) + def multi_axis_converter(space, w_axis, ndim): if space.is_none(w_axis): return [True] * ndim diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -9,6 +9,7 @@ from rpython.rlib.rarithmetic import LONG_BIT, r_longlong, r_ulonglong from rpython.rtyper.lltypesystem import rffi from rpython.rlib import jit +from pypy.module.micronumpy.conversion_utils import byteorder_converter from pypy.module.micronumpy.constants import * @@ -34,10 +35,12 @@ return out class W_Dtype(W_Root): - _immutable_fields_ = ["itemtype?", "num", "kind", "name?", "char", "w_box_type", "byteorder", "float_type"] + _immutable_fields_ = ["itemtype?", "num", "kind", "name?", "char", + "w_box_type", "byteorder", "size?", "float_type", + "fields?", "fieldnames?", "shape", "subdtype", "base"] def __init__(self, itemtype, num, kind, name, char, w_box_type, byteorder=NPY_NATIVE, - alternate_constructors=[], aliases=[], float_type=None, + size=1, alternate_constructors=[], aliases=[], float_type=None, fields=None, fieldnames=None, shape=[], subdtype=None): self.itemtype = itemtype self.num = num @@ -46,6 +49,7 @@ self.char = char self.w_box_type = w_box_type self.byteorder = byteorder + self.size = size self.alternate_constructors = alternate_constructors self.aliases = aliases self.float_type = float_type @@ -122,7 +126,7 @@ return self.byteorder in (NPY_NATIVE, NPY_NATBYTE) def get_size(self): - return self.itemtype.get_element_size() + return self.size * self.itemtype.get_element_size() def get_name(self): if self.char == 'S': @@ -136,7 +140,7 @@ return space.wrap("dtype('%s')" % self.get_name()) def descr_get_itemsize(self, space): - return space.wrap(self.itemtype.get_element_size()) + return space.wrap(self.get_size()) def descr_get_alignment(self, space): return space.wrap(self.itemtype.alignment) @@ -196,7 +200,6 @@ self.fields = None else: self.fields = {} - ofs_and_items = [] size = 0 for key in space.listview(w_fields): value = space.getitem(w_fields, key) @@ -207,11 +210,11 @@ offset = space.int_w(space.getitem(value, space.wrap(1))) self.fields[space.str_w(key)] = offset, dtype - ofs_and_items.append((offset, dtype.itemtype)) - size += dtype.itemtype.get_element_size() + size += dtype.get_size() - self.itemtype = types.RecordType(ofs_and_items, size) - self.name = "void" + str(8 * self.itemtype.get_element_size()) + self.itemtype = types.RecordType() + self.size = size + self.name = "void" + str(8 * self.get_size()) def descr_get_names(self, space): if self.fieldnames is None: @@ -263,7 +266,7 @@ w_class = space.type(self) kind = self.kind - elemsize = self.itemtype.get_element_size() + elemsize = self.get_size() builder_args = space.newtuple([space.wrap("%s%d" % (kind, elemsize)), space.wrap(0), space.wrap(1)]) version = space.wrap(3) @@ -308,11 +311,23 @@ fields = space.getitem(w_data, space.wrap(4)) self.set_fields(space, fields) + @unwrap_spec(new_order=str) + def descr_newbyteorder(self, space, new_order=NPY_SWAP): + newendian = byteorder_converter(space, new_order) + endian = self.byteorder + if endian != NPY_IGNORE: + if newendian == NPY_SWAP: + endian = NPY_OPPBYTE if self.is_native() else NPY_NATBYTE + elif newendian != NPY_IGNORE: + endian = newendian + itemtype = self.itemtype.__class__(endian in (NPY_NATIVE, NPY_NATBYTE)) + return W_Dtype(itemtype, self.num, self.kind, self.name, self.char, + self.w_box_type, endian, size=self.size) + def dtype_from_list(space, w_lst): lst_w = space.listview(w_lst) fields = {} offset = 0 - ofs_and_items = [] fieldnames = [] for w_elem in lst_w: size = 1 @@ -329,13 +344,13 @@ raise OperationError(space.w_ValueError, space.wrap("two fields with the same name")) assert isinstance(subdtype, W_Dtype) fields[fldname] = (offset, subdtype) - ofs_and_items.append((offset, subdtype.itemtype)) - offset += subdtype.itemtype.get_element_size() * size + offset += subdtype.get_size() * size fieldnames.append(fldname) - itemtype = types.RecordType(ofs_and_items, offset) - return W_Dtype(itemtype, NPY_VOID, NPY_VOIDLTR, "void" + str(8 * itemtype.get_element_size()), - NPY_VOIDLTR, space.gettypefor(interp_boxes.W_VoidBox), fields=fields, - fieldnames=fieldnames) + itemtype = types.RecordType() + return W_Dtype(itemtype, NPY_VOID, NPY_VOIDLTR, + "void" + str(8 * offset * itemtype.get_element_size()), + NPY_VOIDLTR, space.gettypefor(interp_boxes.W_VoidBox), + fields=fields, fieldnames=fieldnames, size=offset) def dtype_from_dict(space, w_dict): raise OperationError(space.w_NotImplementedError, space.wrap( @@ -349,7 +364,8 @@ # w_align and w_copy are necessary for pickling cache = get_dtype_cache(space) - if w_shape is not None and (space.isinstance_w(w_shape, space.w_int) or space.len_w(w_shape) > 0): + if w_shape is not None and (space.isinstance_w(w_shape, space.w_int) or + space.len_w(w_shape) > 0): subdtype = descr__new__(space, w_subtype, w_dtype, w_align, w_copy) assert isinstance(subdtype, W_Dtype) size = 1 @@ -360,8 +376,11 @@ dim = space.int_w(w_dim) shape.append(dim) size *= dim - return W_Dtype(types.VoidType(subdtype.itemtype.get_element_size() * size), NPY_VOID, NPY_VOIDLTR, "void" + str(8 * subdtype.itemtype.get_element_size() * size), - NPY_VOIDLTR, space.gettypefor(interp_boxes.W_VoidBox), shape=shape, subdtype=subdtype) + return W_Dtype(types.VoidType(), NPY_VOID, NPY_VOIDLTR, + "void" + str(8 * subdtype.get_size() * size), + NPY_VOIDLTR, space.gettypefor(interp_boxes.W_VoidBox), + shape=shape, subdtype=subdtype, + size=subdtype.get_size() * size) if space.is_none(w_dtype): return cache.w_float64dtype @@ -413,6 +432,7 @@ __reduce__ = interp2app(W_Dtype.descr_reduce), __setstate__ = interp2app(W_Dtype.descr_setstate), + newbyteorder = interp2app(W_Dtype.descr_newbyteorder), type = interp_attrproperty_w("w_box_type", cls=W_Dtype), kind = interp_attrproperty("kind", cls=W_Dtype), @@ -450,17 +470,17 @@ size = 1 if char == NPY_STRINGLTR: - itemtype = types.StringType(size) + itemtype = types.StringType() basename = 'string' num = NPY_STRING w_box_type = space.gettypefor(interp_boxes.W_StringBox) elif char == NPY_VOIDLTR: - itemtype = types.VoidType(size) + itemtype = types.VoidType() basename = 'void' num = NPY_VOID w_box_type = space.gettypefor(interp_boxes.W_VoidBox) elif char == NPY_UNICODELTR: - itemtype = types.UnicodeType(size) + itemtype = types.UnicodeType() basename = 'unicode' num = NPY_UNICODE w_box_type = space.gettypefor(interp_boxes.W_UnicodeBox) @@ -468,27 +488,29 @@ assert False return W_Dtype(itemtype, num, char, - basename + str(8 * itemtype.get_element_size()), - char, w_box_type) + basename + str(8 * size * itemtype.get_element_size()), + char, w_box_type, size=size) def new_string_dtype(space, size): - itemtype = types.StringType(size) + itemtype = types.StringType() return W_Dtype( itemtype, + size=size, num=NPY_STRING, kind=NPY_STRINGLTR, - name='string' + str(8 * itemtype.get_element_size()), + name='string' + str(8 * size * itemtype.get_element_size()), char=NPY_STRINGLTR, w_box_type = space.gettypefor(interp_boxes.W_StringBox), ) def new_unicode_dtype(space, size): - itemtype = types.UnicodeType(size) + itemtype = types.UnicodeType() return W_Dtype( itemtype, + size=size, num=NPY_UNICODE, kind=NPY_UNICODELTR, - name='unicode' + str(8 * itemtype.get_element_size()), + name='unicode' + str(8 * size * itemtype.get_element_size()), char=NPY_UNICODELTR, w_box_type = space.gettypefor(interp_boxes.W_UnicodeBox), ) @@ -663,7 +685,8 @@ float_type = self.w_floatlongdtype, ) self.w_stringdtype = W_Dtype( - types.StringType(0), + types.StringType(), + size=0, num=NPY_STRING, kind=NPY_STRINGLTR, name='string', @@ -673,7 +696,8 @@ aliases=["str"], ) self.w_unicodedtype = W_Dtype( - types.UnicodeType(0), + types.UnicodeType(), + size=0, num=NPY_UNICODE, kind=NPY_UNICODELTR, name='unicode', @@ -682,7 +706,8 @@ alternate_constructors=[space.w_unicode], ) self.w_voiddtype = W_Dtype( - types.VoidType(0), + types.VoidType(), + size=0, num=NPY_VOID, kind=NPY_VOIDLTR, name='void', @@ -750,7 +775,7 @@ self.w_intpdtype, self.w_uintpdtype, ] self.float_dtypes_by_num_bytes = sorted( - (dtype.itemtype.get_element_size(), dtype) + (dtype.get_size(), dtype) for dtype in float_dtypes ) self.dtypes_by_num = {} @@ -760,7 +785,7 @@ for dtype in reversed(self.builtin_dtypes): self.dtypes_by_num[dtype.num] = dtype self.dtypes_by_name[dtype.name] = dtype - can_name = dtype.kind + str(dtype.itemtype.get_element_size()) + can_name = dtype.kind + str(dtype.get_size()) self.dtypes_by_name[can_name] = dtype self.dtypes_by_name[NPY_NATBYTE + can_name] = dtype self.dtypes_by_name[NPY_NATIVE + can_name] = dtype @@ -830,7 +855,7 @@ for k, v in typeinfo_partial.iteritems(): space.setitem(w_typeinfo, space.wrap(k), space.gettypefor(v)) for k, dtype in typeinfo_full.iteritems(): - itemsize = dtype.itemtype.get_element_size() + itemsize = dtype.get_size() items_w = [space.wrap(dtype.char), space.wrap(dtype.num), space.wrap(itemsize * 8), # in case of changing diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -85,10 +85,10 @@ return space.wrap(len(self.get_shape())) def descr_get_itemsize(self, space): - return space.wrap(self.get_dtype().itemtype.get_element_size()) + return space.wrap(self.get_dtype().get_size()) def descr_get_nbytes(self, space): - return space.wrap(self.get_size() * self.get_dtype().itemtype.get_element_size()) + return space.wrap(self.get_size() * self.get_dtype().get_size()) def descr_fill(self, space, w_value): self.fill(self.get_dtype().coerce(space, w_value)) @@ -625,10 +625,10 @@ raise OperationError(space.w_NotImplementedError, space.wrap( "itemset not implemented yet")) - @unwrap_spec(neworder=str) - def descr_newbyteorder(self, space, neworder): - raise OperationError(space.w_NotImplementedError, space.wrap( - "newbyteorder not implemented yet")) + @unwrap_spec(new_order=str) + def descr_newbyteorder(self, space, new_order=NPY_SWAP): + return self.descr_view(space, + self.get_dtype().descr_newbyteorder(space, new_order)) @unwrap_spec(w_axis=WrappedDefault(None), w_out=WrappedDefault(None)) @@ -1268,6 +1268,7 @@ diagonal = interp2app(W_NDimArray.descr_diagonal), trace = interp2app(W_NDimArray.descr_trace), view = interp2app(W_NDimArray.descr_view), + newbyteorder = interp2app(W_NDimArray.descr_newbyteorder), ctypes = GetSetProperty(W_NDimArray.descr_get_ctypes), # XXX unimplemented __array_interface__ = GetSetProperty(W_NDimArray.descr_array_iface), @@ -1340,7 +1341,7 @@ # not an array or incorrect dtype shape, elems_w = find_shape_and_elems(space, w_object, dtype) if dtype is None or ( - dtype.is_str_or_unicode() and dtype.itemtype.get_size() < 1): + dtype.is_str_or_unicode() and dtype.get_size() < 1): for w_elem in elems_w: dtype = interp_ufuncs.find_dtype_for_scalar(space, w_elem, dtype) @@ -1349,7 +1350,7 @@ if dtype is None: dtype = interp_dtype.get_dtype_cache(space).w_float64dtype - if dtype.is_str_or_unicode() and dtype.itemtype.get_size() < 1: + if dtype.is_str_or_unicode() and dtype.get_size() < 1: # promote S0 -> S1, U0 -> U1 dtype = interp_dtype.variable_dtype(space, dtype.char + '1') if ndmin > len(shape): diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -475,8 +475,7 @@ if dt2.is_record_type(): return dt2 if dt1.is_str_or_unicode(): - if dt2.itemtype.get_element_size() >= \ - dt1.itemtype.get_element_size(): + if dt2.get_size() >= dt1.get_size(): return dt2 return dt1 return dt2 @@ -556,7 +555,7 @@ return interp_dtype.variable_dtype(space, 'S%d' % space.len_w(w_obj)) elif current_guess.num == NPY_STRING: - if current_guess.itemtype.get_size() < space.len_w(w_obj): + if current_guess.get_size() < space.len_w(w_obj): return interp_dtype.variable_dtype(space, 'S%d' % space.len_w(w_obj)) return current_guess diff --git a/pypy/module/micronumpy/iter.py b/pypy/module/micronumpy/iter.py --- a/pypy/module/micronumpy/iter.py +++ b/pypy/module/micronumpy/iter.py @@ -164,7 +164,7 @@ self.array = array self.offset = 0 self.dtype = array.dtype - self.skip = self.dtype.itemtype.get_element_size() + self.skip = self.dtype.get_size() self.size = array.size def setitem(self, elem): diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -288,6 +288,49 @@ assert a.dtype.__reduce__() == (dtype, ('i4', 0, 1), (3, '<', None, None, None, -1, -1, 0)) assert loads(dumps(a.dtype)) == a.dtype + def test_newbyteorder(self): + import numpypy as np + import sys + sys_is_le = sys.byteorder == 'little' + native_code = sys_is_le and '<' or '>' + swapped_code = sys_is_le and '>' or '<' + native_dt = np.dtype(native_code+'i2') + swapped_dt = np.dtype(swapped_code+'i2') + assert native_dt.newbyteorder('S') == swapped_dt + assert native_dt.newbyteorder() == swapped_dt + assert native_dt == swapped_dt.newbyteorder('S') + assert native_dt == swapped_dt.newbyteorder('=') + assert native_dt == swapped_dt.newbyteorder('N') + assert native_dt == native_dt.newbyteorder('|') + assert np.dtype('<i2') == native_dt.newbyteorder('<') + assert np.dtype('<i2') == native_dt.newbyteorder('L') + assert np.dtype('>i2') == native_dt.newbyteorder('>') + assert np.dtype('>i2') == native_dt.newbyteorder('B') + + for t in [np.int_, np.float_]: + dt = np.dtype(t) + dt1 = dt.newbyteorder().newbyteorder() + dt2 = dt.newbyteorder("<") + dt3 = dt.newbyteorder(">") + assert dt.byteorder != dt1.byteorder + #assert hash(dt) == hash(dt1) + if dt == dt2: + assert dt.byteorder != dt2.byteorder + #assert hash(dt) == hash(dt2) + else: + assert dt.byteorder != dt3.byteorder + #assert hash(dt) == hash(dt3) + + exc = raises(ValueError, dt.newbyteorder, 'XX') + assert exc.value[0] == 'XX is an unrecognized byteorder' + + for t in [np.int_, np.float_]: + dt1 = np.dtype(t) + dt2 = dt1.newbyteorder() + s1 = np.array(123, dtype=dt1).tostring() + s2 = np.array(123, dtype=dt2).byteswap().tostring() + assert s1 == s2 + class AppTestTypes(BaseAppTestDtypes): def test_abstract_types(self): import numpypy as numpy diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -2928,6 +2928,15 @@ assert str(a.dtype) == '|S1' assert a == 'x' + def test_newbyteorder(self): + import numpy as np + a = np.array([1, 2], dtype=np.int16) + b = a.newbyteorder() + assert (b == [256, 512]).all() + c = b.byteswap() + assert (c == [1, 2]).all() + assert (a == [1, 2]).all() + def test_pickle(self): from numpypy import dtype, array from cPickle import loads, dumps diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -1591,17 +1591,8 @@ ComponentBoxType = interp_boxes.W_FloatLongBox class BaseStringType(BaseType): - _immutable_fields = ['size'] - - def __init__(self, size=0): - BaseType.__init__(self) - self.size = size - def get_element_size(self): - return self.size * rffi.sizeof(self.T) - - def get_size(self): - return self.size + return rffi.sizeof(self.T) def str_unary_op(func): specialize.argtype(1)(func) @@ -1636,13 +1627,13 @@ def store(self, arr, i, offset, box): assert isinstance(box, interp_boxes.W_StringBox) - return self._store(arr.storage, i, offset, box) + size = min(arr.dtype.size, box.arr.size - box.ofs) + return self._store(arr.storage, i, offset, box, size) @jit.unroll_safe - def _store(self, storage, i, offset, box): + def _store(self, storage, i, offset, box, size): assert isinstance(box, interp_boxes.W_StringBox) - # XXX simplify to range(box.dtype.get_size()) ? - for k in range(min(self.size, box.arr.size-box.ofs)): + for k in range(size): storage[k + offset + i] = box.arr.storage[k + box.ofs] def read(self, arr, i, offset, dtype=None): @@ -1725,17 +1716,17 @@ else: w_arg = box.descr_str(space) arg = space.str_w(space.str(w_arg)) - arr = VoidBoxStorage(self.size, mydtype) + arr = VoidBoxStorage(mydtype.size, mydtype) i = 0 - for i in range(min(len(arg), self.size)): + for i in range(min(len(arg), mydtype.size)): arr.storage[i] = arg[i] - for j in range(i + 1, self.size): + for j in range(i + 1, mydtype.size): arr.storage[j] = '\x00' - return interp_boxes.W_StringBox(arr, 0, arr.dtype) + return interp_boxes.W_StringBox(arr, 0, arr.dtype) def fill(self, storage, width, box, start, stop, offset): for i in xrange(start, stop, width): - self._store(storage, i, offset, box) + self._store(storage, i, offset, box, width) class UnicodeType(BaseStringType): T = lltype.UniChar @@ -1772,14 +1763,14 @@ ofs += size def coerce(self, space, dtype, w_items): - arr = VoidBoxStorage(self.size, dtype) + arr = VoidBoxStorage(dtype.get_size(), dtype) self._coerce(space, arr, 0, dtype, w_items, dtype.shape) return interp_boxes.W_VoidBox(arr, 0, dtype) @jit.unroll_safe def store(self, arr, i, ofs, box): assert isinstance(box, interp_boxes.W_VoidBox) - for k in range(self.get_element_size()): + for k in range(box.arr.dtype.get_size()): arr.storage[k + ofs] = box.arr.storage[k + box.ofs] def readarray(self, arr, i, offset, dtype=None): @@ -1793,15 +1784,9 @@ class RecordType(BaseType): T = lltype.Char - _immutable_fields_ = ['offsets_and_fields', 'size'] - - def __init__(self, offsets_and_fields, size): - BaseType.__init__(self) - self.offsets_and_fields = offsets_and_fields - self.size = size def get_element_size(self): - return self.size + return rffi.sizeof(self.T) def read(self, arr, i, offset, dtype=None): if dtype is None: @@ -1817,14 +1802,14 @@ if not space.issequence_w(w_item): raise OperationError(space.w_TypeError, space.wrap( "expected sequence")) - if len(self.offsets_and_fields) != space.len_w(w_item): + if len(dtype.fields) != space.len_w(w_item): raise OperationError(space.w_ValueError, space.wrap( "wrong length")) items_w = space.fixedview(w_item) - arr = VoidBoxStorage(self.size, dtype) + arr = VoidBoxStorage(dtype.get_size(), dtype) for i in range(len(items_w)): - subdtype = dtype.fields[dtype.fieldnames[i]][1] - ofs, itemtype = self.offsets_and_fields[i] + ofs, subdtype = dtype.fields[dtype.fieldnames[i]] + itemtype = subdtype.itemtype w_item = items_w[i] w_box = itemtype.coerce(space, subdtype, w_item) itemtype.store(arr, 0, ofs, w_box) @@ -1833,7 +1818,7 @@ @jit.unroll_safe def store(self, arr, i, ofs, box): assert isinstance(box, interp_boxes.W_VoidBox) - for k in range(self.get_element_size()): + for k in range(box.arr.dtype.get_size()): arr.storage[k + i] = box.arr.storage[k + box.ofs] @jit.unroll_safe @@ -1841,7 +1826,9 @@ assert isinstance(box, interp_boxes.W_VoidBox) pieces = ["("] first = True - for ofs, tp in self.offsets_and_fields: + for name in box.dtype.fieldnames: + ofs, subdtype = box.dtype.fields[name] + tp = subdtype.itemtype if first: first = False else: _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit