Coverage for numpy\core\_dtype_ctypes.py: 0%

# Coverage for numpy\core\_dtype_ctypes.py : 0%

## 53 statements 0 run 53 missing 0 excluded

Hot-keys on this page

r m x p toggle line displays

j k next/prev highlighted chunk

0 (zero) top of page

1 (one) first highlighted chunk

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | """ 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) """ import _ctypes import ctypes import numpy as np def _from_ctypes_array(t): return np.dtype((dtype_from_ctypes_type(t._type_), (t._length_,))) def _from_ctypes_structure(t): 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) def _from_ctypes_scalar(t): """ Return the dtype type with endianness included if it's the case """ if getattr(t, '__ctype_be__', None) is t: return np.dtype('>' + t._type_) elif getattr(t, '__ctype_le__', None) is t: return np.dtype('<' + t._type_) else: return np.dtype(t._type_) def _from_ctypes_union(t): 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))) def dtype_from_ctypes_type(t): """ Construct a dtype object from a ctypes type """ if issubclass(t, _ctypes.Array): return _from_ctypes_array(t) elif issubclass(t, _ctypes._Pointer): raise TypeError("ctypes pointers have no dtype equivalent") elif issubclass(t, _ctypes.Structure): return _from_ctypes_structure(t) elif issubclass(t, _ctypes.Union): return _from_ctypes_union(t) elif isinstance(getattr(t, '_type_', None), str): return _from_ctypes_scalar(t) else: raise NotImplementedError( "Unknown ctypes type {}".format(t.__name__))