Commit 22f4444a authored by da-woods's avatar da-woods Committed by GitHub

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.
parent c769c329
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from cpython.object cimport PyObject 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 cimport cython
__test__ = {} __test__ = {}
...@@ -1013,17 +1013,14 @@ def check_object_nulled_1d(MockBuffer[object, ndim=1] buf, int idx, obj): ...@@ -1013,17 +1013,14 @@ def check_object_nulled_1d(MockBuffer[object, ndim=1] buf, int idx, obj):
>>> rc1 = get_refcount(a) >>> rc1 = get_refcount(a)
>>> A = ObjectMockBuffer(None, [a, a]) >>> A = ObjectMockBuffer(None, [a, a])
>>> check_object_nulled_1d(A, 0, a) >>> check_object_nulled_1d(A, 0, a)
>>> decref(a) # new reference "added" to A
>>> check_object_nulled_1d(A, 1, a) >>> check_object_nulled_1d(A, 1, a)
>>> decref(a)
>>> A = ObjectMockBuffer(None, [a, a, a, a], strides=(2,)) >>> A = ObjectMockBuffer(None, [a, a, a, a], strides=(2,))
>>> check_object_nulled_1d(A, 0, a) # only 0 due to stride >>> check_object_nulled_1d(A, 0, a) # only 0 due to stride
>>> decref(a)
>>> get_refcount(a) == rc1 >>> get_refcount(a) == rc1
True True
""" """
cdef void **data = <void **>buf.buffer cdef PyObject **data = <PyObject **>buf.buffer
data[idx] = NULL Py_CLEAR(data[idx])
res = buf[idx] # takes None res = buf[idx] # takes None
buf[idx] = obj buf[idx] = obj
return res return res
...@@ -1037,14 +1034,12 @@ def check_object_nulled_2d(MockBuffer[object, ndim=2] buf, int idx1, int idx2, o ...@@ -1037,14 +1034,12 @@ def check_object_nulled_2d(MockBuffer[object, ndim=2] buf, int idx1, int idx2, o
>>> rc1 = get_refcount(a) >>> rc1 = get_refcount(a)
>>> A = ObjectMockBuffer(None, [a, a, a, a], shape=(2, 2)) >>> A = ObjectMockBuffer(None, [a, a, a, a], shape=(2, 2))
>>> check_object_nulled_2d(A, 0, 0, a) >>> check_object_nulled_2d(A, 0, 0, a)
>>> decref(a) # new reference "added" to A
>>> check_object_nulled_2d(A, 1, 1, a) >>> check_object_nulled_2d(A, 1, 1, a)
>>> decref(a)
>>> get_refcount(a) == rc1 >>> get_refcount(a) == rc1
True True
""" """
cdef void **data = <void **>buf.buffer cdef PyObject **data = <PyObject **>buf.buffer
data[idx1 + 2*idx2] = NULL Py_CLEAR(data[idx1 + 2*idx2])
res = buf[idx1, idx2] # takes None res = buf[idx1, idx2] # takes None
buf[idx1, idx2] = obj buf[idx1, idx2] = obj
return res return res
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from cpython.object cimport PyObject 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 cimport cython
from cython cimport view from cython cimport view
...@@ -1130,6 +1130,49 @@ def assign_temporary_to_object(object[:] buf): ...@@ -1130,6 +1130,49 @@ def assign_temporary_to_object(object[:] buf):
""" """
buf[1] = {3-2: 2+(2*4)-2} 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__ # Test __cythonbufferdefaults__
# #
......
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