diff --git a/buildconfig/stubs/pygame/__init__.pyi b/buildconfig/stubs/pygame/__init__.pyi index c05a428fb4..0b91ac36a2 100644 --- a/buildconfig/stubs/pygame/__init__.pyi +++ b/buildconfig/stubs/pygame/__init__.pyi @@ -60,7 +60,6 @@ from .base import ( BufferError as BufferError, HAVE_NEWBUF as HAVE_NEWBUF, error as error, - get_array_interface as get_array_interface, get_error as get_error, get_init as get_init, get_sdl_byteorder as get_sdl_byteorder, diff --git a/buildconfig/stubs/pygame/base.pyi b/buildconfig/stubs/pygame/base.pyi index 4aa5d42149..4ca18d99f5 100644 --- a/buildconfig/stubs/pygame/base.pyi +++ b/buildconfig/stubs/pygame/base.pyi @@ -16,6 +16,3 @@ def set_error(error_msg: str, /) -> None: ... def get_sdl_version(linked: bool = True) -> Tuple[int, int, int]: ... def get_sdl_byteorder() -> int: ... def register_quit(callable: Callable[[], Any], /) -> None: ... - -# undocumented part of pygame API, kept here to make stubtest happy -def get_array_interface(arg: Any, /) -> dict: ... diff --git a/buildconfig/stubs/pygame/bufferproxy.pyi b/buildconfig/stubs/pygame/bufferproxy.pyi index b77eb46c43..cb5b578805 100644 --- a/buildconfig/stubs/pygame/bufferproxy.pyi +++ b/buildconfig/stubs/pygame/bufferproxy.pyi @@ -4,10 +4,7 @@ class BufferProxy: parent: Any length: int raw: bytes - # possibly going to be deprecated/removed soon, in which case these - # typestubs must be removed too __array_interface__: Dict[str, Any] - __array_struct__: Any @overload def __init__(self) -> None: ... @overload diff --git a/buildconfig/stubs/pygame/color.pyi b/buildconfig/stubs/pygame/color.pyi index d53344de1d..3d204eac02 100644 --- a/buildconfig/stubs/pygame/color.pyi +++ b/buildconfig/stubs/pygame/color.pyi @@ -23,7 +23,6 @@ class Color(Collection[int]): i1i2i3: Tuple[float, float, float] normalized: Tuple[float, float, float, float] __hash__: None # type: ignore - __array_struct__: Any @overload def __init__(self, r: int, g: int, b: int, a: int = 255) -> None: ... @overload diff --git a/buildconfig/stubs/pygame/mixer.pyi b/buildconfig/stubs/pygame/mixer.pyi index 4d1cafc830..1fb71157c2 100644 --- a/buildconfig/stubs/pygame/mixer.pyi +++ b/buildconfig/stubs/pygame/mixer.pyi @@ -59,10 +59,7 @@ class Sound: maxtime: int = 0, fade_ms: int = 0, ) -> Channel: ... - # possibly going to be deprecated/removed soon, in which case these - # typestubs must be removed too __array_interface__: Dict[str, Any] - __array_struct__: Any def stop(self) -> None: ... def fadeout(self, time: int, /) -> None: ... def set_volume(self, value: float, /) -> None: ... @@ -71,7 +68,6 @@ class Sound: def get_length(self) -> float: ... def get_raw(self) -> bytes: ... - class Channel: def __init__(self, id: int) -> None: ... @property diff --git a/buildconfig/stubs/pygame/pixelarray.pyi b/buildconfig/stubs/pygame/pixelarray.pyi index 935d4c01d6..f68034eb51 100644 --- a/buildconfig/stubs/pygame/pixelarray.pyi +++ b/buildconfig/stubs/pygame/pixelarray.pyi @@ -10,10 +10,7 @@ class PixelArray: ndim: int shape: Tuple[int, ...] strides: Tuple[int, ...] - # possibly going to be deprecated/removed soon, in which case these - # typestubs must be removed too __array_interface__: Dict[str, Any] - __array_struct__: Any def __init__(self, surface: Surface) -> None: ... def __enter__(self) -> PixelArray: ... def __exit__(self, *args, **kwargs) -> None: ... diff --git a/docs/reST/c_api/base.rst b/docs/reST/c_api/base.rst index c2117460ac..ca1dcccd0a 100644 --- a/docs/reST/c_api/base.rst +++ b/docs/reST/c_api/base.rst @@ -124,19 +124,14 @@ C header: src_c/include/pygame.h Return a Python array interface object representation of buffer *view_p*. On failure raise a Python exception and return *NULL*. -.. c:function:: PyObject* pgBuffer_AsArrayStruct(Py_buffer *view_p) - - Return a Python array struct object representation of buffer *view_p*. - On failure raise a Python exception and return *NULL*. - .. c:function:: int pgObject_GetBuffer(PyObject *obj, pg_buffer *pg_view_p, int flags) Request a buffer for object *obj*. Argument *flags* are PyBUF options. Return the buffer description in *pg_view_p*. - An object may support the Python buffer interface, the NumPy array interface, - or the NumPy array struct interface. - Return ``0`` on success, raise a Python exception and return ``-1`` on failure. + An object may support the Python buffer interface or the NumPy python + object array interface. Return ``0`` on success, raise a Python exception + and return ``-1`` on failure. .. c:function:: void pgBuffer_Release(Pg_buffer *pg_view_p) diff --git a/docs/reST/ref/freetype.rst b/docs/reST/ref/freetype.rst index bf6a74609e..53e0eea765 100644 --- a/docs/reST/ref/freetype.rst +++ b/docs/reST/ref/freetype.rst @@ -506,7 +506,7 @@ loaded. This module must be imported explicitly to be used. :: | :sl:`Render text into an array of ints` | :sg:`render_raw_to(array, text, dest=None, style=STYLE_DEFAULT, rotation=0, size=0, invert=False) -> Rect` - Render to an array object exposing an array struct interface. The array + Render to an array object exposing the buffer protocol. The array must be two dimensional with integer items. The default *dest* value, ``None``, is equivalent to position (0, 0). See :meth:`render_to`. As with the other render methods, *text* can be ``None`` to diff --git a/docs/reST/ref/pixelarray.rst b/docs/reST/ref/pixelarray.rst index 0fb90d7ec0..392745c741 100644 --- a/docs/reST/ref/pixelarray.rst +++ b/docs/reST/ref/pixelarray.rst @@ -17,9 +17,9 @@ for assignment. A pixel array sliced on a single column or row returns a one dimensional pixel array. Arithmetic and other operations are not supported. A pixel array can be safely assigned to itself. - Finally, pixel arrays export an array struct interface, allowing - them to interact with :mod:`pygame.pixelcopy` methods and NumPy - arrays. + Finally, pixel arrays export the buffer protocol as well as the python + array interface, allowing them to interact with :mod:`pygame.pixelcopy` + methods and NumPy arrays. A PixelArray pixel item can be assigned a raw integer values, a :class:`pygame.Color` instance, or a (r, g, b[, a]) tuple. @@ -100,6 +100,8 @@ copying is implemented it is suggested PixelArray to PixelArray copies be only between surfaces of identical format. + .. versionchanged:: 2.5.0 Removed array struct support + .. versionaddedold:: 1.9.4 - close() method was added. For explicitly cleaning up. diff --git a/docs/reST/ref/pixelcopy.rst b/docs/reST/ref/pixelcopy.rst index 51388fbad3..3d36d86c2c 100644 --- a/docs/reST/ref/pixelcopy.rst +++ b/docs/reST/ref/pixelcopy.rst @@ -9,23 +9,18 @@ | :sl:`pygame module for general pixel array copying` The ``pygame.pixelcopy`` module contains functions for copying between -surfaces and objects exporting an array structure interface. It is a backend -for :mod:`pygame.surfarray`, adding NumPy support. But pixelcopy is more -general, and intended for direct use. - -The array struct interface exposes an array's data in a standard way. -It was introduced in NumPy. In Python 2.7 and above it is replaced by the -new buffer protocol, though the buffer protocol is still a work in progress. -The array struct interface, on the other hand, is stable and works with earlier -Python versions. So for now the array struct interface is the predominate way -pygame handles array introspection. +surfaces and objects exporting the buffer protocol or the python array +interface. It is a backend for :mod:`pygame.surfarray`, which adds NumPy +support. But pixelcopy is more general, and intended for direct use. For 2d arrays of integer pixel values, the values are mapped to the pixel format of the related surface. To get the actual color of a pixel value use :meth:`pygame.Surface.unmap_rgb`. 2d arrays can only be used directly between surfaces having the same pixel layout. -New in pygame 1.9.2. +.. versionchanged:: 2.5.0 Removed array struct support + +.. versionaddedold:: 1.9.2 .. function:: surface_to_array diff --git a/docs/reST/ref/surface.rst b/docs/reST/ref/surface.rst index 4d0e3be9da..443b02925a 100644 --- a/docs/reST/ref/surface.rst +++ b/docs/reST/ref/surface.rst @@ -937,8 +937,7 @@ | :sg:`get_view(kind='2', /) -> BufferProxy` Return an object which exports a surface's internal pixel buffer as - a C level array struct, Python level array interface or a C level - buffer interface. The new buffer protocol is supported. + a Python level array interface or a C level buffer interface. The kind argument is the length 1 string '0', '1', '2', '3', 'r', 'g', 'b', or 'a'. The letters are case insensitive; diff --git a/docs/reST/ref/surfarray.rst b/docs/reST/ref/surfarray.rst index 48b917fbfd..255540fc8a 100644 --- a/docs/reST/ref/surfarray.rst +++ b/docs/reST/ref/surfarray.rst @@ -262,10 +262,11 @@ will be locked during the lifetime of the array. Create a new Surface that best resembles the data and format on the array. The array can be 2D or 3D with any sized integer values. Function - make_surface uses the array struct interface to acquire array properties, + make_surface uses the buffer protocol to acquire array properties, so is not limited to just NumPy arrays. See :mod:`pygame.pixelcopy`. - New in pygame 1.9.2: array struct interface support. + .. versionchanged:: 2.5.0 Removed array struct interface support. + .. versionaddedold:: 1.9.2 array struct interface support. .. ## pygame.surfarray.make_surface ## diff --git a/src_c/_pygame.h b/src_c/_pygame.h index f16cbbf5af..163095cb2c 100644 --- a/src_c/_pygame.h +++ b/src_c/_pygame.h @@ -538,7 +538,7 @@ typedef enum { #define PYGAMEAPI_PIXELARRAY_NUMSLOTS 2 #define PYGAMEAPI_COLOR_NUMSLOTS 5 #define PYGAMEAPI_MATH_NUMSLOTS 2 -#define PYGAMEAPI_BASE_NUMSLOTS 29 +#define PYGAMEAPI_BASE_NUMSLOTS 28 #define PYGAMEAPI_EVENT_NUMSLOTS 10 #define PYGAMEAPI_WINDOW_NUMSLOTS 1 #define PYGAMEAPI_GEOMETRY_NUMSLOTS 1 diff --git a/src_c/base.c b/src_c/base.c index 2a609e6601..f3910c03a2 100644 --- a/src_c/base.c +++ b/src_c/base.c @@ -26,7 +26,6 @@ #include #include "doc/pygame_doc.h" -#include "pgarrinter.h" #include "pgcompat.h" /* This file controls all the initialization of @@ -60,12 +59,6 @@ QDGlobals pg_qd; #endif #define BUF_MY_ENDIAN '=' -/* Extended array struct */ -typedef struct pg_capsule_interface_s { - PyArrayInterface inter; - Py_intptr_t imem[1]; -} pgCapsuleInterface; - /* Py_buffer internal data for an array interface/struct */ typedef struct pg_view_internals_s { char format[4]; /* make 4 byte word sized */ @@ -89,16 +82,8 @@ static void pg_uninstall_parachute(void); static void pg_atexit_quit(void); -static int -pgGetArrayStruct(PyObject *, PyObject **, PyArrayInterface **); -static PyObject * -pgArrayStruct_AsDict(PyArrayInterface *); static PyObject * pgBuffer_AsArrayInterface(Py_buffer *); -static PyObject * -pgBuffer_AsArrayStruct(Py_buffer *); -static int -_pg_buffer_is_byteswapped(Py_buffer *); static void pgBuffer_Release(pg_buffer *); static int @@ -106,12 +91,6 @@ pgObject_GetBuffer(PyObject *, pg_buffer *, int); static int pgGetArrayInterface(PyObject **, PyObject *); static int -pgArrayStruct_AsBuffer(pg_buffer *, PyObject *, PyArrayInterface *, int); -static int -_pg_arraystruct_as_buffer(Py_buffer *, PyObject *, PyArrayInterface *, int); -static int -_pg_arraystruct_to_format(char *, PyArrayInterface *, int); -static int pgDict_AsBuffer(pg_buffer *, PyObject *, int); static int _pg_shape_check(PyObject *); @@ -142,22 +121,6 @@ static char _pg_as_arrayinter_typekind(Py_buffer *); static char _pg_as_arrayinter_byteorder(Py_buffer *); -static int -_pg_as_arrayinter_flags(Py_buffer *); -static pgCapsuleInterface * -_pg_new_capsuleinterface(Py_buffer *); -static void -_pg_capsule_PyMem_Free(PyObject *); -static PyObject * -_pg_shape_as_tuple(PyArrayInterface *); -static PyObject * -_pg_typekind_as_str(PyArrayInterface *); -static PyObject * -_pg_strides_as_tuple(PyArrayInterface *); -static PyObject * -_pg_data_as_tuple(PyArrayInterface *); -static PyObject * -pg_get_array_interface(PyObject *, PyObject *); static void _pg_release_buffer_array(Py_buffer *); static void @@ -777,64 +740,6 @@ pg_set_error(PyObject *s, PyObject *args) } /*array interface*/ - -static int -pgGetArrayStruct(PyObject *obj, PyObject **cobj_p, PyArrayInterface **inter_p) -{ - PyObject *cobj = PyObject_GetAttrString(obj, "__array_struct__"); - PyArrayInterface *inter = NULL; - - if (cobj == NULL) { - if (PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Clear(); - PyErr_SetString(PyExc_ValueError, "no C-struct array interface"); - } - return -1; - } - - if (PyCapsule_IsValid(cobj, NULL)) { - inter = (PyArrayInterface *)PyCapsule_GetPointer(cobj, NULL); - } - - if (inter == NULL || inter->two != 2 /* conditional or */) { - Py_DECREF(cobj); - PyErr_SetString(PyExc_ValueError, "invalid array interface"); - return -1; - } - - *cobj_p = cobj; - *inter_p = inter; - return 0; -} - -static PyObject * -pgArrayStruct_AsDict(PyArrayInterface *inter_p) -{ - PyObject *dictobj = Py_BuildValue("{sisNsNsNsN}", "version", (int)3, - "typestr", _pg_typekind_as_str(inter_p), - "shape", _pg_shape_as_tuple(inter_p), - "strides", _pg_strides_as_tuple(inter_p), - "data", _pg_data_as_tuple(inter_p)); - - if (!dictobj) { - return 0; - } - if (inter_p->flags & PAI_ARR_HAS_DESCR) { - if (!inter_p->descr) { - Py_DECREF(dictobj); - PyErr_SetString(PyExc_ValueError, - "Array struct has descr flag set" - " but no descriptor"); - return 0; - } - if (PyDict_SetItemString(dictobj, "descr", inter_p->descr)) { - Py_DECREF(dictobj); - return 0; - } - } - return dictobj; -} - static PyObject * pgBuffer_AsArrayInterface(Py_buffer *view_p) { @@ -845,84 +750,6 @@ pgBuffer_AsArrayInterface(Py_buffer *view_p) pg_view_get_data_obj(view_p)); } -static PyObject * -pgBuffer_AsArrayStruct(Py_buffer *view_p) -{ - void *cinter_p = _pg_new_capsuleinterface(view_p); - PyObject *capsule; - - if (!cinter_p) { - return 0; - } - capsule = PyCapsule_New(cinter_p, 0, _pg_capsule_PyMem_Free); - if (!capsule) { - PyMem_Free(cinter_p); - return 0; - } - return capsule; -} - -static pgCapsuleInterface * -_pg_new_capsuleinterface(Py_buffer *view_p) -{ - int ndim = view_p->ndim; - Py_ssize_t cinter_size; - pgCapsuleInterface *cinter_p; - int i; - - cinter_size = - (sizeof(pgCapsuleInterface) + sizeof(Py_intptr_t) * (2 * ndim - 1)); - cinter_p = (pgCapsuleInterface *)PyMem_Malloc(cinter_size); - if (!cinter_p) { - PyErr_NoMemory(); - return 0; - } - cinter_p->inter.two = 2; - cinter_p->inter.nd = ndim; - cinter_p->inter.typekind = _pg_as_arrayinter_typekind(view_p); - cinter_p->inter.itemsize = (int)view_p->itemsize; - cinter_p->inter.flags = _pg_as_arrayinter_flags(view_p); - if (view_p->shape) { - cinter_p->inter.shape = cinter_p->imem; - for (i = 0; i < ndim; ++i) { - cinter_p->inter.shape[i] = (Py_intptr_t)view_p->shape[i]; - } - } - if (view_p->strides) { - cinter_p->inter.strides = cinter_p->imem + ndim; - for (i = 0; i < ndim; ++i) { - cinter_p->inter.strides[i] = (Py_intptr_t)view_p->strides[i]; - } - } - cinter_p->inter.data = view_p->buf; - cinter_p->inter.descr = 0; - return cinter_p; -} - -static void -_pg_capsule_PyMem_Free(PyObject *capsule) -{ - PyMem_Free(PyCapsule_GetPointer(capsule, 0)); -} - -static int -_pg_as_arrayinter_flags(Py_buffer *view_p) -{ - int inter_flags = PAI_ALIGNED; /* atomic int types always aligned */ - - if (!view_p->readonly) { - inter_flags |= PAI_WRITEABLE; - } - inter_flags |= _pg_buffer_is_byteswapped(view_p) ? 0 : PAI_NOTSWAPPED; - if (PyBuffer_IsContiguous(view_p, 'C')) { - inter_flags |= PAI_CONTIGUOUS; - } - if (PyBuffer_IsContiguous(view_p, 'F')) { - inter_flags |= PAI_FORTRAN; - } - return inter_flags; -} - static PyObject * pg_view_get_typestr_obj(Py_buffer *view) { @@ -1052,91 +879,11 @@ _pg_as_arrayinter_byteorder(Py_buffer *view) return byteorder; } -static PyObject * -_pg_shape_as_tuple(PyArrayInterface *inter_p) -{ - PyObject *shapeobj = PyTuple_New((Py_ssize_t)inter_p->nd); - PyObject *lengthobj; - Py_ssize_t i; - - if (!shapeobj) { - return 0; - } - for (i = 0; i < inter_p->nd; ++i) { - lengthobj = PyLong_FromLong((long)inter_p->shape[i]); - if (!lengthobj) { - Py_DECREF(shapeobj); - return 0; - } - PyTuple_SET_ITEM(shapeobj, i, lengthobj); - } - return shapeobj; -} - -static PyObject * -_pg_typekind_as_str(PyArrayInterface *inter_p) -{ - return PyUnicode_FromFormat( - "%c%c%i", - inter_p->itemsize > 1 - ? ((inter_p->flags & PAI_NOTSWAPPED) ? PAI_MY_ENDIAN - : PAI_OTHER_ENDIAN) - : '|', - inter_p->typekind, inter_p->itemsize); -} - -static PyObject * -_pg_strides_as_tuple(PyArrayInterface *inter_p) -{ - PyObject *stridesobj = PyTuple_New((Py_ssize_t)inter_p->nd); - PyObject *lengthobj; - Py_ssize_t i; - - if (!stridesobj) { - return 0; - } - for (i = 0; i < inter_p->nd; ++i) { - lengthobj = PyLong_FromLong((long)inter_p->strides[i]); - if (!lengthobj) { - Py_DECREF(stridesobj); - return 0; - } - PyTuple_SET_ITEM(stridesobj, i, lengthobj); - } - return stridesobj; -} - -static PyObject * -_pg_data_as_tuple(PyArrayInterface *inter_p) -{ - long readonly = (inter_p->flags & PAI_WRITEABLE) == 0; - - return Py_BuildValue("NN", PyLong_FromVoidPtr(inter_p->data), - PyBool_FromLong(readonly)); -} - -static PyObject * -pg_get_array_interface(PyObject *self, PyObject *arg) -{ - PyObject *cobj; - PyArrayInterface *inter_p; - PyObject *dictobj; - - if (pgGetArrayStruct(arg, &cobj, &inter_p)) { - return 0; - } - dictobj = pgArrayStruct_AsDict(inter_p); - Py_DECREF(cobj); - return dictobj; -} - static int pgObject_GetBuffer(PyObject *obj, pg_buffer *pg_view_p, int flags) { Py_buffer *view_p = (Py_buffer *)pg_view_p; - PyObject *cobj = 0; PyObject *dict = 0; - PyArrayInterface *inter_p = 0; int success = 0; pg_view_p->release_buffer = _pg_release_buffer_generic; @@ -1226,20 +973,6 @@ pgObject_GetBuffer(PyObject *obj, pg_buffer *pg_view_p, int flags) PyErr_Clear(); } - if (!success && pgGetArrayStruct(obj, &cobj, &inter_p) == 0) { - if (pgArrayStruct_AsBuffer(pg_view_p, cobj, inter_p, flags)) { - Py_DECREF(cobj); - return -1; - } - Py_INCREF(obj); - view_p->obj = obj; - Py_DECREF(cobj); - success = 1; - } - else if (!success) { - PyErr_Clear(); - } - if (!success && pgGetArrayInterface(&dict, obj) == 0) { if (pgDict_AsBuffer(pg_view_p, dict, flags)) { Py_DECREF(dict); @@ -1295,31 +1028,6 @@ _pg_release_buffer_array(Py_buffer *view_p) _pg_release_buffer_generic(view_p); } -static int -_pg_buffer_is_byteswapped(Py_buffer *view) -{ - if (view->format) { - switch (view->format[0]) { - case '<': -#if SDL_BYTEORDER == SDL_LIL_ENDIAN - /* Use macros to make static analyzer happy */ - return 0; -#else - return 1; -#endif - case '>': - case '!': -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - /* Use macros to make static analyzer happy */ - return 0; -#else - return 1; -#endif - } - } - return 0; -} - static int pgGetArrayInterface(PyObject **dict, PyObject *obj) { @@ -1343,239 +1051,6 @@ pgGetArrayInterface(PyObject **dict, PyObject *obj) return 0; } -static int -pgArrayStruct_AsBuffer(pg_buffer *pg_view_p, PyObject *cobj, - PyArrayInterface *inter_p, int flags) -{ - pg_view_p->release_buffer = _pg_release_buffer_array; - if (_pg_arraystruct_as_buffer((Py_buffer *)pg_view_p, cobj, inter_p, - flags)) { - pgBuffer_Release(pg_view_p); - return -1; - } - return 0; -} - -static int -_pg_arraystruct_as_buffer(Py_buffer *view_p, PyObject *cobj, - PyArrayInterface *inter_p, int flags) -{ - pgViewInternals *internal_p; - Py_ssize_t sz = - (sizeof(pgViewInternals) + (2 * inter_p->nd - 1) * sizeof(Py_ssize_t)); - int readonly = (inter_p->flags & PAI_WRITEABLE) ? 0 : 1; - Py_ssize_t i; - - view_p->obj = 0; - view_p->internal = 0; - if (PyBUF_HAS_FLAG(flags, PyBUF_WRITABLE) && readonly) { - PyErr_SetString(pgExc_BufferError, - "require writable buffer, but it is read-only"); - return -1; - } - if (PyBUF_HAS_FLAG(flags, PyBUF_ANY_CONTIGUOUS)) { - if (!(inter_p->flags & (PAI_CONTIGUOUS | PAI_FORTRAN))) { - PyErr_SetString(pgExc_BufferError, - "buffer data is not contiguous"); - return -1; - } - } - else if (PyBUF_HAS_FLAG(flags, PyBUF_C_CONTIGUOUS)) { - if (!(inter_p->flags & PAI_CONTIGUOUS)) { - PyErr_SetString(pgExc_BufferError, - "buffer data is not C contiguous"); - return -1; - } - } - else if (PyBUF_HAS_FLAG(flags, PyBUF_F_CONTIGUOUS)) { - if (!(inter_p->flags & PAI_FORTRAN)) { - PyErr_SetString(pgExc_BufferError, - "buffer data is not F contiguous"); - return -1; - } - } - internal_p = (pgViewInternals *)PyMem_Malloc(sz); - if (!internal_p) { - PyErr_NoMemory(); - return -1; - } - view_p->internal = internal_p; - if (PyBUF_HAS_FLAG(flags, PyBUF_FORMAT)) { - if (_pg_arraystruct_to_format(internal_p->format, inter_p, - sizeof(internal_p->format))) { - return -1; - } - view_p->format = internal_p->format; - } - else { - view_p->format = 0; - } - view_p->buf = inter_p->data; - view_p->itemsize = (Py_ssize_t)inter_p->itemsize; - view_p->readonly = readonly; - if (PyBUF_HAS_FLAG(flags, PyBUF_ND)) { - view_p->ndim = (Py_ssize_t)inter_p->nd; - view_p->shape = internal_p->imem; - for (i = 0; i < view_p->ndim; ++i) { - view_p->shape[i] = (Py_ssize_t)inter_p->shape[i]; - } - } - else if (inter_p->flags & PAI_CONTIGUOUS) { - view_p->ndim = 0; - view_p->shape = 0; - } - else { - PyErr_SetString(pgExc_BufferError, - "buffer data is not C contiguous, shape needed"); - return -1; - } - if (PyBUF_HAS_FLAG(flags, PyBUF_STRIDES)) { - view_p->strides = view_p->shape + inter_p->nd; - for (i = 0; i < view_p->ndim; ++i) { - view_p->strides[i] = (Py_ssize_t)inter_p->strides[i]; - } - } - else if (inter_p->flags & (PAI_CONTIGUOUS | PAI_FORTRAN)) { - view_p->strides = 0; - } - else { - PyErr_SetString(pgExc_BufferError, - "buffer is not contiguous, strides needed"); - return -1; - } - view_p->suboffsets = 0; - view_p->len = view_p->itemsize; - for (i = 0; i < inter_p->nd; ++i) { - view_p->len *= (Py_ssize_t)inter_p->shape[i]; - } - return 0; -} - -static int -_pg_arraystruct_to_format(char *format, PyArrayInterface *inter_p, - int max_format_len) -{ - char *fchar_p = format; - - assert(max_format_len >= 4); - switch (inter_p->typekind) { - case 'i': - *fchar_p = ((inter_p->flags & PAI_NOTSWAPPED) ? BUF_MY_ENDIAN - : BUF_OTHER_ENDIAN); - ++fchar_p; - switch (inter_p->itemsize) { - case 1: - *fchar_p = 'b'; - break; - case 2: - *fchar_p = 'h'; - break; - case 4: - *fchar_p = 'i'; - break; - case 8: - *fchar_p = 'q'; - break; - default: - PyErr_Format(PyExc_ValueError, - "Unsupported signed integer size %d", - (int)inter_p->itemsize); - return -1; - } - break; - case 'u': - *fchar_p = ((inter_p->flags & PAI_NOTSWAPPED) ? BUF_MY_ENDIAN - : BUF_OTHER_ENDIAN); - ++fchar_p; - switch (inter_p->itemsize) { - case 1: - *fchar_p = 'B'; - break; - case 2: - *fchar_p = 'H'; - break; - case 4: - *fchar_p = 'I'; - break; - case 8: - *fchar_p = 'Q'; - break; - default: - PyErr_Format(PyExc_ValueError, - "Unsupported unsigned integer size %d", - (int)inter_p->itemsize); - return -1; - } - break; - case 'f': - *fchar_p = ((inter_p->flags & PAI_NOTSWAPPED) ? BUF_MY_ENDIAN - : BUF_OTHER_ENDIAN); - ++fchar_p; - switch (inter_p->itemsize) { - case 4: - *fchar_p = 'f'; - break; - case 8: - *fchar_p = 'd'; - break; - default: - PyErr_Format(PyExc_ValueError, "Unsupported float size %d", - (int)inter_p->itemsize); - return -1; - } - break; - case 'V': - if (inter_p->itemsize > 9) { - PyErr_Format(PyExc_ValueError, "Unsupported void size %d", - (int)inter_p->itemsize); - return -1; - } - switch (inter_p->itemsize) { - case 1: - *fchar_p = '1'; - break; - case 2: - *fchar_p = '2'; - break; - case 3: - *fchar_p = '3'; - break; - case 4: - *fchar_p = '4'; - break; - case 5: - *fchar_p = '5'; - break; - case 6: - *fchar_p = '6'; - break; - case 7: - *fchar_p = '7'; - break; - case 8: - *fchar_p = '8'; - break; - case 9: - *fchar_p = '9'; - break; - default: - PyErr_Format(PyExc_ValueError, "Unsupported void size %d", - (int)inter_p->itemsize); - return -1; - } - ++fchar_p; - *fchar_p = 'x'; - break; - default: - PyErr_Format(PyExc_ValueError, "Unsupported value type '%c'", - (int)inter_p->typekind); - return -1; - } - ++fchar_p; - *fchar_p = '\0'; - return 0; -} - static int pgDict_AsBuffer(pg_buffer *pg_view_p, PyObject *dict, int flags) { @@ -2197,9 +1672,6 @@ static PyMethodDef _base_methods[] = { METH_VARARGS | METH_KEYWORDS, DOC_GETSDLVERSION}, {"get_sdl_byteorder", (PyCFunction)pg_get_sdl_byteorder, METH_NOARGS, DOC_GETSDLBYTEORDER}, - - {"get_array_interface", (PyCFunction)pg_get_array_interface, METH_O, - "return an array struct interface as an interface dictionary"}, {NULL, NULL, 0, NULL}}; #if defined(BUILD_STATIC) && defined(NO_PYGAME_C_API) @@ -2281,7 +1753,7 @@ MODINIT_DEFINE(base) c_api[11] = pg_mod_autoquit; c_api[12] = pg_RGBAFromObj; c_api[13] = pgBuffer_AsArrayInterface; - c_api[14] = pgBuffer_AsArrayStruct; + c_api[14] = pg_SetDefaultConvertFormat; c_api[15] = pgObject_GetBuffer; c_api[16] = pgBuffer_Release; c_api[17] = pgDict_AsBuffer; @@ -2295,9 +1767,8 @@ MODINIT_DEFINE(base) c_api[25] = pg_TwoDoublesFromObj; c_api[26] = pg_TwoDoublesFromFastcallArgs; c_api[27] = pg_GetDefaultConvertFormat; - c_api[28] = pg_SetDefaultConvertFormat; -#define FILLED_SLOTS 29 +#define FILLED_SLOTS 28 #if PYGAMEAPI_BASE_NUMSLOTS != FILLED_SLOTS #error export slot count mismatch diff --git a/src_c/bufferproxy.c b/src_c/bufferproxy.c index a8c4a436d1..3223e07aef 100644 --- a/src_c/bufferproxy.c +++ b/src_c/bufferproxy.c @@ -20,11 +20,8 @@ /* This module exports a proxy object that exposes another object's - data through the Python buffer protocol or the array interface. - The new buffer protocol is available for Python 3.x. For Python 2.x - only the old protocol is implemented (for PyPy compatibility). - Both the C level array structure - __array_struct__ - interface and - Python level - __array_interface__ - are exposed. + data through the Python buffer protocol or the python array + interface */ #define PY_SSIZE_T_CLEAN @@ -297,22 +294,6 @@ proxy_traverse(pgBufproxyObject *self, visitproc visit, void *arg) } /**** Getter and setter access ****/ -static PyObject * -proxy_get_arraystruct(pgBufproxyObject *self, PyObject *closure) -{ - Py_buffer *view_p = _proxy_get_view(self); - PyObject *capsule; - - if (!view_p) { - return 0; - } - capsule = pgBuffer_AsArrayStruct(view_p); - if (!capsule) { - _proxy_release_view(self); - } - return capsule; -} - static PyObject * proxy_get_arrayinterface(pgBufproxyObject *self, PyObject *closure) { @@ -464,8 +445,6 @@ static struct PyMethodDef proxy_methods[] = { * Getters and setters for the pgBufproxyObject. */ static PyGetSetDef proxy_getsets[] = { - {"__array_struct__", (getter)proxy_get_arraystruct, 0, - "Version 3 array interface, C level", 0}, {"__array_interface__", (getter)proxy_get_arrayinterface, 0, "Version 3 array interface, Python level", 0}, {"parent", (getter)proxy_get_parent, 0, DOC_BUFFERPROXY_PARENT, 0}, diff --git a/src_c/color.c b/src_c/color.c index 80761a4b0d..09aad33753 100644 --- a/src_c/color.c +++ b/src_c/color.c @@ -151,8 +151,6 @@ static PyObject * _color_get_normalized(pgColorObject *, void *); static int _color_set_normalized(pgColorObject *, PyObject *, void *); -static PyObject * -_color_get_arraystruct(pgColorObject *, void *); /* Number protocol methods */ static PyObject * @@ -265,8 +263,6 @@ static PyGetSetDef _color_getsets[] = { NULL}, {"normalized", (getter)_color_get_normalized, (setter)_color_set_normalized, DOC_COLOR_NORMALIZED, NULL}, - {"__array_struct__", (getter)_color_get_arraystruct, NULL, - "array structure interface, read only", NULL}, {NULL, NULL, NULL, NULL, NULL}}; static PyNumberMethods _color_as_number = { @@ -1571,20 +1567,6 @@ _color_set_normalized(pgColorObject *color, PyObject *value, void *closure) return 0; } -static PyObject * -_color_get_arraystruct(pgColorObject *color, void *closure) -{ - Py_buffer view; - PyObject *capsule; - - if (_color_getbuffer(color, &view, PyBUF_FULL_RO)) { - return 0; - } - capsule = pgBuffer_AsArrayStruct(&view); - Py_DECREF(color); - return capsule; -} - /* Number protocol methods */ /** diff --git a/src_c/include/_pygame.h b/src_c/include/_pygame.h index e1510b7756..d3f17f9d93 100644 --- a/src_c/include/_pygame.h +++ b/src_c/include/_pygame.h @@ -155,8 +155,8 @@ typedef struct pg_bufferinfo_s { #define pgBuffer_AsArrayInterface \ (*(PyObject * (*)(Py_buffer *)) PYGAMEAPI_GET_SLOT(base, 13)) -#define pgBuffer_AsArrayStruct \ - (*(PyObject * (*)(Py_buffer *)) PYGAMEAPI_GET_SLOT(base, 14)) +#define pg_SetDefaultConvertFormat \ + (*(SDL_PixelFormat * (*)(Uint32)) PYGAMEAPI_GET_SLOT(base, 14)) #define pgObject_GetBuffer \ (*(int (*)(PyObject *, pg_buffer *, int))PYGAMEAPI_GET_SLOT(base, 15)) @@ -186,9 +186,6 @@ typedef struct pg_bufferinfo_s { #define pg_GetDefaultConvertFormat \ (*(SDL_PixelFormat * (*)(void)) PYGAMEAPI_GET_SLOT(base, 27)) -#define pg_SetDefaultConvertFormat \ - (*(SDL_PixelFormat * (*)(Uint32)) PYGAMEAPI_GET_SLOT(base, 28)) - #define import_pygame_base() IMPORT_PYGAME_MODULE(base) #endif /* ~PYGAMEAPI_BASE_INTERNAL */ diff --git a/src_c/mixer.c b/src_c/mixer.c index f2f4ecb1f7..8b7e0eaccc 100644 --- a/src_c/mixer.c +++ b/src_c/mixer.c @@ -785,21 +785,6 @@ snd_get_raw(PyObject *self, PyObject *_null) (Py_ssize_t)chunk->alen); } -static PyObject * -snd_get_arraystruct(PyObject *self, void *closure) -{ - Py_buffer view; - PyObject *cobj; - - if (snd_getbuffer(self, &view, PyBUF_RECORDS)) { - return 0; - } - cobj = pgBuffer_AsArrayStruct(&view); - snd_releasebuffer(view.obj, &view); - Py_XDECREF(view.obj); - return cobj; -} - static PyObject * snd_get_arrayinterface(PyObject *self, void *closure) { @@ -845,7 +830,6 @@ PyMethodDef sound_methods[] = { {NULL, NULL, 0, NULL}}; static PyGetSetDef sound_getset[] = { - {"__array_struct__", snd_get_arraystruct, NULL, "Version 3", NULL}, {"__array_interface__", snd_get_arrayinterface, NULL, "Version 3", NULL}, {"_samples_address", (getter)snd_get_samples_address, NULL, "samples buffer address (readonly)", NULL}, diff --git a/src_c/pgarrinter.h b/src_c/pgarrinter.h deleted file mode 100644 index 5ba096be22..0000000000 --- a/src_c/pgarrinter.h +++ /dev/null @@ -1,26 +0,0 @@ -/* array structure interface version 3 declarations */ - -#if !defined(PG_ARRAYINTER_HEADER) -#define PG_ARRAYINTER_HEADER - -static const int PAI_CONTIGUOUS = 0x01; -static const int PAI_FORTRAN = 0x02; -static const int PAI_ALIGNED = 0x100; -static const int PAI_NOTSWAPPED = 0x200; -static const int PAI_WRITEABLE = 0x400; -static const int PAI_ARR_HAS_DESCR = 0x800; - -typedef struct { - int two; /* contains the integer 2 -- simple sanity check */ - int nd; /* number of dimensions */ - char typekind; /* kind in array -- character code of typestr */ - int itemsize; /* size of each element */ - int flags; /* flags indicating how the data should be */ - /* interpreted */ - Py_intptr_t *shape; /* A length-nd array of shape information */ - Py_intptr_t *strides; /* A length-nd array of stride information */ - void *data; /* A pointer to the first element of the array */ - PyObject *descr; /* NULL or a data-description */ -} PyArrayInterface; - -#endif diff --git a/src_c/pixelarray.c b/src_c/pixelarray.c index 26e631576d..0fe741cb96 100644 --- a/src_c/pixelarray.c +++ b/src_c/pixelarray.c @@ -79,8 +79,6 @@ _pxarray_get_strides(pgPixelArrayObject *, void *); static PyObject * _pxarray_get_ndim(pgPixelArrayObject *, void *); static PyObject * -_pxarray_get_arraystruct(pgPixelArrayObject *, void *); -static PyObject * _pxarray_get_arrayinterface(pgPixelArrayObject *, void *); static PyObject * _pxarray_get_pixelsaddress(pgPixelArrayObject *, void *); @@ -227,7 +225,6 @@ static PyGetSetDef _pxarray_getsets[] = { {"shape", (getter)_pxarray_get_shape, 0, DOC_PIXELARRAY_SHAPE, 0}, {"strides", (getter)_pxarray_get_strides, 0, DOC_PIXELARRAY_STRIDES, 0}, {"ndim", (getter)_pxarray_get_ndim, 0, DOC_PIXELARRAY_NDIM, 0}, - {"__array_struct__", (getter)_pxarray_get_arraystruct, 0, "Version 3", 0}, {"__array_interface__", (getter)_pxarray_get_arrayinterface, 0, "Version 3", 0}, {"_pixels_address", (getter)_pxarray_get_pixelsaddress, 0, @@ -481,24 +478,6 @@ _pxarray_get_ndim(pgPixelArrayObject *self, void *closure) return PyLong_FromLong(self->shape[1] ? 2L : 1L); } -/** - * Getter for PixelArray.__array_struct__ - * (array struct interface) - */ -static PyObject * -_pxarray_get_arraystruct(pgPixelArrayObject *self, void *closure) -{ - Py_buffer view; - PyObject *dict; - - if (_pxarray_getbuffer(self, &view, PyBUF_RECORDS)) { - return 0; - } - dict = pgBuffer_AsArrayStruct(&view); - Py_XDECREF(view.obj); - return dict; -} - static PyObject * _pxarray_get_arrayinterface(pgPixelArrayObject *self, void *closure) { diff --git a/test/base_test.py b/test/base_test.py index 0959295338..819f92f752 100644 --- a/test/base_test.py +++ b/test/base_test.py @@ -5,10 +5,6 @@ IS_PYPY = "PyPy" == platform.python_implementation() -try: - from pygame.tests.test_utils import arrinter -except NameError: - pass import pygame @@ -84,8 +80,6 @@ def get__array_interface__(self): } __array_interface__ = property(get__array_interface__) - # Should be ignored by PgObject_GetBuffer - __array_struct__ = property(lambda self: None) _shape = [2, 3, 5, 7, 11] # Some prime numbers for ndim in range(1, len(_shape)): @@ -151,48 +145,6 @@ def is_dict_alive(self): gc.collect() self.assertFalse(o.is_dict_alive()) - def test_GetView_array_struct(self): - from pygame.bufferproxy import BufferProxy - - class Exporter(self.ExporterBase): - def __init__(self, shape, typechar, itemsize): - super().__init__(shape, typechar, itemsize) - self.view = BufferProxy(self.__dict__) - - def get__array_struct__(self): - return self.view.__array_struct__ - - __array_struct__ = property(get__array_struct__) - # Should not cause PgObject_GetBuffer to fail - __array_interface__ = property(lambda self: None) - - _shape = [2, 3, 5, 7, 11] # Some prime numbers - for ndim in range(1, len(_shape)): - o = Exporter(_shape[0:ndim], "i", 2) - v = BufferProxy(o) - self.assertSame(v, o) - ndim = 2 - shape = _shape[0:ndim] - for typechar in ("i", "u"): - for itemsize in (1, 2, 4, 8): - o = Exporter(shape, typechar, itemsize) - v = BufferProxy(o) - self.assertSame(v, o) - for itemsize in (4, 8): - o = Exporter(shape, "f", itemsize) - v = BufferProxy(o) - self.assertSame(v, o) - - # Check returned cobject/capsule reference count - try: - from sys import getrefcount - except ImportError: - # PyPy: no reference counting - pass - else: - o = Exporter(shape, typechar, itemsize) - self.assertEqual(getrefcount(o.__array_struct__), 1) - from pygame.tests.test_utils import buftools def NEWBUF_assertSame(self, proxy, exp): @@ -378,105 +330,6 @@ def test_PgDict_AsBuffer_PyBUF_flags(self): self.assertEqual(b.buf, 1000000) self.assertRaises(BufferError, Importer, a, buftools.PyBUF_FULL) - @unittest.skipIf(IS_PYPY, "newbuf with ctypes") - def test_PgObject_AsBuffer_PyBUF_flags(self): - from pygame.bufferproxy import BufferProxy - import ctypes - - is_lil_endian = pygame.get_sdl_byteorder() == pygame.LIL_ENDIAN - fsys, frev = ("<", ">") if is_lil_endian else (">", "<") - buftools = self.buftools - Importer = buftools.Importer - e = arrinter.Exporter( - (10, 2), typekind="f", itemsize=ctypes.sizeof(ctypes.c_double) - ) - a = BufferProxy(e) - b = Importer(a, buftools.PyBUF_SIMPLE) - self.assertEqual(b.ndim, 0) - self.assertTrue(b.format is None) - self.assertEqual(b.len, e.len) - self.assertEqual(b.itemsize, e.itemsize) - self.assertTrue(b.shape is None) - self.assertTrue(b.strides is None) - self.assertTrue(b.suboffsets is None) - self.assertFalse(b.readonly) - self.assertEqual(b.buf, e.data) - b = Importer(a, buftools.PyBUF_WRITABLE) - self.assertEqual(b.ndim, 0) - self.assertTrue(b.format is None) - self.assertEqual(b.len, e.len) - self.assertEqual(b.itemsize, e.itemsize) - self.assertTrue(b.shape is None) - self.assertTrue(b.strides is None) - self.assertTrue(b.suboffsets is None) - self.assertFalse(b.readonly) - self.assertEqual(b.buf, e.data) - b = Importer(a, buftools.PyBUF_ND) - self.assertEqual(b.ndim, e.nd) - self.assertTrue(b.format is None) - self.assertEqual(b.len, a.length) - self.assertEqual(b.itemsize, e.itemsize) - self.assertEqual(b.shape, e.shape) - self.assertTrue(b.strides is None) - self.assertTrue(b.suboffsets is None) - self.assertFalse(b.readonly) - self.assertEqual(b.buf, e.data) - e = arrinter.Exporter((5, 10), typekind="i", itemsize=2, strides=(24, 2)) - a = BufferProxy(e) - b = Importer(a, buftools.PyBUF_STRIDES) - self.assertEqual(b.ndim, e.nd) - self.assertTrue(b.format is None) - self.assertEqual(b.len, e.len) - self.assertEqual(b.itemsize, e.itemsize) - self.assertEqual(b.shape, e.shape) - self.assertEqual(b.strides, e.strides) - self.assertTrue(b.suboffsets is None) - self.assertFalse(b.readonly) - self.assertEqual(b.buf, e.data) - b = Importer(a, buftools.PyBUF_FULL_RO) - self.assertEqual(b.ndim, e.nd) - self.assertEqual(b.format, "=h") - self.assertEqual(b.len, e.len) - self.assertEqual(b.itemsize, e.itemsize) - self.assertEqual(b.shape, e.shape) - self.assertEqual(b.strides, e.strides) - self.assertTrue(b.suboffsets is None) - self.assertFalse(b.readonly) - self.assertEqual(b.buf, e.data) - self.assertRaises(BufferError, Importer, a, buftools.PyBUF_SIMPLE) - self.assertRaises(BufferError, Importer, a, buftools.PyBUF_WRITABLE) - self.assertRaises(BufferError, Importer, a, buftools.PyBUF_WRITABLE) - self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ND) - self.assertRaises(BufferError, Importer, a, buftools.PyBUF_C_CONTIGUOUS) - self.assertRaises(BufferError, Importer, a, buftools.PyBUF_F_CONTIGUOUS) - self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ANY_CONTIGUOUS) - self.assertRaises(BufferError, Importer, a, buftools.PyBUF_CONTIG) - self.assertRaises(BufferError, Importer, a, buftools.PyBUF_SIMPLE) - self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ND) - self.assertRaises(BufferError, Importer, a, buftools.PyBUF_C_CONTIGUOUS) - self.assertRaises(BufferError, Importer, a, buftools.PyBUF_F_CONTIGUOUS) - self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ANY_CONTIGUOUS) - self.assertRaises(BufferError, Importer, a, buftools.PyBUF_CONTIG) - e = arrinter.Exporter( - (3, 5, 10), - typekind="i", - itemsize=2, - strides=(120, 24, 2), - flags=arrinter.PAI_ALIGNED, - ) - a = BufferProxy(e) - b = Importer(a, buftools.PyBUF_FULL_RO) - self.assertEqual(b.ndim, e.nd) - self.assertEqual(b.format, frev + "h") - self.assertEqual(b.len, e.len) - self.assertEqual(b.itemsize, e.itemsize) - self.assertEqual(b.shape, e.shape) - self.assertEqual(b.strides, e.strides) - self.assertTrue(b.suboffsets is None) - self.assertTrue(b.readonly) - self.assertEqual(b.buf, e.data) - self.assertRaises(BufferError, Importer, a, buftools.PyBUF_FULL) - def test_PgObject_GetBuffer_exception(self): # For consistency with surfarray from pygame.bufferproxy import BufferProxy diff --git a/test/bufferproxy_test.py b/test/bufferproxy_test.py index bd0b22f4c3..4db517ba48 100644 --- a/test/bufferproxy_test.py +++ b/test/bufferproxy_test.py @@ -28,17 +28,6 @@ def test_module_name(self): def test_class_name(self): self.assertEqual(BufferProxy.__name__, "BufferProxy") - def test___array_struct___property(self): - kwds = self.view_keywords - v = BufferProxy(kwds) - d = pygame.get_array_interface(v) - self.assertEqual(len(d), 5) - self.assertEqual(d["version"], 3) - self.assertEqual(d["shape"], kwds["shape"]) - self.assertEqual(d["typestr"], kwds["typestr"]) - self.assertEqual(d["data"], kwds["data"]) - self.assertEqual(d["strides"], kwds["strides"]) - def test___array_interface___property(self): kwds = self.view_keywords v = BufferProxy(kwds) @@ -86,25 +75,6 @@ def raise_exception(parent): gc.collect() self.assertEqual(len(success), 1) - # For array struct - success = [] - kwds["before"] = callback - v = BufferProxy(kwds) - self.assertEqual(len(success), 0) - c = v.__array_struct__ - self.assertEqual(len(success), 1) - self.assertTrue(success[0]) - c = v.__array_struct__ - self.assertEqual(len(success), 1) - c = v = None - gc.collect() - self.assertEqual(len(success), 1) - - # Callback raises an exception - kwds["before"] = raise_exception - v = BufferProxy(kwds) - self.assertRaises(MyException, lambda: v.__array_struct__) - def test_after(self): def callback(parent): success.append(parent is p) @@ -127,20 +97,6 @@ def callback(parent): self.assertEqual(len(success), 1) self.assertTrue(success[0]) - # For array struct - success = [] - kwds["after"] = callback - v = BufferProxy(kwds) - self.assertEqual(len(success), 0) - c = v.__array_struct__ - self.assertEqual(len(success), 0) - c = v.__array_struct__ - self.assertEqual(len(success), 0) - c = v = None - gc.collect() - self.assertEqual(len(success), 1) - self.assertTrue(success[0]) - def test_attribute(self): v = BufferProxy(self.view_keywords) self.assertRaises(AttributeError, getattr, v, "undefined") diff --git a/test/color_test.py b/test/color_test.py index a34424e957..224444b108 100644 --- a/test/color_test.py +++ b/test/color_test.py @@ -1100,28 +1100,6 @@ def test_pickle(self): ################################################################################ # only available if ctypes module is also available - @unittest.skipIf(IS_PYPY, "PyPy has no ctypes") - def test_arraystruct(self): - import pygame.tests.test_utils.arrinter as ai - import ctypes as ct - - c_byte_p = ct.POINTER(ct.c_byte) - c = pygame.Color(5, 7, 13, 23) - flags = ai.PAI_CONTIGUOUS | ai.PAI_FORTRAN | ai.PAI_ALIGNED | ai.PAI_NOTSWAPPED - for i in range(1, 5): - c.set_length(i) - inter = ai.ArrayInterface(c) - self.assertEqual(inter.two, 2) - self.assertEqual(inter.nd, 1) - self.assertEqual(inter.typekind, "u") - self.assertEqual(inter.itemsize, 1) - self.assertEqual(inter.flags, flags) - self.assertEqual(inter.shape[0], i) - self.assertEqual(inter.strides[0], 1) - data = ct.cast(inter.data, c_byte_p) - for j in range(i): - self.assertEqual(data[j], c[j]) - def test_newbuf(self): from pygame.tests.test_utils import buftools from ctypes import cast, POINTER, c_uint8 diff --git a/test/freetype_test.py b/test/freetype_test.py index 200a9933bd..8c4984998a 100644 --- a/test/freetype_test.py +++ b/test/freetype_test.py @@ -9,12 +9,6 @@ IS_PYPY = "PyPy" == platform.python_implementation() - -try: - from pygame.tests.test_utils import arrinter -except NameError: - pass - import pygame import pygame.freetype as ft @@ -1107,46 +1101,6 @@ def test_freetype_Font_render_raw_to(self): TypeError, font.render_raw_to, surf_buf, text, dest, size=24 ) - def test_freetype_Font_text_is_None_with_arr(self): - f = ft.Font(self._sans_path, 36) - f.style = ft.STYLE_NORMAL - f.rotation = 0 - text = "ABCD" - - # reference values - get_rect = f.get_rect(text) - f.vertical = True - get_rect_vert = f.get_rect(text) - - self.assertTrue(get_rect_vert.width < get_rect.width) - self.assertTrue(get_rect_vert.height > get_rect.height) - f.vertical = False - render_to_surf = pygame.Surface(get_rect.size, pygame.SRCALPHA, 32) - - if IS_PYPY: - return - - arr = arrinter.Array(get_rect.size, "u", 1) - render = f.render(text, (0, 0, 0)) - render_to = f.render_to(render_to_surf, (0, 0), text, (0, 0, 0)) - render_raw = f.render_raw(text) - render_raw_to = f.render_raw_to(arr, text) - - # comparisons - surf = pygame.Surface(get_rect.size, pygame.SRCALPHA, 32) - self.assertEqual(f.get_rect(None), get_rect) - s, r = f.render(None, (0, 0, 0)) - self.assertEqual(r, render[1]) - self.assertTrue(surf_same_image(s, render[0])) - r = f.render_to(surf, (0, 0), None, (0, 0, 0)) - self.assertEqual(r, render_to) - self.assertTrue(surf_same_image(surf, render_to_surf)) - px, sz = f.render_raw(None) - self.assertEqual(sz, render_raw[1]) - self.assertEqual(px, render_raw[0]) - sz = f.render_raw_to(arr, None) - self.assertEqual(sz, render_raw_to) - def test_freetype_Font_text_is_None(self): f = ft.Font(self._sans_path, 36) f.style = ft.STYLE_NORMAL @@ -1610,12 +1564,10 @@ def ref_items(seq): except ImportError: pass else: - array = arrinter.Array(rect.size, "u", 1) o = font.render_raw(text) self.assertEqual(getrefcount(o), 2) self.assertEqual(getrefcount(o[0]), 2) self.assertEqual(getrefcount(o[1]), 2) - self.assertEqual(getrefcount(font.render_raw_to(array, text)), 1) o = font.get_metrics("AB") self.assertEqual(getrefcount(o), 2) for i in range(len(o)): diff --git a/test/pixelarray_test.py b/test/pixelarray_test.py index 942931c2ad..bcad680b4e 100644 --- a/test/pixelarray_test.py +++ b/test/pixelarray_test.py @@ -7,12 +7,6 @@ from functools import reduce from pygame.tests.test_utils import SurfaceSubclass - -try: - from pygame.tests.test_utils import arrinter -except NameError: - pass - import pygame @@ -1333,72 +1327,7 @@ def test_assign_seq_to_single(self): test[400, 400] = [255, 255, 0] -@unittest.skipIf(IS_PYPY, "pypy having issues") class PixelArrayArrayInterfaceTest(unittest.TestCase, TestMixin): - @unittest.skipIf(IS_PYPY, "skipping for PyPy (why?)") - def test_basic(self): - # Check unchanging fields. - sf = pygame.Surface((2, 2), 0, 32) - ar = pygame.PixelArray(sf) - - ai = arrinter.ArrayInterface(ar) - self.assertEqual(ai.two, 2) - self.assertEqual(ai.typekind, "u") - self.assertEqual(ai.nd, 2) - self.assertEqual(ai.data, ar._pixels_address) - - @unittest.skipIf(IS_PYPY, "skipping for PyPy (why?)") - def test_shape(self): - for shape in [[4, 16], [5, 13]]: - w, h = shape - sf = pygame.Surface(shape, 0, 32) - ar = pygame.PixelArray(sf) - ai = arrinter.ArrayInterface(ar) - ai_shape = [ai.shape[i] for i in range(ai.nd)] - self.assertEqual(ai_shape, shape) - ar2 = ar[::2, :] - ai2 = arrinter.ArrayInterface(ar2) - w2 = len(([0] * w)[::2]) - ai_shape = [ai2.shape[i] for i in range(ai2.nd)] - self.assertEqual(ai_shape, [w2, h]) - ar2 = ar[:, ::2] - ai2 = arrinter.ArrayInterface(ar2) - h2 = len(([0] * h)[::2]) - ai_shape = [ai2.shape[i] for i in range(ai2.nd)] - self.assertEqual(ai_shape, [w, h2]) - - @unittest.skipIf(IS_PYPY, "skipping for PyPy (why?)") - def test_itemsize(self): - for bytes_per_pixel in range(1, 5): - bits_per_pixel = 8 * bytes_per_pixel - sf = pygame.Surface((2, 2), 0, bits_per_pixel) - ar = pygame.PixelArray(sf) - ai = arrinter.ArrayInterface(ar) - self.assertEqual(ai.itemsize, bytes_per_pixel) - - @unittest.skipIf(IS_PYPY, "skipping for PyPy (why?)") - def test_flags(self): - aim = arrinter - common_flags = aim.PAI_NOTSWAPPED | aim.PAI_WRITEABLE | aim.PAI_ALIGNED - s = pygame.Surface((10, 2), 0, 32) - ar = pygame.PixelArray(s) - ai = aim.ArrayInterface(ar) - self.assertEqual(ai.flags, common_flags | aim.PAI_FORTRAN) - - ar2 = ar[::2, :] - ai = aim.ArrayInterface(ar2) - self.assertEqual(ai.flags, common_flags) - - s = pygame.Surface((8, 2), 0, 24) - ar = pygame.PixelArray(s) - ai = aim.ArrayInterface(ar) - self.assertEqual(ai.flags, common_flags | aim.PAI_FORTRAN) - - s = pygame.Surface((7, 2), 0, 24) - ar = pygame.PixelArray(s) - ai = aim.ArrayInterface(ar) - self.assertEqual(ai.flags, common_flags) - def test_slicing(self): # This will implicitly test data and strides fields. # diff --git a/test/pixelcopy_test.py b/test/pixelcopy_test.py index 662918d120..3fbd511e6c 100644 --- a/test/pixelcopy_test.py +++ b/test/pixelcopy_test.py @@ -1,10 +1,6 @@ import platform import unittest -try: - from pygame.tests.test_utils import arrinter -except NameError: - pass import pygame from pygame.locals import * from pygame.pixelcopy import surface_to_array, map_array, array_to_surface, make_surface @@ -130,34 +126,6 @@ def test_surface_to_array_2d(self): dp, sp, "%s != %s: bpp: %i" % (dp, sp, surf.get_bitsize()) ) - if IS_PYPY: - return - # Swapped endian destination array - pai_flags = arrinter.PAI_ALIGNED | arrinter.PAI_WRITEABLE - for surf in self.sources: - for itemsize in [1, 2, 4, 8]: - if itemsize < surf.get_bytesize(): - continue - a = arrinter.Array(surf.get_size(), "u", itemsize, flags=pai_flags) - surface_to_array(a, surf) - for posn, i in self.test_points: - sp = unsigned32(surf.get_at_mapped(posn)) - dp = a[posn] - self.assertEqual( - dp, - sp, - "%s != %s: itemsize: %i, flags: %i" - ", bpp: %i, posn: %s" - % ( - dp, - sp, - itemsize, - surf.get_flags(), - surf.get_bitsize(), - posn, - ), - ) - def test_surface_to_array_3d(self): self.iter_surface_to_array_3d((0xFF, 0xFF00, 0xFF0000, 0)) self.iter_surface_to_array_3d((0xFF0000, 0xFF00, 0xFF, 0)) diff --git a/test/surface_test.py b/test/surface_test.py index ca60ccb8e0..14c70ad66f 100644 --- a/test/surface_test.py +++ b/test/surface_test.py @@ -6,10 +6,6 @@ SurfaceSubclass, ) -try: - from pygame.tests.test_utils.arrinter import * -except (ImportError, NameError): - pass import pygame from pygame.locals import * from pygame.bufferproxy import BufferProxy @@ -780,9 +776,6 @@ def test_get_view(self): # Check default argument value: '2' s = pygame.Surface((2, 4), 0, 32) v = s.get_view() - if not IS_PYPY: - ai = ArrayInterface(v) - self.assertEqual(ai.nd, 2) # Check locking. s = pygame.Surface((2, 4), 0, 32) @@ -2840,184 +2833,8 @@ def test_subsurface(self): class SurfaceGetBufferTest(unittest.TestCase): # These tests require ctypes. They are disabled if ctypes # is not installed. - try: - ArrayInterface - except NameError: - __tags__ = ("ignore", "subprocess_ignore") - lilendian = pygame.get_sdl_byteorder() == pygame.LIL_ENDIAN - def _check_interface_2D(self, s): - s_w, s_h = s.get_size() - s_bytesize = s.get_bytesize() - s_pitch = s.get_pitch() - s_pixels = s._pixels_address - - # check the array interface structure fields. - v = s.get_view("2") - if not IS_PYPY: - flags = PAI_ALIGNED | PAI_NOTSWAPPED | PAI_WRITEABLE - if s.get_pitch() == s_w * s_bytesize: - flags |= PAI_FORTRAN - - inter = ArrayInterface(v) - - self.assertEqual(inter.two, 2) - self.assertEqual(inter.nd, 2) - self.assertEqual(inter.typekind, "u") - self.assertEqual(inter.itemsize, s_bytesize) - self.assertEqual(inter.shape[0], s_w) - self.assertEqual(inter.shape[1], s_h) - self.assertEqual(inter.strides[0], s_bytesize) - self.assertEqual(inter.strides[1], s_pitch) - self.assertEqual(inter.flags, flags) - self.assertEqual(inter.data, s_pixels) - - def _check_interface_3D(self, s): - s_w, s_h = s.get_size() - s_bytesize = s.get_bytesize() - s_pitch = s.get_pitch() - s_pixels = s._pixels_address - s_shifts = list(s.get_shifts()) - - # Check for RGB or BGR surface. - if s_shifts[0:3] == [0, 8, 16]: - if self.lilendian: - # RGB - offset = 0 - step = 1 - else: - # BGR - offset = s_bytesize - 1 - step = -1 - elif s_shifts[0:3] == [8, 16, 24]: - if self.lilendian: - # xRGB - offset = 1 - step = 1 - else: - # BGRx - offset = s_bytesize - 2 - step = -1 - elif s_shifts[0:3] == [16, 8, 0]: - if self.lilendian: - # BGR - offset = 2 - step = -1 - else: - # RGB - offset = s_bytesize - 3 - step = 1 - elif s_shifts[0:3] == [24, 16, 8]: - if self.lilendian: - # BGRx - offset = 2 - step = -1 - else: - # RGBx - offset = s_bytesize - 4 - step = -1 - else: - return - - # check the array interface structure fields. - v = s.get_view("3") - if not IS_PYPY: - inter = ArrayInterface(v) - flags = PAI_ALIGNED | PAI_NOTSWAPPED | PAI_WRITEABLE - self.assertEqual(inter.two, 2) - self.assertEqual(inter.nd, 3) - self.assertEqual(inter.typekind, "u") - self.assertEqual(inter.itemsize, 1) - self.assertEqual(inter.shape[0], s_w) - self.assertEqual(inter.shape[1], s_h) - self.assertEqual(inter.shape[2], 3) - self.assertEqual(inter.strides[0], s_bytesize) - self.assertEqual(inter.strides[1], s_pitch) - self.assertEqual(inter.strides[2], step) - self.assertEqual(inter.flags, flags) - self.assertEqual(inter.data, s_pixels + offset) - - def _check_interface_rgba(self, s, plane): - s_w, s_h = s.get_size() - s_bytesize = s.get_bytesize() - s_pitch = s.get_pitch() - s_pixels = s._pixels_address - s_shifts = s.get_shifts() - s_masks = s.get_masks() - - # Find the color plane position within the pixel. - if not s_masks[plane]: - return - alpha_shift = s_shifts[plane] - offset = alpha_shift // 8 - if not self.lilendian: - offset = s_bytesize - offset - 1 - - # check the array interface structure fields. - v = s.get_view("rgba"[plane]) - if not IS_PYPY: - inter = ArrayInterface(v) - flags = PAI_ALIGNED | PAI_NOTSWAPPED | PAI_WRITEABLE - self.assertEqual(inter.two, 2) - self.assertEqual(inter.nd, 2) - self.assertEqual(inter.typekind, "u") - self.assertEqual(inter.itemsize, 1) - self.assertEqual(inter.shape[0], s_w) - self.assertEqual(inter.shape[1], s_h) - self.assertEqual(inter.strides[0], s_bytesize) - self.assertEqual(inter.strides[1], s_pitch) - self.assertEqual(inter.flags, flags) - self.assertEqual(inter.data, s_pixels + offset) - - def test_array_interface(self): - self._check_interface_2D(pygame.Surface((5, 7), 0, 8)) - self._check_interface_2D(pygame.Surface((5, 7), 0, 16)) - self._check_interface_2D(pygame.Surface((5, 7), pygame.SRCALPHA, 16)) - self._check_interface_3D(pygame.Surface((5, 7), 0, 24)) - self._check_interface_3D(pygame.Surface((8, 4), 0, 24)) # No gaps - self._check_interface_2D(pygame.Surface((5, 7), 0, 32)) - self._check_interface_3D(pygame.Surface((5, 7), 0, 32)) - self._check_interface_2D(pygame.Surface((5, 7), pygame.SRCALPHA, 32)) - self._check_interface_3D(pygame.Surface((5, 7), pygame.SRCALPHA, 32)) - - def test_array_interface_masks(self): - """Test non-default color byte orders on 3D views""" - - sz = (5, 7) - # Reversed RGB byte order - s = pygame.Surface(sz, 0, 32) - s_masks = list(s.get_masks()) - masks = [0xFF, 0xFF00, 0xFF0000] - if s_masks[0:3] == masks or s_masks[0:3] == masks[::-1]: - masks = s_masks[2::-1] + s_masks[3:4] - self._check_interface_3D(pygame.Surface(sz, 0, 32, masks)) - s = pygame.Surface(sz, 0, 24) - s_masks = list(s.get_masks()) - masks = [0xFF, 0xFF00, 0xFF0000] - if s_masks[0:3] == masks or s_masks[0:3] == masks[::-1]: - masks = s_masks[2::-1] + s_masks[3:4] - self._check_interface_3D(pygame.Surface(sz, 0, 24, masks)) - - masks = [0xFF00, 0xFF0000, 0xFF000000, 0] - self._check_interface_3D(pygame.Surface(sz, 0, 32, masks)) - - def test_array_interface_alpha(self): - for shifts in [[0, 8, 16, 24], [8, 16, 24, 0], [24, 16, 8, 0], [16, 8, 0, 24]]: - masks = [0xFF << s for s in shifts] - s = pygame.Surface((4, 2), pygame.SRCALPHA, 32, masks) - self._check_interface_rgba(s, 3) - - def test_array_interface_rgb(self): - for shifts in [[0, 8, 16, 24], [8, 16, 24, 0], [24, 16, 8, 0], [16, 8, 0, 24]]: - masks = [0xFF << s for s in shifts] - masks[3] = 0 - for plane in range(3): - s = pygame.Surface((4, 2), 0, 24) - self._check_interface_rgba(s, plane) - s = pygame.Surface((4, 2), 0, 32) - self._check_interface_rgba(s, plane) - def test_newbuf_PyBUF_flags_bytes(self): from pygame.tests.test_utils import buftools diff --git a/test/test_utils/arrinter.py b/test/test_utils/arrinter.py deleted file mode 100644 index 626913c9ce..0000000000 --- a/test/test_utils/arrinter.py +++ /dev/null @@ -1,438 +0,0 @@ -import sys -import ctypes -from ctypes import * -import unittest - -__all__ = [ - "PAI_CONTIGUOUS", - "PAI_FORTRAN", - "PAI_ALIGNED", - "PAI_NOTSWAPPED", - "PAI_WRITEABLE", - "PAI_ARR_HAS_DESCR", - "ArrayInterface", -] - -if sizeof(c_uint) == sizeof(c_void_p): - c_size_t = c_uint - c_ssize_t = c_int -elif sizeof(c_ulong) == sizeof(c_void_p): - c_size_t = c_ulong - c_ssize_t = c_long -elif sizeof(c_ulonglong) == sizeof(c_void_p): - c_size_t = c_ulonglong - c_ssize_t = c_longlong - - -SIZEOF_VOID_P = sizeof(c_void_p) -if SIZEOF_VOID_P <= sizeof(c_int): - Py_intptr_t = c_int -elif SIZEOF_VOID_P <= sizeof(c_long): - Py_intptr_t = c_long -elif "c_longlong" in globals() and SIZEOF_VOID_P <= sizeof(c_longlong): - Py_intptr_t = c_longlong -else: - raise RuntimeError("Unrecognized pointer size %i" % (SIZEOF_VOID_P,)) - - -class PyArrayInterface(Structure): - _fields_ = [ - ("two", c_int), - ("nd", c_int), - ("typekind", c_char), - ("itemsize", c_int), - ("flags", c_int), - ("shape", POINTER(Py_intptr_t)), - ("strides", POINTER(Py_intptr_t)), - ("data", c_void_p), - ("descr", py_object), - ] - - -PAI_Ptr = POINTER(PyArrayInterface) - -try: - PyCObject_AsVoidPtr = pythonapi.PyCObject_AsVoidPtr -except AttributeError: - - def PyCObject_AsVoidPtr(o): - raise TypeError("Not available") - -else: - PyCObject_AsVoidPtr.restype = c_void_p - PyCObject_AsVoidPtr.argtypes = [py_object] - PyCObject_GetDesc = pythonapi.PyCObject_GetDesc - PyCObject_GetDesc.restype = c_void_p - PyCObject_GetDesc.argtypes = [py_object] - -try: - PyCapsule_IsValid = pythonapi.PyCapsule_IsValid -except AttributeError: - - def PyCapsule_IsValid(capsule, name): - return 0 - -else: - PyCapsule_IsValid.restype = c_int - PyCapsule_IsValid.argtypes = [py_object, c_char_p] - PyCapsule_GetPointer = pythonapi.PyCapsule_GetPointer - PyCapsule_GetPointer.restype = c_void_p - PyCapsule_GetPointer.argtypes = [py_object, c_char_p] - PyCapsule_GetContext = pythonapi.PyCapsule_GetContext - PyCapsule_GetContext.restype = c_void_p - PyCapsule_GetContext.argtypes = [py_object] - -PyCapsule_Destructor = CFUNCTYPE(None, py_object) -PyCapsule_New = pythonapi.PyCapsule_New -PyCapsule_New.restype = py_object -PyCapsule_New.argtypes = [c_void_p, c_char_p, POINTER(PyCapsule_Destructor)] - - -def capsule_new(p): - return PyCapsule_New(addressof(p), None, None) - - -PAI_CONTIGUOUS = 0x01 -PAI_FORTRAN = 0x02 -PAI_ALIGNED = 0x100 -PAI_NOTSWAPPED = 0x200 -PAI_WRITEABLE = 0x400 -PAI_ARR_HAS_DESCR = 0x800 - - -class ArrayInterface: - def __init__(self, arr): - try: - self._cobj = arr.__array_struct__ - except AttributeError: - raise TypeError("The array object lacks an array structure") - if not self._cobj: - raise TypeError("The array object has a NULL array structure value") - try: - vp = PyCObject_AsVoidPtr(self._cobj) - except TypeError: - if PyCapsule_IsValid(self._cobj, None): - vp = PyCapsule_GetPointer(self._cobj, None) - else: - raise TypeError("The array object has an invalid array structure") - self.desc = PyCapsule_GetContext(self._cobj) - else: - self.desc = PyCObject_GetDesc(self._cobj) - self._inter = cast(vp, PAI_Ptr)[0] - - def __getattr__(self, name): - if name == "typekind": - return self._inter.typekind.decode("latin-1") - return getattr(self._inter, name) - - def __str__(self): - if isinstance(self.desc, tuple): - ver = self.desc[0] - else: - ver = "N/A" - return ( - "nd: %i\n" - "typekind: %s\n" - "itemsize: %i\n" - "flags: %s\n" - "shape: %s\n" - "strides: %s\n" - "ver: %s\n" - % ( - self.nd, - self.typekind, - self.itemsize, - format_flags(self.flags), - format_shape(self.nd, self.shape), - format_strides(self.nd, self.strides), - ver, - ) - ) - - -def format_flags(flags): - names = [] - for flag, name in [ - (PAI_CONTIGUOUS, "CONTIGUOUS"), - (PAI_FORTRAN, "FORTRAN"), - (PAI_ALIGNED, "ALIGNED"), - (PAI_NOTSWAPPED, "NOTSWAPPED"), - (PAI_WRITEABLE, "WRITEABLE"), - (PAI_ARR_HAS_DESCR, "ARR_HAS_DESCR"), - ]: - if flag & flags: - names.append(name) - return ", ".join(names) - - -def format_shape(nd, shape): - return ", ".join([str(shape[i]) for i in range(nd)]) - - -def format_strides(nd, strides): - return ", ".join([str(strides[i]) for i in range(nd)]) - - -class Exporter: - def __init__( - self, shape, typekind=None, itemsize=None, strides=None, descr=None, flags=None - ): - if typekind is None: - typekind = "u" - if itemsize is None: - itemsize = 1 - if flags is None: - flags = PAI_WRITEABLE | PAI_ALIGNED | PAI_NOTSWAPPED - if descr is not None: - flags |= PAI_ARR_HAS_DESCR - if len(typekind) != 1: - raise ValueError("Argument 'typekind' must be length 1 string") - nd = len(shape) - self.typekind = typekind - self.itemsize = itemsize - self.nd = nd - self.shape = tuple(shape) - self._shape = (c_ssize_t * self.nd)(*self.shape) - if strides is None: - self._strides = (c_ssize_t * self.nd)() - self._strides[self.nd - 1] = self.itemsize - for i in range(self.nd - 1, 0, -1): - self._strides[i - 1] = self.shape[i] * self._strides[i] - strides = tuple(self._strides) - self.strides = strides - elif len(strides) == nd: - self.strides = tuple(strides) - self._strides = (c_ssize_t * self.nd)(*self.strides) - else: - raise ValueError("Mismatch in length of strides and shape") - self.descr = descr - if self.is_contiguous("C"): - flags |= PAI_CONTIGUOUS - if self.is_contiguous("F"): - flags |= PAI_FORTRAN - self.flags = flags - sz = max(shape[i] * strides[i] for i in range(nd)) - self._data = (c_ubyte * sz)() - self.data = addressof(self._data) - self._inter = PyArrayInterface( - 2, - nd, - typekind.encode("latin_1"), - itemsize, - flags, - self._shape, - self._strides, - self.data, - descr, - ) - self.len = itemsize - for i in range(nd): - self.len *= self.shape[i] - - __array_struct__ = property(lambda self: capsule_new(self._inter)) - - def is_contiguous(self, fortran): - if fortran in "CA": - if self.strides[-1] == self.itemsize: - for i in range(self.nd - 1, 0, -1): - if self.strides[i - 1] != self.shape[i] * self.strides[i]: - break - else: - return True - if fortran in "FA": - if self.strides[0] == self.itemsize: - for i in range(0, self.nd - 1): - if self.strides[i + 1] != self.shape[i] * self.strides[i]: - break - else: - return True - return False - - -class Array(Exporter): - _ctypes = { - ("u", 1): c_uint8, - ("u", 2): c_uint16, - ("u", 4): c_uint32, - ("u", 8): c_uint64, - ("i", 1): c_int8, - ("i", 2): c_int16, - ("i", 4): c_int32, - ("i", 8): c_int64, - } - - def __init__(self, *args, **kwds): - super().__init__(*args, **kwds) - try: - if self.flags & PAI_NOTSWAPPED: - ct = self._ctypes[self.typekind, self.itemsize] - elif c_int.__ctype_le__ is c_int: - ct = self._ctypes[self.typekind, self.itemsize].__ctype_be__ - else: - ct = self._ctypes[self.typekind, self.itemsize].__ctype_le__ - except KeyError: - ct = c_uint8 * self.itemsize - self._ctype = ct - self._ctype_p = POINTER(ct) - - def __getitem__(self, key): - return cast(self._addr_at(key), self._ctype_p)[0] - - def __setitem__(self, key, value): - cast(self._addr_at(key), self._ctype_p)[0] = value - - def _addr_at(self, key): - if not isinstance(key, tuple): - key = (key,) - if len(key) != self.nd: - raise ValueError("wrong number of indexes") - for i in range(self.nd): - if not (0 <= key[i] < self.shape[i]): - raise IndexError(f"index {i} out of range") - return self.data + sum(i * s for i, s in zip(key, self.strides)) - - -class ExporterTest(unittest.TestCase): - def test_strides(self): - self.check_args(0, (10,), "u", (2,), 20, 20, 2) - self.check_args(0, (5, 3), "u", (6, 2), 30, 30, 2) - self.check_args(0, (7, 3, 5), "u", (30, 10, 2), 210, 210, 2) - self.check_args(0, (13, 5, 11, 3), "u", (330, 66, 6, 2), 4290, 4290, 2) - self.check_args(3, (7, 3, 5), "i", (2, 14, 42), 210, 210, 2) - self.check_args(3, (7, 3, 5), "x", (2, 16, 48), 210, 240, 2) - self.check_args(3, (13, 5, 11, 3), "%", (440, 88, 8, 2), 4290, 5720, 2) - self.check_args(3, (7, 5), "-", (15, 3), 105, 105, 3) - self.check_args(3, (7, 5), "*", (3, 21), 105, 105, 3) - self.check_args(3, (7, 5), " ", (3, 24), 105, 120, 3) - - def test_is_contiguous(self): - a = Exporter((10,), itemsize=2) - self.assertTrue(a.is_contiguous("C")) - self.assertTrue(a.is_contiguous("F")) - self.assertTrue(a.is_contiguous("A")) - a = Exporter((10, 4), itemsize=2) - self.assertTrue(a.is_contiguous("C")) - self.assertTrue(a.is_contiguous("A")) - self.assertFalse(a.is_contiguous("F")) - a = Exporter((13, 5, 11, 3), itemsize=2, strides=(330, 66, 6, 2)) - self.assertTrue(a.is_contiguous("C")) - self.assertTrue(a.is_contiguous("A")) - self.assertFalse(a.is_contiguous("F")) - a = Exporter((10, 4), itemsize=2, strides=(2, 20)) - self.assertTrue(a.is_contiguous("F")) - self.assertTrue(a.is_contiguous("A")) - self.assertFalse(a.is_contiguous("C")) - a = Exporter((13, 5, 11, 3), itemsize=2, strides=(2, 26, 130, 1430)) - self.assertTrue(a.is_contiguous("F")) - self.assertTrue(a.is_contiguous("A")) - self.assertFalse(a.is_contiguous("C")) - a = Exporter((2, 11, 6, 4), itemsize=2, strides=(576, 48, 8, 2)) - self.assertFalse(a.is_contiguous("A")) - a = Exporter((2, 11, 6, 4), itemsize=2, strides=(2, 4, 48, 288)) - self.assertFalse(a.is_contiguous("A")) - a = Exporter((3, 2, 2), itemsize=2, strides=(16, 8, 4)) - self.assertFalse(a.is_contiguous("A")) - a = Exporter((3, 2, 2), itemsize=2, strides=(4, 12, 24)) - self.assertFalse(a.is_contiguous("A")) - - def check_args( - self, call_flags, shape, typekind, strides, length, bufsize, itemsize, offset=0 - ): - if call_flags & 1: - typekind_arg = typekind - else: - typekind_arg = None - if call_flags & 2: - strides_arg = strides - else: - strides_arg = None - a = Exporter(shape, itemsize=itemsize, strides=strides_arg) - self.assertEqual(sizeof(a._data), bufsize) - self.assertEqual(a.data, ctypes.addressof(a._data) + offset) - m = ArrayInterface(a) - self.assertEqual(m.data, a.data) - self.assertEqual(m.itemsize, itemsize) - self.assertEqual(tuple(m.shape[0 : m.nd]), shape) - self.assertEqual(tuple(m.strides[0 : m.nd]), strides) - - -class ArrayTest(unittest.TestCase): - def __init__(self, *args, **kwds): - unittest.TestCase.__init__(self, *args, **kwds) - self.a = Array((20, 15), "i", 4) - - def setUp(self): - # Every test starts with a zeroed array. - memset(self.a.data, 0, sizeof(self.a._data)) - - def test__addr_at(self): - a = self.a - self.assertEqual(a._addr_at((0, 0)), a.data) - self.assertEqual(a._addr_at((0, 1)), a.data + 4) - self.assertEqual(a._addr_at((1, 0)), a.data + 60) - self.assertEqual(a._addr_at((1, 1)), a.data + 64) - - def test_indices(self): - a = self.a - self.assertEqual(a[0, 0], 0) - self.assertEqual(a[19, 0], 0) - self.assertEqual(a[0, 14], 0) - self.assertEqual(a[19, 14], 0) - self.assertEqual(a[5, 8], 0) - a[0, 0] = 12 - a[5, 8] = 99 - self.assertEqual(a[0, 0], 12) - self.assertEqual(a[5, 8], 99) - self.assertRaises(IndexError, a.__getitem__, (-1, 0)) - self.assertRaises(IndexError, a.__getitem__, (0, -1)) - self.assertRaises(IndexError, a.__getitem__, (20, 0)) - self.assertRaises(IndexError, a.__getitem__, (0, 15)) - self.assertRaises(ValueError, a.__getitem__, 0) - self.assertRaises(ValueError, a.__getitem__, (0, 0, 0)) - a = Array((3,), "i", 4) - a[1] = 333 - self.assertEqual(a[1], 333) - - def test_typekind(self): - a = Array((1,), "i", 4) - self.assertTrue(a._ctype is c_int32) - self.assertTrue(a._ctype_p is POINTER(c_int32)) - a = Array((1,), "u", 4) - self.assertTrue(a._ctype is c_uint32) - self.assertTrue(a._ctype_p is POINTER(c_uint32)) - a = Array((1,), "f", 4) # float types unsupported: size system dependent - ct = a._ctype - self.assertTrue(issubclass(ct, ctypes.Array)) - self.assertEqual(sizeof(ct), 4) - - def test_itemsize(self): - for size in [1, 2, 4, 8]: - a = Array((1,), "i", size) - ct = a._ctype - self.assertTrue(issubclass(ct, ctypes._SimpleCData)) - self.assertEqual(sizeof(ct), size) - - def test_oddball_itemsize(self): - for size in [3, 5, 6, 7, 9]: - a = Array((1,), "i", size) - ct = a._ctype - self.assertTrue(issubclass(ct, ctypes.Array)) - self.assertEqual(sizeof(ct), size) - - def test_byteswapped(self): - a = Array((1,), "u", 4, flags=(PAI_ALIGNED | PAI_WRITEABLE)) - ct = a._ctype - self.assertTrue(ct is not c_uint32) - if sys.byteorder == "little": - self.assertTrue(ct is c_uint32.__ctype_be__) - else: - self.assertTrue(ct is c_uint32.__ctype_le__) - i = 0xA0B0C0D - n = c_uint32(i) - a[0] = i - self.assertEqual(a[0], i) - self.assertEqual(a._data[0:4], cast(addressof(n), POINTER(c_uint8))[3:-1:-1]) - - -if __name__ == "__main__": - unittest.main() diff --git a/test/test_utils/meson.build b/test/test_utils/meson.build index d02d773e0e..2a2c760229 100644 --- a/test/test_utils/meson.build +++ b/test/test_utils/meson.build @@ -1,7 +1,6 @@ # pure python sources test_files = files( '__init__.py', - 'arrinter.py', 'async_sub.py', 'buftools.py', 'png.py',