1 /**********************************************/
2 /* BEGIN interface for fold compound status */
3 /* callback */
4 /**********************************************/
5
6 #ifdef SWIGPYTHON
7 %{
8
9 #include <stdexcept>
10
11 typedef struct {
12 PyObject *cb;
13 PyObject *data;
14 PyObject *delete_data;
15 } pycallback_t;
16
17 static void
18 py_wrap_fc_status_callback(unsigned char status,
19 void *data);
20
21 static void
delete_pydata(pycallback_t * cb)22 delete_pydata(pycallback_t *cb)
23 {
24 if(cb->data != Py_None){
25 if(cb->delete_data != Py_None){
26 /* call user-defined data destructor */
27 PyObject *func, *arglist, *result, *err;
28 func = cb->delete_data;
29 arglist = Py_BuildValue("O", cb->data);
30 result = PyObject_CallObject(func, arglist);
31
32 /* BEGIN recognizing errors in callback execution */
33 if (result == NULL) {
34 if ((err = PyErr_Occurred())) {
35 /* print error message */
36 PyErr_Print();
37 /* we only treat TypeErrors differently here, as they indicate that the callback does not follow requirements! */
38 if (PyErr_GivenExceptionMatches(err, PyExc_TypeError)) {
39 throw std::runtime_error( "Fold compound delete_data() callback must take exactly 1 argument" );
40 } else {
41 throw std::runtime_error( "Some error occurred while executing fold compound delete_data() callback" );
42 }
43 }
44 PyErr_Clear();
45 }
46 /* END recognizing errors in callback execution */
47
48 Py_DECREF(arglist);
49 Py_XDECREF(result);
50 }
51 }
52
53 Py_DECREF(cb->data);
54 Py_DECREF(cb->delete_data);
55 }
56
57
58 static void
delete_pycallback(void * data)59 delete_pycallback(void * data)
60 {
61 pycallback_t *cb = (pycallback_t *)data;
62 /* first delete user data */
63 delete_pydata(cb);
64
65 /* now dispose of the callback */
66 Py_DECREF(cb->cb);
67
68 /* finally free pycallback */
69 free(cb);
70 }
71
72 static void
fc_add_pycallback(vrna_fold_compound_t * vc,PyObject * PyFunc)73 fc_add_pycallback(vrna_fold_compound_t *vc,
74 PyObject *PyFunc)
75 {
76
77 /* try to dispose of previous callback */
78 pycallback_t * cb;
79 if(vc->auxdata){
80 cb = (pycallback_t *)vc->auxdata;
81 /* release previous callback */
82 Py_XDECREF(cb->cb);
83 } else {
84 cb = (pycallback_t *)vrna_alloc(sizeof(pycallback_t));
85 Py_INCREF(Py_None);
86 cb->data = Py_None;
87
88 Py_INCREF(Py_None);
89 cb->delete_data = Py_None;
90 }
91 cb->cb = PyFunc; /* remember callback */
92 Py_XINCREF(PyFunc); /* Increase referenc counter */
93
94 /* finaly bind callback wrapper to fold compound */
95 vc->auxdata = (void *)cb;
96 if(!vc->free_auxdata)
97 vc->free_auxdata = &delete_pycallback;
98
99 vrna_fold_compound_add_callback(vc, &py_wrap_fc_status_callback);
100 }
101
102 static void
fc_add_pydata(vrna_fold_compound_t * vc,PyObject * data,PyObject * PyFunc)103 fc_add_pydata(vrna_fold_compound_t *vc,
104 PyObject *data,
105 PyObject *PyFunc)
106 {
107
108 pycallback_t * cb;
109 /* try to dispose of previous data */
110 if(vc->auxdata){
111 cb = (pycallback_t *)vc->auxdata;
112 delete_pydata(cb);
113 } else {
114 cb = (pycallback_t *)vrna_alloc(sizeof(pycallback_t));
115
116 Py_INCREF(Py_None);
117 cb->cb = Py_None;
118 }
119 cb->data = data; /* remember data */
120 cb->delete_data = PyFunc; /* remember delete data function */
121
122 /* increase reference counter */
123 Py_INCREF(data);
124 Py_INCREF(PyFunc);
125
126 vc->auxdata = (void *)cb;
127 if(!vc->free_auxdata)
128 vc->free_auxdata = &delete_pycallback;
129 }
130
131 static void
py_wrap_fc_status_callback(unsigned char status,void * data)132 py_wrap_fc_status_callback( unsigned char status,
133 void *data)
134 {
135
136 PyObject *func, *arglist, *result, *err;
137 pycallback_t *cb = (pycallback_t *)data;
138
139 func = cb->cb;
140 /* compose argument list */
141 arglist = Py_BuildValue("(B,O)", status, (cb->data) ? cb->data : Py_None);
142 result = PyObject_CallObject(func, arglist);
143
144 /* BEGIN recognizing errors in callback execution */
145 if (result == NULL) {
146 if ((err = PyErr_Occurred())) {
147 /* print error message */
148 PyErr_Print();
149 /* we only treat TypeErrors differently here, as they indicate that the callback does not follow requirements! */
150 if (PyErr_GivenExceptionMatches(err, PyExc_TypeError)) {
151 throw std::runtime_error( "Fold compound callback must take exactly 2 arguments" );
152 } else {
153 throw std::runtime_error( "Some error occurred while executing fold compound callback" );
154 }
155 }
156 PyErr_Clear();
157 }
158 /* END recognizing errors in callback execution */
159
160 Py_DECREF(arglist);
161 Py_XDECREF(result);
162 return /*void*/;
163 }
164
165 %}
166
167 static void
168 fc_add_pycallback(vrna_fold_compound_t *vc,
169 PyObject *PyFunc);
170
171 static void
172 fc_add_pydata(vrna_fold_compound_t *vc,
173 PyObject *data,
174 PyObject *PyFuncOrNone);
175
176 /* now we bind the above functions as methods to the fold_compound object */
177 %extend vrna_fold_compound_t {
178
179 %feature("autodoc") add_auxdata;
180 %feature("kwargs") add_auxdata;
181 %feature("autodoc") add_callback;
182 %feature("kwargs") add_callback;
183
184 PyObject *
185 add_auxdata(PyObject *data,
186 PyObject *PyFuncOrNone = Py_None)
187 {
188 fc_add_pydata($self, data, PyFuncOrNone);
189 Py_RETURN_NONE;
190 }
191
192 PyObject *
add_callback(PyObject * PyFunc)193 add_callback(PyObject *PyFunc)
194 {
195 fc_add_pycallback($self, PyFunc);
196 Py_RETURN_NONE;
197 }
198 }
199
200 #endif
201