26
26
#include " adevs.h"
27
27
28
28
29
-
30
29
namespace pydevs {
31
30
32
31
@@ -86,8 +85,14 @@ class Atomic: public AtomicBase {
86
85
virtual void delta_int () {
87
86
88
87
bool isDefined = this ->pythonObject_ && this ->deltaIntFunc_ ;
89
- if (isDefined)
88
+ if (isDefined){
90
89
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
+ }
91
96
else
92
97
throw std::bad_function_call ();
93
98
@@ -98,10 +103,14 @@ class Atomic: public AtomicBase {
98
103
virtual void delta_ext (Time e, const IOBag& xb) {
99
104
100
105
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
+ }
105
114
else
106
115
throw std::bad_function_call ();
107
116
@@ -112,13 +121,16 @@ class Atomic: public AtomicBase {
112
121
virtual void delta_conf (const IOBag& xb) {
113
122
114
123
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
+ }
119
132
else
120
133
throw std::bad_function_call ();
121
-
122
134
}
123
135
124
136
@@ -127,11 +139,18 @@ class Atomic: public AtomicBase {
127
139
128
140
bool isDefined = this ->pythonObject_ && this ->outputFunc_ ;
129
141
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
+ }
133
150
else
151
+ {
134
152
throw std::bad_function_call ();
153
+ }
135
154
136
155
}
137
156
@@ -171,6 +190,39 @@ class Atomic: public AtomicBase {
171
190
}
172
191
173
192
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
+ }
174
226
175
227
private:
176
228
@@ -180,7 +232,6 @@ class Atomic: public AtomicBase {
180
232
const DeltaConfFunc deltaConfFunc_;
181
233
const OutputFunc outputFunc_;
182
234
const TaFunc taFunc_;
183
-
184
235
};
185
236
186
237
0 commit comments