Skip to content

Commit 2a24ab6

Browse files
authored
Merge pull request #16 from debsankha/fix_exception_handling
Fix exception handling
2 parents 6717a4b + 8b412a5 commit 2a24ab6

File tree

9 files changed

+216
-10472
lines changed

9 files changed

+216
-10472
lines changed

.travis.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
sudo: false
2+
3+
language: python
4+
5+
python:
6+
- '2.7'
7+
- '3.6'
8+
9+
branches:
10+
only:
11+
- master
12+
- fix_exception_handling
13+
14+
before_install:
15+
- pwd
16+
- pip install cython pytest pytest-mock
17+
- pip install -r requirements.txt
18+
- pip install ./
19+
20+
script:
21+
- pytest -vvv --import-mode=append

devs/adevs_python.hpp

Lines changed: 66 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
#include "adevs.h"
2727

2828

29-
3029
namespace pydevs {
3130

3231

@@ -86,8 +85,14 @@ class Atomic: public AtomicBase {
8685
virtual void delta_int() {
8786

8887
bool isDefined = this->pythonObject_ && this->deltaIntFunc_;
89-
if (isDefined)
88+
if (isDefined){
9089
this->deltaIntFunc_ (this->pythonObject_);
90+
if (PyErr_Occurred())
91+
{
92+
std::string error_message = get_PyExceptionAsString();
93+
throw std::runtime_error(error_message);
94+
}
95+
}
9196
else
9297
throw std::bad_function_call();
9398

@@ -98,10 +103,14 @@ class Atomic: public AtomicBase {
98103
virtual void delta_ext (Time e, const IOBag& xb) {
99104

100105
bool isDefined = this->pythonObject_ && this->deltaExtFunc_;
101-
if (isDefined)
102-
this->deltaExtFunc_ (
103-
this->pythonObject_, e, xb
104-
);
106+
if (isDefined){
107+
this->deltaExtFunc_ (this->pythonObject_, e, xb);
108+
if (PyErr_Occurred())
109+
{
110+
std::string error_message = get_PyExceptionAsString();
111+
throw std::runtime_error(error_message);
112+
}
113+
}
105114
else
106115
throw std::bad_function_call();
107116

@@ -112,13 +121,16 @@ class Atomic: public AtomicBase {
112121
virtual void delta_conf (const IOBag& xb) {
113122

114123
bool isDefined = this->pythonObject_ && this->deltaConfFunc_;
115-
if (isDefined)
116-
this->deltaConfFunc_ (
117-
this->pythonObject_, xb
118-
);
124+
if (isDefined){
125+
this->deltaConfFunc_ (this->pythonObject_, xb);
126+
if (PyErr_Occurred())
127+
{
128+
std::string error_message = get_PyExceptionAsString();
129+
throw std::runtime_error(error_message);
130+
}
131+
}
119132
else
120133
throw std::bad_function_call();
121-
122134
}
123135

124136

@@ -127,11 +139,18 @@ class Atomic: public AtomicBase {
127139

128140
bool isDefined = this->pythonObject_ && this->outputFunc_;
129141
if (isDefined)
130-
this->outputFunc_ (
131-
this->pythonObject_, yb
132-
);
142+
{
143+
this->outputFunc_ (this->pythonObject_, yb);
144+
if (PyErr_Occurred())
145+
{
146+
std::string error_message = get_PyExceptionAsString();
147+
throw std::runtime_error(error_message);
148+
}
149+
}
133150
else
151+
{
134152
throw std::bad_function_call();
153+
}
135154

136155
}
137156

@@ -171,6 +190,39 @@ class Atomic: public AtomicBase {
171190
}
172191

173192

193+
std::string get_PyExceptionAsString()
194+
{
195+
// now we will try to get the python traceback.
196+
// see https://stackoverflow.com/questions/1796510/accessing-a-python-traceback-from-the-c-api
197+
// for longer discussion on how to do it.
198+
PyObject *ptype, *pvalue, *ptraceback;
199+
PyObject *pystr, *pystr_unic;
200+
201+
std::string error_desc;
202+
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
203+
if (pvalue == NULL){
204+
error_desc = {"No information on the occured exception available"};
205+
}
206+
else {
207+
#if PY_MAJOR_VERSION < 3
208+
pystr = PyObject_Unicode(pvalue);
209+
pystr_unic = PyUnicode_AsEncodedString(pystr, "utf-8", "ignore"); // same in py2 and py3
210+
error_desc = {PyBytes_AsString(pystr_unic)};
211+
#else
212+
pystr = PyObject_Str(pvalue);
213+
pystr_unic = PyUnicode_AsEncodedString(pystr, "utf-8", "ignore");
214+
error_desc = {PyBytes_AsString(pystr_unic)};
215+
#endif
216+
217+
Py_XDECREF(pystr);
218+
Py_XDECREF(pystr_unic);
219+
}
220+
Py_XDECREF(ptype);
221+
Py_XDECREF(pvalue);
222+
Py_XDECREF(ptraceback);
223+
224+
return "Python traceback follows:\n" + error_desc;
225+
}
174226

175227
private:
176228

@@ -180,7 +232,6 @@ class Atomic: public AtomicBase {
180232
const DeltaConfFunc deltaConfFunc_;
181233
const OutputFunc outputFunc_;
182234
const TaFunc taFunc_;
183-
184235
};
185236

186237

devs/cadevs.pxd

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,5 +103,6 @@ cdef extern from "adevs_python.hpp" namespace "pydevs":
103103
Simulator(Atomic*) except +
104104
Simulator(Digraph*) except +
105105
Time nextEventTime() except *
106-
void executeNextEvent() except *
107-
void executeUntil(Time) except *
106+
void executeNextEvent() except +* # the +* signifies this can raise
107+
# both python and c++ exceptions
108+
void executeUntil(Time) except +*

0 commit comments

Comments
 (0)