""" Conversion from ctypes to dtype.
In an ideal world, we could acheive this through the PEP3118 buffer protocol, something like::
def dtype_from_ctypes_type(t): # needed to ensure that the shape of `t` is within memoryview.format class DummyStruct(ctypes.Structure): _fields_ = [('a', t)]
# empty to avoid memory allocation ctype_0 = (DummyStruct * 0)() mv = memoryview(ctype_0)
# convert the struct, and slice back out the field return _dtype_from_pep3118(mv.format)['a']
Unfortunately, this fails because:
* ctypes cannot handle length-0 arrays with PEP3118 (bpo-32782) * PEP3118 cannot represent unions, but both numpy and ctypes can * ctypes cannot handle big-endian structs with PEP3118 (bpo-32780) """
return np.dtype((dtype_from_ctypes_type(t._type_), (t._length_,)))
for item in t._fields_: if len(item) > 2: raise TypeError( "ctypes bitfields have no dtype equivalent")
if hasattr(t, "_pack_"): formats = [] offsets = [] names = [] current_offset = 0 for fname, ftyp in t._fields_: names.append(fname) formats.append(dtype_from_ctypes_type(ftyp)) # Each type has a default offset, this is platform dependent for some types. effective_pack = min(t._pack_, ctypes.alignment(ftyp)) current_offset = ((current_offset + effective_pack - 1) // effective_pack) * effective_pack offsets.append(current_offset) current_offset += ctypes.sizeof(ftyp)
return np.dtype(dict( formats=formats, offsets=offsets, names=names, itemsize=ctypes.sizeof(t))) else: fields = [] for fname, ftyp in t._fields_: fields.append((fname, dtype_from_ctypes_type(ftyp)))
# by default, ctypes structs are aligned return np.dtype(fields, align=True)
""" Return the dtype type with endianness included if it's the case """ else:
formats = [] offsets = [] names = [] for fname, ftyp in t._fields_: names.append(fname) formats.append(dtype_from_ctypes_type(ftyp)) offsets.append(0) # Union fields are offset to 0
return np.dtype(dict( formats=formats, offsets=offsets, names=names, itemsize=ctypes.sizeof(t)))
""" Construct a dtype object from a ctypes type """ return _from_ctypes_array(t) raise TypeError("ctypes pointers have no dtype equivalent") return _from_ctypes_structure(t) return _from_ctypes_union(t) else: raise NotImplementedError( "Unknown ctypes type {}".format(t.__name__)) |