Commit 3c13f13d authored by Mark Florisson's avatar Mark Florisson

Support packed struct cython.array cast + better dtype error checking

parent d2797186
...@@ -713,6 +713,9 @@ def get_type_information_cname(code, dtype, maxdepth=None): ...@@ -713,6 +713,9 @@ def get_type_information_cname(code, dtype, maxdepth=None):
assert False assert False
rep = str(dtype) rep = str(dtype)
flags = "0"
if dtype.is_int: if dtype.is_int:
if dtype.signed == 0: if dtype.signed == 0:
typegroup = 'U' typegroup = 'U'
...@@ -724,6 +727,8 @@ def get_type_information_cname(code, dtype, maxdepth=None): ...@@ -724,6 +727,8 @@ def get_type_information_cname(code, dtype, maxdepth=None):
typegroup = 'R' typegroup = 'R'
elif dtype.is_struct: elif dtype.is_struct:
typegroup = 'S' typegroup = 'S'
if dtype.packed:
flags = "__PYX_BUF_FLAGS_PACKED_STRUCT"
elif dtype.is_pyobject: elif dtype.is_pyobject:
typegroup = 'O' typegroup = 'O'
else: else:
...@@ -735,13 +740,14 @@ def get_type_information_cname(code, dtype, maxdepth=None): ...@@ -735,13 +740,14 @@ def get_type_information_cname(code, dtype, maxdepth=None):
else: else:
is_unsigned = "0" is_unsigned = "0"
typecode.putln(('static __Pyx_TypeInfo %s = { "%s", %s, sizeof(%s), \'%s\', %s };' typecode.putln(('static __Pyx_TypeInfo %s = { "%s", %s, sizeof(%s), \'%s\', %s, %s };'
) % (name, ) % (name,
rep, rep,
structinfo_name, structinfo_name,
declcode, declcode,
typegroup, typegroup,
is_unsigned, is_unsigned,
flags,
), safe=True) ), safe=True)
return name return name
......
...@@ -6242,7 +6242,7 @@ class CythonArrayNode(ExprNode): ...@@ -6242,7 +6242,7 @@ class CythonArrayNode(ExprNode):
Used when a pointer of base_type is cast to a memoryviewslice with that Used when a pointer of base_type is cast to a memoryviewslice with that
base type. i.e. base type. i.e.
<int[::1, :]> p <int[:M:1, :N]> p
creates a fortran-contiguous cython.array. creates a fortran-contiguous cython.array.
...@@ -6302,13 +6302,14 @@ class CythonArrayNode(ExprNode): ...@@ -6302,13 +6302,14 @@ class CythonArrayNode(ExprNode):
self.operand.analyse_types(env) self.operand.analyse_types(env)
array_dtype = self.base_type_node.base_type_node.analyse(env) array_dtype = self.base_type_node.base_type_node.analyse(env)
MemoryView.validate_memslice_dtype(self.pos, array_dtype)
if not self.operand.type.is_ptr: if not self.operand.type.is_ptr:
return error(self.operand.pos, ERR_NOT_POINTER) return error(self.operand.pos, ERR_NOT_POINTER)
elif not self.operand.type.base_type.same_as(array_dtype): elif not self.operand.type.base_type.same_as(array_dtype):
return error(self.operand.pos, ERR_BASE_TYPE) return error(self.operand.pos, ERR_BASE_TYPE)
#self.operand = self.operand.coerce_to(PyrexTypes.c_char_ptr_type, env)
if not self.operand.is_name: if not self.operand.is_name:
self.operand = self.operand.coerce_to_temp(env) self.operand = self.operand.coerce_to_temp(env)
...@@ -6320,7 +6321,7 @@ class CythonArrayNode(ExprNode): ...@@ -6320,7 +6321,7 @@ class CythonArrayNode(ExprNode):
self.coercion_type = PyrexTypes.MemoryViewSliceType(array_dtype, axes) self.coercion_type = PyrexTypes.MemoryViewSliceType(array_dtype, axes)
#self.type = py_object_type #self.type = py_object_type
self.type = env.global_scope().context.cython_scope.lookup("array").type self.type = self.get_cython_array_type(env)
assert self.type assert self.type
env.use_utility_code(MemoryView.cython_array_utility_code) env.use_utility_code(MemoryView.cython_array_utility_code)
...@@ -6332,6 +6333,12 @@ class CythonArrayNode(ExprNode): ...@@ -6332,6 +6333,12 @@ class CythonArrayNode(ExprNode):
self.temp_code = code.funcstate.allocate_temp(self.type, True) self.temp_code = code.funcstate.allocate_temp(self.type, True)
def infer_type(self, env):
return self.get_cython_array_type(env)
def get_cython_array_type(self, env):
return env.global_scope().context.cython_scope.lookup("array").type
def generate_result_code(self, code): def generate_result_code(self, code):
import Buffer import Buffer
......
...@@ -161,6 +161,27 @@ def src_conforms_to_dst(src, dst): ...@@ -161,6 +161,27 @@ def src_conforms_to_dst(src, dst):
return True return True
def valid_memslice_dtype(dtype):
"""
Return whether type dtype can be used as the base type of a
memoryview slice
"""
if dtype.is_complex and dtype.real_type.is_int:
return False
return (
dtype.is_error or
dtype.is_ptr or
dtype.is_numeric or
dtype.is_struct or
dtype.is_pyobject or
(dtype.is_typedef and valid_memslice_dtype(dtype.typedef_base_type))
)
def validate_memslice_dtype(pos, dtype):
if not valid_memslice_dtype(dtype):
error(pos, "Invalid base type for memoryview slice")
class MemoryViewSliceBufferEntry(Buffer.BufferEntry): class MemoryViewSliceBufferEntry(Buffer.BufferEntry):
def __init__(self, entry): def __init__(self, entry):
......
...@@ -828,10 +828,8 @@ class MemoryViewSliceTypeNode(CBaseTypeNode): ...@@ -828,10 +828,8 @@ class MemoryViewSliceTypeNode(CBaseTypeNode):
self.type = PyrexTypes.ErrorType() self.type = PyrexTypes.ErrorType()
return self.type return self.type
MemoryView.validate_memslice_dtype(self.pos, base_type)
self.type = PyrexTypes.MemoryViewSliceType(base_type, axes_specs) self.type = PyrexTypes.MemoryViewSliceType(base_type, axes_specs)
if self.type.dtype.is_memoryviewslice:
error(self.pos, "Memoryview slices may not be used as the "
"base type for memoryview slices")
self.use_memview_utilities(env) self.use_memview_utilities(env)
return self.type return self.type
......
...@@ -42,12 +42,15 @@ static void __Pyx_RaiseBufferFallbackError(void) { ...@@ -42,12 +42,15 @@ static void __Pyx_RaiseBufferFallbackError(void) {
/* Run-time type information about structs used with buffers */ /* Run-time type information about structs used with buffers */
struct __Pyx_StructField_; struct __Pyx_StructField_;
#define __PYX_BUF_FLAGS_PACKED_STRUCT (1 << 0)
typedef struct { typedef struct {
const char* name; /* for error messages only */ const char* name; /* for error messages only */
struct __Pyx_StructField_* fields; struct __Pyx_StructField_* fields;
size_t size; /* sizeof(type) */ size_t size; /* sizeof(type) */
char typegroup; /* _R_eal, _C_omplex, Signed _I_nt, _U_nsigned int, _S_truct, _P_ointer, _O_bject */ char typegroup; /* _R_eal, _C_omplex, Signed _I_nt, _U_nsigned int, _S_truct, _P_ointer, _O_bject */
char is_unsigned; char is_unsigned;
int flags;
} __Pyx_TypeInfo; } __Pyx_TypeInfo;
typedef struct __Pyx_StructField_ { typedef struct __Pyx_StructField_ {
...@@ -544,7 +547,7 @@ static struct __pyx_typeinfo_string __Pyx_TypeInfoToFormat(__Pyx_TypeInfo *type) ...@@ -544,7 +547,7 @@ static struct __pyx_typeinfo_string __Pyx_TypeInfoToFormat(__Pyx_TypeInfo *type)
case 'I': case 'I':
case 'U': case 'U':
if (size == 1) if (size == 1)
*buf = 'c'; *buf = 'b';
else if (size == 2) else if (size == 2)
*buf = 'h'; *buf = 'h';
else if (size == 4) else if (size == 4)
...@@ -559,16 +562,15 @@ static struct __pyx_typeinfo_string __Pyx_TypeInfoToFormat(__Pyx_TypeInfo *type) ...@@ -559,16 +562,15 @@ static struct __pyx_typeinfo_string __Pyx_TypeInfoToFormat(__Pyx_TypeInfo *type)
*buf = 'P'; *buf = 'P';
break; break;
case 'C': case 'C':
{ {
__Pyx_TypeInfo complex_type = *type; __Pyx_TypeInfo complex_type = *type;
complex_type.typegroup = 'R'; complex_type.typegroup = 'R';
complex_type.size /= 2; complex_type.size /= 2;
*buf++ = 'Z'; *buf++ = 'Z';
/* Note: What about short/int/long complex? Probably not used? */
*buf = __Pyx_TypeInfoToFormat(&complex_type).string[0]; *buf = __Pyx_TypeInfoToFormat(&complex_type).string[0];
break; break;
} }
case 'R': case 'R':
if (size == 4) if (size == 4)
*buf = 'f'; *buf = 'f';
......
...@@ -28,13 +28,13 @@ cdef class array: ...@@ -28,13 +28,13 @@ cdef class array:
Py_ssize_t len Py_ssize_t len
char *format char *format
int ndim int ndim
Py_ssize_t *shape Py_ssize_t *_shape
Py_ssize_t *strides Py_ssize_t *_strides
Py_ssize_t itemsize Py_ssize_t itemsize
unicode mode unicode mode
bytes _format bytes _format
void (*callback_free_data)(char *data) void (*callback_free_data)(char *data)
cdef object _memview # cdef object _memview
def __cinit__(array self, tuple shape, Py_ssize_t itemsize, format, def __cinit__(array self, tuple shape, Py_ssize_t itemsize, format,
mode=u"c", bint allocate_buffer=True): mode=u"c", bint allocate_buffer=True):
...@@ -54,12 +54,12 @@ cdef class array: ...@@ -54,12 +54,12 @@ cdef class array:
self._format = format self._format = format
self.format = self._format self.format = self._format
self.shape = <Py_ssize_t *> malloc(sizeof(Py_ssize_t)*self.ndim) self._shape = <Py_ssize_t *> malloc(sizeof(Py_ssize_t)*self.ndim)
self.strides = <Py_ssize_t *> malloc(sizeof(Py_ssize_t)*self.ndim) self._strides = <Py_ssize_t *> malloc(sizeof(Py_ssize_t)*self.ndim)
if not self.shape or not self.strides: if not self._shape or not self._strides:
free(self.shape) free(self._shape)
free(self.strides) free(self._strides)
raise MemoryError("unable to allocate shape or strides.") raise MemoryError("unable to allocate shape or strides.")
cdef int idx cdef int idx
...@@ -69,20 +69,20 @@ cdef class array: ...@@ -69,20 +69,20 @@ cdef class array:
if dim <= 0: if dim <= 0:
raise ValueError("Invalid shape.") raise ValueError("Invalid shape.")
self.shape[idx] = dim self._shape[idx] = dim
idx += 1 idx += 1
stride = itemsize stride = itemsize
if mode == "fortran": if mode == "fortran":
idx = 0 idx = 0
for dim in shape: for dim in shape:
self.strides[idx] = stride self._strides[idx] = stride
stride = stride * dim stride = stride * dim
idx += 1 idx += 1
elif mode == "c": elif mode == "c":
idx = self.ndim-1 idx = self.ndim-1
for dim in shape[::-1]: for dim in shape[::-1]:
self.strides[idx] = stride self._strides[idx] = stride
stride = stride * dim stride = stride * dim
idx -= 1 idx -= 1
else: else:
...@@ -111,8 +111,8 @@ cdef class array: ...@@ -111,8 +111,8 @@ cdef class array:
info.buf = self.data info.buf = self.data
info.len = self.len info.len = self.len
info.ndim = self.ndim info.ndim = self.ndim
info.shape = self.shape info.shape = self._shape
info.strides = self.strides info.strides = self._strides
info.suboffsets = NULL info.suboffsets = NULL
info.itemsize = self.itemsize info.itemsize = self.itemsize
info.readonly = 0 info.readonly = 0
...@@ -122,6 +122,8 @@ cdef class array: ...@@ -122,6 +122,8 @@ cdef class array:
else: else:
info.format = NULL info.format = NULL
info.obj = self
def __dealloc__(array self): def __dealloc__(array self):
if self.callback_free_data != NULL: if self.callback_free_data != NULL:
self.callback_free_data(self.data) self.callback_free_data(self.data)
...@@ -130,13 +132,13 @@ cdef class array: ...@@ -130,13 +132,13 @@ cdef class array:
self.data = NULL self.data = NULL
if self.strides: if self._strides:
free(self.strides) free(self._strides)
self.strides = NULL self._strides = NULL
if self.shape: if self._shape:
free(self.shape) free(self._shape)
self.shape = NULL self._shape = NULL
self.format = NULL self.format = NULL
self.itemsize = 0 self.itemsize = 0
...@@ -145,11 +147,14 @@ cdef class array: ...@@ -145,11 +147,14 @@ cdef class array:
@cname('__pyx_cython_array_get_memview') @cname('__pyx_cython_array_get_memview')
def __get__(self): def __get__(self):
# Make this a property as 'data' may be set after instantiation # Make this a property as 'data' may be set after instantiation
if self._memview is None: #if self._memview is None:
flags = PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT|PyBUF_WRITABLE # flags = PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT|PyBUF_WRITABLE
self._memview = __pyx_memoryview_new(self, flags) # self._memview = __pyx_memoryview_new(self, flags)
#return self._memview
flags = PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT|PyBUF_WRITABLE
return __pyx_memoryview_new(self, flags)
return self._memview
def __getattr__(self, attr): def __getattr__(self, attr):
return getattr(self.memview, attr) return getattr(self.memview, attr)
...@@ -221,6 +226,15 @@ cdef extern from *: ...@@ -221,6 +226,15 @@ cdef extern from *:
PyObject *Py_None PyObject *Py_None
cdef enum:
PyBUF_C_CONTIGUOUS,
PyBUF_F_CONTIGUOUS,
PyBUF_ANY_CONTIGUOUS
PyBUF_FORMAT
PyBUF_WRITABLE
PyBUF_STRIDES
PyBUF_INDIRECT
@cname('__pyx_MemviewEnum') @cname('__pyx_MemviewEnum')
cdef class Enum(object): cdef class Enum(object):
cdef object name cdef object name
...@@ -348,11 +362,34 @@ cdef class memoryview(object): ...@@ -348,11 +362,34 @@ cdef class memoryview(object):
itemp[i] = c itemp[i] = c
def __getbuffer__(self, Py_buffer *info, int flags): def __getbuffer__(self, Py_buffer *info, int flags):
# Note: self.view.obj must not be NULL if flags & PyBUF_STRIDES:
Py_INCREF(self.view.obj) info.shape = self.view.shape
info[0] = self.view else:
info.shape = NULL
if flags & PyBUF_STRIDES:
info.strides = self.view.strides
else:
info.strides = NULL
if flags & PyBUF_INDIRECT:
info.suboffsets = self.view.suboffsets
else:
info.suboffsets = NULL
if flags & PyBUF_FORMAT:
info.format = self.view.format
else:
info.format = NULL
info.buf = self.view.buf
info.ndim = self.view.ndim
info.itemsize = self.view.itemsize
info.len = self.view.len
info.readonly = 0
info.obj = self info.obj = self
# Some properties that have the same sematics as in NumPy # Some properties that have the same sematics as in NumPy
property T: property T:
@cname('__pyx_memoryview_transpose') @cname('__pyx_memoryview_transpose')
...@@ -374,11 +411,18 @@ cdef class memoryview(object): ...@@ -374,11 +411,18 @@ cdef class memoryview(object):
property strides: property strides:
@cname('__pyx_memoryview_get_strides') @cname('__pyx_memoryview_get_strides')
def __get__(self): def __get__(self):
if self.view.strides == NULL:
# Note: we always ask for strides, so if this is not set it's a bug
raise ValueError("Buffer view does not expose strides")
return tuple([self.view.strides[i] for i in xrange(self.view.ndim)]) return tuple([self.view.strides[i] for i in xrange(self.view.ndim)])
property suboffsets: property suboffsets:
@cname('__pyx_memoryview_get_suboffsets') @cname('__pyx_memoryview_get_suboffsets')
def __get__(self): def __get__(self):
if self.view.suboffsets == NULL:
return [-1] * self.view.ndim
return tuple([self.view.suboffsets[i] for i in xrange(self.view.ndim)]) return tuple([self.view.suboffsets[i] for i in xrange(self.view.ndim)])
property ndim: property ndim:
...@@ -409,6 +453,9 @@ cdef class memoryview(object): ...@@ -409,6 +453,9 @@ cdef class memoryview(object):
return self._size return self._size
# The __array_interface__ is broken as it does not properly convert PEP 3118 format
# strings into NumPy typestrs. NumPy 1.5 support the new buffer interface though.
'''
property __array_interface__: property __array_interface__:
@cname('__pyx_numpy_array_interface') @cname('__pyx_numpy_array_interface')
def __get__(self): def __get__(self):
...@@ -424,10 +471,11 @@ cdef class memoryview(object): ...@@ -424,10 +471,11 @@ cdef class memoryview(object):
data = (PyLong_FromVoidPtr(self.view.buf), False), data = (PyLong_FromVoidPtr(self.view.buf), False),
shape = self.shape, shape = self.shape,
strides = self.strides, strides = self.strides,
typestr = "%s%d" % (self.format, self.view.itemsize), typestr = "%s%d" % (self.view.format, self.view.itemsize),
version = 3) version = 3)
return self._array_interface return self._array_interface
'''
def __len__(self): def __len__(self):
if self.view.ndim >= 1: if self.view.ndim >= 1:
...@@ -848,12 +896,17 @@ cdef memoryview_copy(memoryview memview): ...@@ -848,12 +896,17 @@ cdef memoryview_copy(memoryview memview):
cdef extern from *: cdef extern from *:
ctypedef struct __Pyx_StructField ctypedef struct __Pyx_StructField
cdef enum:
__PYX_BUF_FLAGS_PACKED_STRUCT
__PYX_BUF_FLAGS_INTEGER_COMPLEX
ctypedef struct __Pyx_TypeInfo: ctypedef struct __Pyx_TypeInfo:
char* name char* name
__Pyx_StructField* fields __Pyx_StructField* fields
size_t size size_t size
char typegroup char typegroup
char is_unsigned char is_unsigned
int flags
ctypedef struct __Pyx_StructField: ctypedef struct __Pyx_StructField:
__Pyx_TypeInfo* type __Pyx_TypeInfo* type
...@@ -882,6 +935,11 @@ cdef format_from_typeinfo(__Pyx_TypeInfo *type): ...@@ -882,6 +935,11 @@ cdef format_from_typeinfo(__Pyx_TypeInfo *type):
if type.typegroup == 'S': if type.typegroup == 'S':
assert type.fields != NULL and type.fields.type != NULL assert type.fields != NULL and type.fields.type != NULL
if type.flags & __PYX_BUF_FLAGS_PACKED_STRUCT:
alignment = '^'
else:
alignment = ''
parts = ["T{"] parts = ["T{"]
field = type.fields field = type.fields
...@@ -889,8 +947,7 @@ cdef format_from_typeinfo(__Pyx_TypeInfo *type): ...@@ -889,8 +947,7 @@ cdef format_from_typeinfo(__Pyx_TypeInfo *type):
parts.append(format_from_typeinfo(field.type)) parts.append(format_from_typeinfo(field.type))
field += 1 field += 1
parts.append("}") result = alignment.join(parts) + '}'
result = "".join(parts)
else: else:
fmt = __Pyx_TypeInfoToFormat(type) fmt = __Pyx_TypeInfoToFormat(type)
result = fmt.string result = fmt.string
......
...@@ -60,7 +60,7 @@ def full_or_strided(): ...@@ -60,7 +60,7 @@ def full_or_strided():
def dont_allocate_buffer(): def dont_allocate_buffer():
""" """
>>> dont_allocate_buffer() >>> dont_allocate_buffer()
callback called 1 callback called
""" """
cdef cy.array result = cy.array((10, 10), itemsize=sizeof(int), format='i', allocate_buffer=False) cdef cy.array result = cy.array((10, 10), itemsize=sizeof(int), format='i', allocate_buffer=False)
assert result.data == NULL assert result.data == NULL
......
...@@ -2,7 +2,7 @@ from libc.stdlib cimport malloc, free ...@@ -2,7 +2,7 @@ from libc.stdlib cimport malloc, free
cimport cython cimport cython
cdef void callback(char *data): cdef void callback(char *data):
print "callback called %d" % <long> data print "callback called"
def create_array(shape, mode, use_callback=False): def create_array(shape, mode, use_callback=False):
cdef cython.array result = cython.array(shape, itemsize=sizeof(int), cdef cython.array result = cython.array(shape, itemsize=sizeof(int),
......
...@@ -9,6 +9,7 @@ cimport numpy as np ...@@ -9,6 +9,7 @@ cimport numpy as np
import numpy as np import numpy as np
include "cythonarrayutil.pxi" include "cythonarrayutil.pxi"
include "mockbuffers.pxi"
ctypedef np.int32_t dtype_t ctypedef np.int32_t dtype_t
...@@ -27,10 +28,23 @@ def ae(*args): ...@@ -27,10 +28,23 @@ def ae(*args):
if x != args[0]: if x != args[0]:
raise AssertionError(args) raise AssertionError(args)
__test__ = {}
def testcase(f):
__test__[f.__name__] = f.__doc__
return f
def testcase_numpy_1_5(f):
major, minor, *rest = np.__version__.split('.')
if (int(major), int(minor)) >= (1, 5):
__test__[f.__name__] = f.__doc__
return f
# #
### Test slicing memoryview slices ### Test slicing memoryview slices
# #
@testcase
def test_partial_slicing(array): def test_partial_slicing(array):
""" """
>>> test_partial_slicing(a) >>> test_partial_slicing(a)
...@@ -46,6 +60,7 @@ def test_partial_slicing(array): ...@@ -46,6 +60,7 @@ def test_partial_slicing(array):
ae(b.strides[0], c.strides[0], obj.strides[0]) ae(b.strides[0], c.strides[0], obj.strides[0])
ae(b.strides[1], c.strides[1], obj.strides[1]) ae(b.strides[1], c.strides[1], obj.strides[1])
@testcase
def test_ellipsis(array): def test_ellipsis(array):
""" """
>>> test_ellipsis(a) >>> test_ellipsis(a)
...@@ -87,7 +102,7 @@ def test_ellipsis(array): ...@@ -87,7 +102,7 @@ def test_ellipsis(array):
# #
### Test slicing memoryview objects ### Test slicing memoryview objects
# #
@testcase
def test_partial_slicing_memoryview(array): def test_partial_slicing_memoryview(array):
""" """
>>> test_partial_slicing_memoryview(a) >>> test_partial_slicing_memoryview(a)
...@@ -104,6 +119,7 @@ def test_partial_slicing_memoryview(array): ...@@ -104,6 +119,7 @@ def test_partial_slicing_memoryview(array):
ae(b.strides[0], c.strides[0], obj.strides[0]) ae(b.strides[0], c.strides[0], obj.strides[0])
ae(b.strides[1], c.strides[1], obj.strides[1]) ae(b.strides[1], c.strides[1], obj.strides[1])
@testcase
def test_ellipsis_memoryview(array): def test_ellipsis_memoryview(array):
""" """
>>> test_ellipsis_memoryview(a) >>> test_ellipsis_memoryview(a)
...@@ -143,6 +159,7 @@ def test_ellipsis_memoryview(array): ...@@ -143,6 +159,7 @@ def test_ellipsis_memoryview(array):
ae(e.shape[0], e_obj.shape[0]) ae(e.shape[0], e_obj.shape[0])
ae(e.strides[0], e_obj.strides[0]) ae(e.strides[0], e_obj.strides[0])
@testcase
def test_transpose(): def test_transpose():
""" """
>>> test_transpose() >>> test_transpose()
...@@ -172,26 +189,10 @@ def test_transpose(): ...@@ -172,26 +189,10 @@ def test_transpose():
print a[3, 2], a.T[2, 3], a_obj[3, 2], a_obj.T[2, 3], numpy_obj[3, 2], numpy_obj.T[2, 3] print a[3, 2], a.T[2, 3], a_obj[3, 2], a_obj.T[2, 3], numpy_obj[3, 2], numpy_obj.T[2, 3]
def test_coerce_to_numpy(): @testcase
"""
>>> test_coerce_to_numpy()
34
34
2
"""
cyarray = create_array(shape=(8, 5), mode="c", use_callback=True)
numarray = np.asarray(cyarray)
print cyarray[6, 4]
del cyarray
print numarray[6, 4]
numarray[6, 4] = 2
print numarray[6, 4]
def test_numpy_like_attributes(cyarray): def test_numpy_like_attributes(cyarray):
""" """
>>> cyarray = create_array(shape=(8, 5), mode="c", use_callback=True) >>> cyarray = create_array(shape=(8, 5), mode="c")
>>> test_numpy_like_attributes(cyarray) >>> test_numpy_like_attributes(cyarray)
>>> test_numpy_like_attributes(cyarray.memview) >>> test_numpy_like_attributes(cyarray.memview)
""" """
...@@ -205,3 +206,164 @@ def test_numpy_like_attributes(cyarray): ...@@ -205,3 +206,164 @@ def test_numpy_like_attributes(cyarray):
cdef int[:, :] mslice = numarray cdef int[:, :] mslice = numarray
assert (<object> mslice).base is numarray assert (<object> mslice).base is numarray
ctypedef int td_cy_int
cdef extern from "bufaccess.h":
ctypedef td_cy_int td_h_short # Defined as short, but Cython doesn't know this!
ctypedef float td_h_double # Defined as double
ctypedef unsigned int td_h_ushort # Defined as unsigned short
ctypedef td_h_short td_h_cy_short
cdef void dealloc_callback(char *data):
print "deallocating..."
def index(cython.array array):
array.callback_free_data = dealloc_callback
print np.asarray(array)[3, 2]
@testcase_numpy_1_5
def test_coerce_to_numpy():
"""
Test coercion to NumPy arrays, especially with automatically
generated format strings.
>>> test_coerce_to_numpy()
(97, 98, 600L, 700, 800)
deallocating...
(600, 700)
deallocating...
((100, 200), (300, 400), 500)
deallocating...
(97, 900)
deallocating...
99
deallocating...
111
deallocating...
222
deallocating...
333
deallocating...
11.1
deallocating...
12.2
deallocating...
13.3
deallocating...
(14.4+15.5j)
deallocating...
(16.6+17.7j)
deallocating...
(18.8+19.9j)
deallocating...
22
deallocating...
33.33
deallocating...
44
deallocating...
"""
#
### First set up some C arrays that will be used to hold data
#
cdef MyStruct mystructs[20]
cdef SmallStruct smallstructs[20]
cdef NestedStruct nestedstructs[20]
cdef PackedStruct packedstructs[20]
cdef char chars[20]
cdef short shorts[20]
cdef int ints[20]
cdef long long longlongs[20]
cdef td_h_short externs[20]
cdef float floats[20]
cdef double doubles[20]
cdef long double longdoubles[20]
cdef float complex floatcomplex[20]
cdef double complex doublecomplex[20]
cdef long double complex longdoublecomplex[20]
cdef td_h_short h_shorts[20]
cdef td_h_double h_doubles[20]
cdef td_h_ushort h_ushorts[20]
cdef Py_ssize_t idx = 17
#
### Initialize one element in each array
#
mystructs[idx] = {
'a': 'a',
'b': 'b',
'c': 600,
'd': 700,
'e': 800,
}
smallstructs[idx] = { 'a': 600, 'b': 700 }
nestedstructs[idx] = {
'x': { 'a': 100, 'b': 200 },
'y': { 'a': 300, 'b': 400 },
'z': 500,
}
packedstructs[idx] = { 'a': 'a', 'b': 900 }
chars[idx] = 99
shorts[idx] = 111
ints[idx] = 222
longlongs[idx] = 333
externs[idx] = 444
floats[idx] = 11.1
doubles[idx] = 12.2
longdoubles[idx] = 13.3
floatcomplex[idx] = 14.4 + 15.5j
doublecomplex[idx] = 16.6 + 17.7j
longdoublecomplex[idx] = 18.8 + 19.9j
h_shorts[idx] = 22
h_doubles[idx] = 33.33
h_ushorts[idx] = 44
#
### Create a NumPy array and see if our element can be correctly retrieved
#
index(<MyStruct[:4, :5]> <MyStruct *> mystructs)
index(<SmallStruct[:4, :5]> <SmallStruct *> smallstructs)
index(<NestedStruct[:4, :5]> <NestedStruct *> nestedstructs)
index(<PackedStruct[:4, :5]> <PackedStruct *> packedstructs)
index(<char[:4, :5]> <char *> chars)
index(<short[:4, :5]> <short *> shorts)
index(<int[:4, :5]> <int *> ints)
index(<long long[:4, :5]> <long long *> longlongs)
index(<float[:4, :5]> <float *> floats)
index(<double[:4, :5]> <double *> doubles)
index(<long double[:4, :5]> <long double *> longdoubles)
index(<float complex[:4, :5]> <float complex *> floatcomplex)
index(<double complex[:4, :5]> <double complex *> doublecomplex)
index(<long double complex[:4, :5]> <long double complex *> longdoublecomplex)
index(<td_h_short[:4, :5]> <td_h_short *> h_shorts)
index(<td_h_double[:4, :5]> <td_h_double *> h_doubles)
index(<td_h_ushort[:4, :5]> <td_h_ushort *> h_ushorts)
@testcase_numpy_1_5
def test_memslice_getbuffer():
"""
>>> test_memslice_getbuffer()
[[ 0 2 4]
[10 12 14]]
callback called
"""
cdef int[:, :] array = create_array((4, 5), mode="c", use_callback=True)
print np.asarray(array)[::2, ::2]
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment