Commit 348fff50 authored by Mark's avatar Mark

Merge pull request #119 from markflorisson88/_nonecheck

Refactor none checking, allow nogil exceptions, nogil memoryview slice None comparison
parents 3bbf6177 76c52f26
This diff is collapsed.
......@@ -127,6 +127,7 @@ class Node(object):
is_name = 0
is_none = 0
is_nonecheck = 0
is_literal = 0
is_terminator = 0
temps = None
......@@ -1832,7 +1833,12 @@ class FuncDefNode(StatNode, BlockNode):
def generate_arg_none_check(self, arg, code):
# Generate None check for one argument.
code.putln('if (unlikely(((PyObject *)%s) == Py_None)) {' % arg.entry.cname)
if arg.type.is_memoryviewslice:
cname = "%s.memview" % arg.entry.cname
else:
cname = arg.entry.cname
code.putln('if (unlikely(((PyObject *)%s) == Py_None)) {' % cname)
code.putln('''PyErr_Format(PyExc_TypeError, "Argument '%s' must not be None"); %s''' % (
arg.name,
code.error_goto(arg.pos)))
......@@ -2978,13 +2984,13 @@ class DefNode(FuncDefNode):
arg.needs_conversion = 0
arg.needs_type_test = 0
arg.is_generic = 1
if arg.type.is_pyobject or arg.type.is_buffer:
if arg.type.is_pyobject or arg.type.is_buffer or arg.type.is_memoryviewslice:
if arg.or_none:
arg.accept_none = True
elif arg.not_none:
arg.accept_none = False
elif (arg.type.is_extension_type or arg.type.is_builtin_type
or arg.type.is_buffer):
or arg.type.is_buffer or arg.type.is_memoryviewslice):
if arg.default and arg.default.constant_result is None:
# special case: def func(MyType obj = None)
arg.accept_none = True
......@@ -4028,7 +4034,9 @@ class DefNodeWrapper(FuncDefNode):
for arg in self.args:
if arg.needs_type_test:
self.generate_arg_type_test(arg, code)
elif not arg.accept_none and arg.type.is_pyobject:
elif not arg.accept_none and (arg.type.is_pyobject or
arg.type.is_buffer or
arg.type.is_memoryviewslice):
self.generate_arg_none_check(arg, code)
def error_value(self):
......
/////////////// RaiseNoneAttrError.proto ///////////////
static CYTHON_INLINE void __Pyx_RaiseNoneAttributeError(const char* attrname);
/////////////// RaiseNoneAttrError ///////////////
static CYTHON_INLINE void __Pyx_RaiseNoneAttributeError(const char* attrname) {
PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%s'", attrname);
}
/////////////// RaiseNoneIndexingError.proto ///////////////
static CYTHON_INLINE void __Pyx_RaiseNoneIndexingError(void);
/////////////// RaiseNoneIndexingError ///////////////
static CYTHON_INLINE void __Pyx_RaiseNoneIndexingError(void) {
PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable");
}
/////////////// RaiseNoneIterError.proto ///////////////
static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void);
......
......@@ -2120,6 +2120,10 @@ def test_dtype_object_scalar_assignment():
#
### Test slices that are set to None
#
# for none memoryview slice attribute testing, slicing, indexing, etc, see
# nonecheck.pyx
@testcase
def test_coerce_to_from_None(double[:] m1, double[:] m2 = None):
"""
......@@ -2130,56 +2134,6 @@ def test_coerce_to_from_None(double[:] m1, double[:] m2 = None):
"""
return m1, m2
@testcase
def test_noneslice_attrib(double[:] m):
"""
>>> test_noneslice_attrib(None)
'NoneType' object has no attribute 'copy'
'NoneType' object has no attribute 'T'
"""
cdef double[:] m2
with cython.nonecheck(True):
try:
m2 = m.copy()
except Exception, e:
print e.args[0]
try:
m2 = m.T
except Exception, e:
print e.args[0]
@testcase
def test_noneslice_index(double[:] m):
"""
>>> test_noneslice_index(None)
Cannot index None memoryview slice
Cannot index None memoryview slice
Cannot index None memoryview slice
Cannot index None memoryview slice
"""
with cython.nonecheck(True):
try:
a = m[10]
except Exception, e:
print e.args[0]
try:
b = m[:]
except Exception, e:
print e.args[0]
try:
m[10] = 2
except Exception, e:
print e.args[0]
try:
m[:] = 2
except Exception, e:
print e.args[0]
@testcase
def test_noneslice_compare(double[:] m):
"""
......@@ -2226,6 +2180,29 @@ def test_noneslice_del():
del m
print m
@testcase
def test_noneslice_nogil_check_none(double[:] m):
"""
>>> test_noneslice_nogil_check_none(None)
(True, False)
"""
cdef bint is_none = False
cdef bint not_none = True
with nogil:
is_none = m is None and None is m and m == None and None == m
not_none = m is not None and None is not m and m != None and None != m
return is_none, not_none
@testcase
def test_noneslice_not_none(double[:] m not None):
"""
>>> test_noneslice_not_none(None)
Traceback (most recent call last):
TypeError: Argument 'm' must not be None
"""
def get_int():
return 10
......
......@@ -37,6 +37,26 @@ def setattr_(MyClass var):
"""
var.a = 10
@cython.nonecheck(True)
def getattr_nogil(MyClass var):
"""
>>> getattr_nogil(None)
Traceback (most recent call last):
AttributeError: 'NoneType' object has no attribute 'a'
"""
with nogil:
var.a
@cython.nonecheck(True)
def setattr_nogil(MyClass var):
"""
>>> setattr_nogil(None)
Traceback (most recent call last):
AttributeError: 'NoneType' object has no attribute 'a'
"""
with nogil:
var.a = 1
def some():
return MyClass(4, 5)
......@@ -88,3 +108,85 @@ def check_buffer_set(object[int] buf):
TypeError: 'NoneType' object is not subscriptable
"""
buf[0] = 1
@cython.nonecheck(True)
def test_memslice_get(double[:] buf):
"""
>>> test_memslice_get(None)
Traceback (most recent call last):
TypeError: Cannot index None memoryview slice
"""
return buf[0]
@cython.nonecheck(True)
def test_memslice_set(double[:] buf):
"""
>>> test_memslice_set(None)
Traceback (most recent call last):
TypeError: Cannot index None memoryview slice
"""
buf[0] = 1.0
@cython.nonecheck(True)
def test_memslice_copy(double[:] buf):
"""
>>> test_memslice_copy(None)
Traceback (most recent call last):
AttributeError: Cannot access 'copy' attribute of None memoryview slice
"""
cdef double[:] copy = buf.copy()
@cython.nonecheck(True)
def test_memslice_transpose(double[:] buf):
"""
>>> test_memslice_transpose(None)
Traceback (most recent call last):
AttributeError: Cannot transpose None memoryview slice
"""
cdef double[:] T = buf.T
@cython.nonecheck(True)
def test_memslice_shape(double[:] buf):
"""
>>> test_memslice_shape(None)
Traceback (most recent call last):
AttributeError: Cannot access 'shape' attribute of None memoryview slice
"""
cdef Py_ssize_t extent = buf.shape[0]
@cython.nonecheck(True)
def test_memslice_slice(double[:] buf):
"""
>>> test_memslice_slice(None)
Traceback (most recent call last):
TypeError: Cannot slice None memoryview slice
"""
cdef double[:] sliced = buf[1:]
@cython.nonecheck(True)
def test_memslice_slice2(double[:] buf):
"""
Should this raise an error? It may not slice at all.
>>> test_memslice_slice(None)
Traceback (most recent call last):
TypeError: Cannot slice None memoryview slice
"""
cdef double[:] sliced = buf[:]
@cython.nonecheck(True)
def test_memslice_slice_assign(double[:] buf):
"""
>>> test_memslice_slice_assign(None)
Traceback (most recent call last):
TypeError: Cannot assign to None memoryview slice
"""
buf[...] = 2
@cython.nonecheck(True)
def test_memslice_slice_assign2(double[:] buf):
"""
>>> test_memslice_slice_assign2(None)
Traceback (most recent call last):
TypeError: Cannot slice None memoryview slice
"""
buf[:] = buf[::-1]
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