Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
nexedi
cython
Commits
77a2e6f3
Commit
77a2e6f3
authored
6 years ago
by
Robert Bradshaw
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Allow catching both C++ and Python exceptions.
parent
7b4079c5
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
56 additions
and
8 deletions
+56
-8
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+19
-6
Cython/Compiler/Nodes.py
Cython/Compiler/Nodes.py
+5
-2
Cython/Compiler/Parsing.py
Cython/Compiler/Parsing.py
+3
-0
docs/src/userguide/wrapping_CPlusPlus.rst
docs/src/userguide/wrapping_CPlusPlus.rst
+7
-0
tests/run/cpp_exceptions.pyx
tests/run/cpp_exceptions.pyx
+14
-0
tests/run/cpp_exceptions_helper.h
tests/run/cpp_exceptions_helper.h
+8
-0
No files found.
Cython/Compiler/ExprNodes.py
View file @
77a2e6f3
...
@@ -189,20 +189,31 @@ def infer_sequence_item_type(env, seq_node, index_node=None, seq_type=None):
...
@@ -189,20 +189,31 @@ def infer_sequence_item_type(env, seq_node, index_node=None, seq_type=None):
def
get_exception_handler
(
exception_value
):
def
get_exception_handler
(
exception_value
):
if
exception_value
is
None
:
if
exception_value
is
None
:
return
"__Pyx_CppExn2PyErr();"
return
"__Pyx_CppExn2PyErr();"
,
False
elif
(
exception_value
.
type
==
PyrexTypes
.
c_char_type
and
exception_value
.
value
==
'*'
):
return
"__Pyx_CppExn2PyErr();"
,
True
elif
exception_value
.
type
.
is_pyobject
:
elif
exception_value
.
type
.
is_pyobject
:
return
'try { throw; } catch(const std::exception& exn) { PyErr_SetString(%s, exn.what()); } catch(...) { PyErr_SetNone(%s); }'
%
(
return
'try { throw; } catch(const std::exception& exn) { PyErr_SetString(%s, exn.what()); } catch(...) { PyErr_SetNone(%s); }'
%
(
exception_value
.
entry
.
cname
,
exception_value
.
entry
.
cname
,
exception_value
.
entry
.
cname
)
exception_value
.
entry
.
cname
)
,
False
else
:
else
:
return
'%s(); if (!PyErr_Occurred()) PyErr_SetString(PyExc_RuntimeError , "Error converting c++ exception.");'
%
exception_value
.
entry
.
cname
return
'%s(); if (!PyErr_Occurred()) PyErr_SetString(PyExc_RuntimeError , "Error converting c++ exception.");'
%
exception_value
.
entry
.
cname
,
False
def
maybe_check_py_error
(
code
,
check_py_exception
,
pos
,
nogil
):
if
check_py_exception
:
if
nogil
:
code
.
putln
(
code
.
error_goto_if
(
"__Pyx_ErrOccurredWithGIL()"
,
pos
))
else
:
code
.
putln
(
code
.
error_goto_if
(
"PyErr_Occurred()"
,
pos
))
def
translate_cpp_exception
(
code
,
pos
,
inside
,
py_result
,
exception_value
,
nogil
):
def
translate_cpp_exception
(
code
,
pos
,
inside
,
py_result
,
exception_value
,
nogil
):
raise_py_exception
=
get_exception_handler
(
exception_value
)
raise_py_exception
,
check_py_exception
=
get_exception_handler
(
exception_value
)
code
.
putln
(
"try {"
)
code
.
putln
(
"try {"
)
code
.
putln
(
"%s"
%
inside
)
code
.
putln
(
"%s"
%
inside
)
if
py_result
:
if
py_result
:
code
.
putln
(
code
.
error_goto_if_null
(
py_result
,
pos
))
code
.
putln
(
code
.
error_goto_if_null
(
py_result
,
pos
))
maybe_check_py_error
(
code
,
check_py_exception
,
pos
,
nogil
)
code
.
putln
(
"} catch(...) {"
)
code
.
putln
(
"} catch(...) {"
)
if
nogil
:
if
nogil
:
code
.
put_ensure_gil
(
declare_gilstate
=
True
)
code
.
put_ensure_gil
(
declare_gilstate
=
True
)
...
@@ -216,12 +227,14 @@ def translate_cpp_exception(code, pos, inside, py_result, exception_value, nogil
...
@@ -216,12 +227,14 @@ def translate_cpp_exception(code, pos, inside, py_result, exception_value, nogil
# both have an exception declaration.
# both have an exception declaration.
def
translate_double_cpp_exception
(
code
,
pos
,
lhs_type
,
lhs_code
,
rhs_code
,
def
translate_double_cpp_exception
(
code
,
pos
,
lhs_type
,
lhs_code
,
rhs_code
,
lhs_exc_val
,
assign_exc_val
,
nogil
):
lhs_exc_val
,
assign_exc_val
,
nogil
):
handle_lhs_exc
=
get_exception_handler
(
lhs_exc_val
)
handle_lhs_exc
,
lhc_check_py_exc
=
get_exception_handler
(
lhs_exc_val
)
handle_assignment_exc
=
get_exception_handler
(
assign_exc_val
)
handle_assignment_exc
,
assignment_check_py_exc
=
get_exception_handler
(
assign_exc_val
)
code
.
putln
(
"try {"
)
code
.
putln
(
"try {"
)
code
.
putln
(
lhs_type
.
declaration_code
(
"__pyx_local_lvalue = %s;"
%
lhs_code
))
code
.
putln
(
lhs_type
.
declaration_code
(
"__pyx_local_lvalue = %s;"
%
lhs_code
))
maybe_check_py_error
(
code
,
lhc_check_py_exc
,
pos
,
nogil
)
code
.
putln
(
"try {"
)
code
.
putln
(
"try {"
)
code
.
putln
(
"__pyx_local_lvalue = %s;"
%
rhs_code
)
code
.
putln
(
"__pyx_local_lvalue = %s;"
%
rhs_code
)
maybe_check_py_error
(
code
,
assignment_check_py_exc
,
pos
,
nogil
)
# Catch any exception from the overloaded assignment.
# Catch any exception from the overloaded assignment.
code
.
putln
(
"} catch(...) {"
)
code
.
putln
(
"} catch(...) {"
)
if
nogil
:
if
nogil
:
...
...
This diff is collapsed.
Click to expand it.
Cython/Compiler/Nodes.py
View file @
77a2e6f3
...
@@ -737,13 +737,16 @@ class CFuncDeclaratorNode(CDeclaratorNode):
...
@@ -737,13 +737,16 @@ class CFuncDeclaratorNode(CDeclaratorNode):
self
.
exception_value
=
self
.
exception_value
.
analyse_const_expression
(
env
)
self
.
exception_value
=
self
.
exception_value
.
analyse_const_expression
(
env
)
if
self
.
exception_check
==
'+'
:
if
self
.
exception_check
==
'+'
:
exc_val_type
=
self
.
exception_value
.
type
exc_val_type
=
self
.
exception_value
.
type
print
exc_val_type
if
(
not
exc_val_type
.
is_error
if
(
not
exc_val_type
.
is_error
and
not
exc_val_type
.
is_pyobject
and
not
exc_val_type
.
is_pyobject
and
not
(
exc_val_type
.
is_cfunction
and
not
(
exc_val_type
.
is_cfunction
and
not
exc_val_type
.
return_type
.
is_pyobject
and
not
exc_val_type
.
return_type
.
is_pyobject
and
not
exc_val_type
.
args
)):
and
not
exc_val_type
.
args
)
and
not
(
exc_val_type
==
PyrexTypes
.
c_char_type
and
self
.
exception_value
.
value
==
'*'
)):
error
(
self
.
exception_value
.
pos
,
error
(
self
.
exception_value
.
pos
,
"Exception value must be a Python exception or cdef function with no arguments."
)
"Exception value must be a Python exception or cdef function with no arguments
or *
."
)
exc_val
=
self
.
exception_value
exc_val
=
self
.
exception_value
else
:
else
:
self
.
exception_value
=
self
.
exception_value
.
coerce_to
(
self
.
exception_value
=
self
.
exception_value
.
coerce_to
(
...
...
This diff is collapsed.
Click to expand it.
Cython/Compiler/Parsing.py
View file @
77a2e6f3
...
@@ -2937,6 +2937,9 @@ def p_exception_value_clause(s):
...
@@ -2937,6 +2937,9 @@ def p_exception_value_clause(s):
name
=
s
.
systring
name
=
s
.
systring
s
.
next
()
s
.
next
()
exc_val
=
p_name
(
s
,
name
)
exc_val
=
p_name
(
s
,
name
)
elif
s
.
sy
==
'*'
:
exc_val
=
ExprNodes
.
CharNode
(
s
.
position
(),
value
=
u'*'
)
s
.
next
()
else
:
else
:
if
s
.
sy
==
'?'
:
if
s
.
sy
==
'?'
:
exc_check
=
1
exc_check
=
1
...
...
This diff is collapsed.
Click to expand it.
docs/src/userguide/wrapping_CPlusPlus.rst
View file @
77a2e6f3
...
@@ -440,6 +440,13 @@ called, which allows one to do custom C++ to Python error "translations." If
...
@@ -440,6 +440,13 @@ called, which allows one to do custom C++ to Python error "translations." If
raise_py_error does not actually raise an exception a RuntimeError will be
raise_py_error does not actually raise an exception a RuntimeError will be
raised.
raised.
There is also the special form::
cdef int raise_py_or_cpp() except +*
for those functions that may raise either a Python or a C++ exception.
Static member method
Static member method
--------------------
--------------------
...
...
This diff is collapsed.
Click to expand it.
tests/run/cpp_exceptions.pyx
View file @
77a2e6f3
...
@@ -22,6 +22,7 @@ cdef extern from "cpp_exceptions_helper.h":
...
@@ -22,6 +22,7 @@ cdef extern from "cpp_exceptions_helper.h":
cdef
void
raise_underflow
()
except
+
cdef
void
raise_underflow
()
except
+
cdef
raise_or_throw
(
bint
py
)
except
+
cdef
raise_or_throw
(
bint
py
)
except
+
cdef
int
raise_or_throw_int
(
bint
py
)
except
+*
cdef
cppclass
Foo
:
cdef
cppclass
Foo
:
int
bar_raw
"bar"
(
bint
fire
)
except
+
int
bar_raw
"bar"
(
bint
fire
)
except
+
...
@@ -113,6 +114,19 @@ def test_func_that_can_raise_or_throw(bint py):
...
@@ -113,6 +114,19 @@ def test_func_that_can_raise_or_throw(bint py):
"""
"""
raise_or_throw
(
py
)
raise_or_throw
(
py
)
def
test_func_that_can_raise_or_throw_c_return
(
bint
py
):
"""
>>> test_func_that_can_raise_or_throw_c_return(0)
Traceback (most recent call last):
...
RuntimeError: oopsie
>>> test_func_that_can_raise_or_throw_c_return(1)
Traceback (most recent call last):
...
ValueError: oopsie
"""
raise_or_throw_int
(
py
)
def
test_int_raw
(
bint
fire
):
def
test_int_raw
(
bint
fire
):
"""
"""
>>> test_int_raw(False)
>>> test_int_raw(False)
...
...
This diff is collapsed.
Click to expand it.
tests/run/cpp_exceptions_helper.h
View file @
77a2e6f3
...
@@ -70,3 +70,11 @@ PyObject *raise_or_throw(int py) {
...
@@ -70,3 +70,11 @@ PyObject *raise_or_throw(int py) {
PyErr_SetString
(
PyExc_ValueError
,
"oopsie"
);
PyErr_SetString
(
PyExc_ValueError
,
"oopsie"
);
return
NULL
;
return
NULL
;
}
}
int
raise_or_throw_int
(
int
py
)
{
if
(
!
py
)
{
throw
std
::
runtime_error
(
"oopsie"
);
}
PyErr_SetString
(
PyExc_ValueError
,
"oopsie"
);
return
-
1
;
}
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment