summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorda-woods <dw-git@d-woods.co.uk>2022-07-06 20:47:04 +0100
committerGitHub <noreply@github.com>2022-07-06 21:47:04 +0200
commit22f4444a1722fe0fd3f9157f1db35ab1c02522a9 (patch)
treecbe8fd01f75ffaa9bfb9a5356d31b2499d6c7554
parentc769c3295dec09fbbb607f249224ce385591dbcc (diff)
downloadcython-22f4444a1722fe0fd3f9157f1db35ab1c02522a9.tar.gz
Add tests for NULL objects in memoryviews (GH-4871)
Follow up on https://github.com/cython/cython/pull/4859 by adding tests for memoryviews too. Additional refactoring to avoid invalid decref calls on test failures. Instead, the item is safely cleared directly before the access.
-rw-r--r--tests/buffers/bufaccess.pyx15
-rw-r--r--tests/memoryview/memslice.pyx45
2 files changed, 49 insertions, 11 deletions
diff --git a/tests/buffers/bufaccess.pyx b/tests/buffers/bufaccess.pyx
index 2a5e84185..053ea2890 100644
--- a/tests/buffers/bufaccess.pyx
+++ b/tests/buffers/bufaccess.pyx
@@ -10,7 +10,7 @@
from __future__ import unicode_literals
from cpython.object cimport PyObject
-from cpython.ref cimport Py_INCREF, Py_DECREF
+from cpython.ref cimport Py_INCREF, Py_DECREF, Py_CLEAR
cimport cython
__test__ = {}
@@ -1013,17 +1013,14 @@ def check_object_nulled_1d(MockBuffer[object, ndim=1] buf, int idx, obj):
>>> rc1 = get_refcount(a)
>>> A = ObjectMockBuffer(None, [a, a])
>>> check_object_nulled_1d(A, 0, a)
- >>> decref(a) # new reference "added" to A
>>> check_object_nulled_1d(A, 1, a)
- >>> decref(a)
>>> A = ObjectMockBuffer(None, [a, a, a, a], strides=(2,))
>>> check_object_nulled_1d(A, 0, a) # only 0 due to stride
- >>> decref(a)
>>> get_refcount(a) == rc1
True
"""
- cdef void **data = <void **>buf.buffer
- data[idx] = NULL
+ cdef PyObject **data = <PyObject **>buf.buffer
+ Py_CLEAR(data[idx])
res = buf[idx] # takes None
buf[idx] = obj
return res
@@ -1037,14 +1034,12 @@ def check_object_nulled_2d(MockBuffer[object, ndim=2] buf, int idx1, int idx2, o
>>> rc1 = get_refcount(a)
>>> A = ObjectMockBuffer(None, [a, a, a, a], shape=(2, 2))
>>> check_object_nulled_2d(A, 0, 0, a)
- >>> decref(a) # new reference "added" to A
>>> check_object_nulled_2d(A, 1, 1, a)
- >>> decref(a)
>>> get_refcount(a) == rc1
True
"""
- cdef void **data = <void **>buf.buffer
- data[idx1 + 2*idx2] = NULL
+ cdef PyObject **data = <PyObject **>buf.buffer
+ Py_CLEAR(data[idx1 + 2*idx2])
res = buf[idx1, idx2] # takes None
buf[idx1, idx2] = obj
return res
diff --git a/tests/memoryview/memslice.pyx b/tests/memoryview/memslice.pyx
index 06bdf8673..24af61e17 100644
--- a/tests/memoryview/memslice.pyx
+++ b/tests/memoryview/memslice.pyx
@@ -5,7 +5,7 @@
from __future__ import unicode_literals
from cpython.object cimport PyObject
-from cpython.ref cimport Py_INCREF, Py_DECREF
+from cpython.ref cimport Py_INCREF, Py_DECREF, Py_CLEAR
cimport cython
from cython cimport view
@@ -1130,6 +1130,49 @@ def assign_temporary_to_object(object[:] buf):
"""
buf[1] = {3-2: 2+(2*4)-2}
+@testcase
+def check_object_nulled_1d(object[:] buf, int idx, obj):
+ """
+ See comments on printbuf_object above.
+
+ >>> a = object()
+ >>> rc1 = get_refcount(a)
+ >>> A = ObjectMockBuffer(None, [a, a])
+ >>> check_object_nulled_1d(A, 0, a)
+ >>> check_object_nulled_1d(A, 1, a)
+ >>> A = ObjectMockBuffer(None, [a, a, a, a], strides=(2,))
+ >>> check_object_nulled_1d(A, 0, a) # only 0 due to stride
+ >>> get_refcount(a) == rc1
+ True
+ """
+ cdef ObjectMockBuffer omb = buf.base
+ cdef PyObject **data = <PyObject**>(omb.buffer)
+ Py_CLEAR(data[idx])
+ res = buf[idx] # takes None
+ buf[idx] = obj
+ return res
+
+@testcase
+def check_object_nulled_2d(object[:, ::1] buf, int idx1, int idx2, obj):
+ """
+ See comments on printbuf_object above.
+
+ >>> a = object()
+ >>> rc1 = get_refcount(a)
+ >>> A = ObjectMockBuffer(None, [a, a, a, a], shape=(2, 2))
+ >>> check_object_nulled_2d(A, 0, 0, a)
+ >>> check_object_nulled_2d(A, 1, 1, a)
+ >>> get_refcount(a) == rc1
+ True
+ """
+ cdef ObjectMockBuffer omb = buf.base
+ cdef PyObject **data = <PyObject**>(omb.buffer)
+ Py_CLEAR(data[idx1 + 2*idx2])
+ res = buf[idx1, idx2] # takes None
+ buf[idx1, idx2] = obj
+ return res
+
+
#
# Test __cythonbufferdefaults__
#