Skip to content

Commit

Permalink
Fix builtin Exception type checking.
Browse files Browse the repository at this point in the history
Closes #1496
  • Loading branch information
robertwb committed Oct 26, 2016
1 parent d8c5467 commit c506034
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Cython/Compiler/Nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2129,7 +2129,7 @@ def generate_arg_type_test(self, arg, code):
typeptr_cname,
arg.accept_none,
arg.name,
arg.type.is_builtin_type,
arg.type.is_builtin_type and arg.type.require_exact,
code.error_goto(arg.pos)))
else:
error(arg.pos, "Cannot test type of extern C class without type object name specification")
Expand Down
7 changes: 6 additions & 1 deletion Cython/Compiler/PyrexTypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1138,6 +1138,7 @@ class BuiltinObjectType(PyObjectType):
has_attributes = 1
base_type = None
module_name = '__builtin__'
require_exact = 1

# fields that let it look like an extension type
vtabslot_cname = None
Expand All @@ -1157,6 +1158,8 @@ def __init__(self, name, cname, objstruct_cname=None):
# Special case the type type, as many C API calls (and other
# libraries) actually expect a PyTypeObject* for type arguments.
self.decl_type = objstruct_cname
if name == 'Exception':
self.require_exact = 0

def set_scope(self, scope):
self.scope = scope
Expand Down Expand Up @@ -1210,13 +1213,15 @@ def type_check_function(self, exact=True):
type_check = 'PyString_Check'
elif type_name == 'basestring':
type_check = '__Pyx_PyBaseString_Check'
elif type_name == 'Exception':
type_check = '__Pyx_PyException_Check'
elif type_name == 'bytearray':
type_check = 'PyByteArray_Check'
elif type_name == 'frozenset':
type_check = 'PyFrozenSet_Check'
else:
type_check = 'Py%s_Check' % type_name.capitalize()
if exact and type_name not in ('bool', 'slice'):
if exact and type_name not in ('bool', 'slice', 'Exception'):
type_check += 'Exact'
return type_check

Expand Down
1 change: 1 addition & 0 deletions Cython/Utility/ModuleSetupCode.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@
#endif

#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type)
#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception)

#if PY_MAJOR_VERSION >= 3
#define PyIntObject PyLongObject
Expand Down
23 changes: 23 additions & 0 deletions tests/run/builtin_type_inheritance_T608.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,26 @@ cdef class MyException(Exception):
cdef readonly int value
def __cinit__(self, value):
self.value = value

def test_exception_isinstance(maybe_exn):
"""
>>> test_exception_isinstance(Exception())
True
>>> test_exception_isinstance(MyException(3))
True
>>> test_exception_isinstance(3)
False
"""
return isinstance(maybe_exn, Exception)

def test_exception_type_cast(Exception maybe_exn):
"""
>>> test_exception_type_cast(Exception())
>>> test_exception_type_cast(MyException(3))
>>> test_exception_type_cast(3) # doctest: +ELLIPSIS
Traceback (most recent call last):
...
TypeError: Argument 'maybe_exn' has incorrect type (expected ...Exception, got int)
"""
cdef object o = maybe_exn
cdef Exception e = o

0 comments on commit c506034

Please sign in to comment.