Chris@66
|
1 /* -*- c-basic-offset: 8 indent-tabs-mode: t -*- */
|
fazekasgy@37
|
2 /*
|
fazekasgy@37
|
3
|
fazekasgy@37
|
4 * Vampy : This plugin is a wrapper around the Vamp plugin API.
|
fazekasgy@37
|
5 * It allows for writing Vamp plugins in Python.
|
fazekasgy@37
|
6
|
fazekasgy@37
|
7 * Centre for Digital Music, Queen Mary University of London.
|
fazekasgy@37
|
8 * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources
|
fazekasgy@37
|
9 * for licence information.)
|
fazekasgy@37
|
10
|
fazekasgy@37
|
11 */
|
fazekasgy@37
|
12
|
fazekasgy@37
|
13 #include <Python.h>
|
fazekasgy@37
|
14
|
Chris@71
|
15 #include "PyTypeConversions.h"
|
fazekasgy@37
|
16
|
fazekasgy@37
|
17 #include <math.h>
|
fazekasgy@37
|
18 #include <float.h>
|
fazekasgy@37
|
19 #include <limits.h>
|
fazekasgy@37
|
20 #ifndef SIZE_T_MAX
|
fazekasgy@37
|
21 #define SIZE_T_MAX ((size_t) -1)
|
fazekasgy@37
|
22 #endif
|
fazekasgy@37
|
23
|
fazekasgy@37
|
24 using std::string;
|
fazekasgy@37
|
25 using std::vector;
|
fazekasgy@37
|
26 using std::cerr;
|
fazekasgy@37
|
27 using std::endl;
|
fazekasgy@37
|
28
|
fazekasgy@37
|
29 /* Note: NO FUNCTION IN THIS CLASS SHOULD ALTER REFERENCE COUNTS
|
Chris@66
|
30 (EXCEPT FOR TEMPORARY PYTHON OBJECTS)! */
|
fazekasgy@37
|
31
|
Chris@71
|
32 PyTypeConversions::PyTypeConversions() :
|
fazekasgy@37
|
33 m_strict(false),
|
fazekasgy@37
|
34 m_error(false),
|
fazekasgy@51
|
35 m_numpyInstalled(false),
|
fazekasgy@37
|
36 error(m_error) // const public reference for easy access
|
fazekasgy@37
|
37 {
|
fazekasgy@37
|
38 }
|
fazekasgy@37
|
39
|
Chris@71
|
40 PyTypeConversions::~PyTypeConversions()
|
fazekasgy@37
|
41 {
|
fazekasgy@37
|
42 }
|
fazekasgy@37
|
43
|
fazekasgy@37
|
44 /// floating point numbers (TODO: check numpy.float128)
|
fazekasgy@37
|
45 float
|
Chris@71
|
46 PyTypeConversions::PyValue_To_Float(PyObject* pyValue) const
|
fazekasgy@37
|
47 {
|
fazekasgy@37
|
48 // convert float
|
fazekasgy@37
|
49 if (pyValue && PyFloat_Check(pyValue))
|
fazekasgy@37
|
50 //TODO: check for limits here (same on most systems)
|
fazekasgy@37
|
51 return (float) PyFloat_AS_DOUBLE(pyValue);
|
fazekasgy@37
|
52
|
fazekasgy@37
|
53 if (pyValue == NULL)
|
fazekasgy@37
|
54 {
|
fazekasgy@51
|
55 setValueError("Error while converting object " + PyValue_Get_TypeName(pyValue) + " to float. ",m_strict);
|
fazekasgy@37
|
56 return 0.0;
|
fazekasgy@37
|
57 }
|
fazekasgy@37
|
58
|
fazekasgy@37
|
59 // in strict mode we will not try harder
|
fazekasgy@37
|
60 if (m_strict) {
|
fazekasgy@51
|
61 setValueError("Strict conversion error: object" + PyValue_Get_TypeName(pyValue) +" is not float.",m_strict);
|
fazekasgy@37
|
62 return 0.0;
|
fazekasgy@37
|
63 }
|
fazekasgy@37
|
64
|
fazekasgy@37
|
65 // convert other objects supporting the number protocol
|
fazekasgy@37
|
66 if (PyNumber_Check(pyValue))
|
fazekasgy@37
|
67 {
|
fazekasgy@37
|
68 PyObject* pyFloat = PyNumber_Float(pyValue); // new ref
|
fazekasgy@37
|
69 if (!pyFloat)
|
fazekasgy@37
|
70 {
|
fazekasgy@37
|
71 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
72 setValueError("Error while converting " + PyValue_Get_TypeName(pyValue) + " object to float.",m_strict);
|
fazekasgy@37
|
73 return 0.0;
|
fazekasgy@37
|
74 }
|
fazekasgy@37
|
75 float rValue = (float) PyFloat_AS_DOUBLE(pyFloat);
|
fazekasgy@37
|
76 Py_DECREF(pyFloat);
|
fazekasgy@37
|
77 return rValue;
|
fazekasgy@37
|
78 }
|
fazekasgy@37
|
79 /*
|
fazekasgy@37
|
80 // convert other objects supporting the number protocol
|
fazekasgy@37
|
81 if (PyNumber_Check(pyValue))
|
fazekasgy@37
|
82 {
|
fazekasgy@37
|
83 // PEP353: Py_ssize_t is size_t but signed !
|
fazekasgy@37
|
84 // This will work up to numpy.float64
|
fazekasgy@37
|
85 Py_ssize_t rValue = PyNumber_AsSsize_t(pyValue,NULL);
|
fazekasgy@37
|
86 if (PyErr_Occurred())
|
fazekasgy@37
|
87 {
|
fazekasgy@37
|
88 PyErr_Print(); PyErr_Clear();
|
fazekasgy@37
|
89 setValueError("Error while converting integer object.",m_strict);
|
fazekasgy@37
|
90 return 0.0;
|
fazekasgy@37
|
91 }
|
fazekasgy@37
|
92 if (rValue > (Py_ssize_t)FLT_MAX || rValue < (Py_ssize_t)FLT_MIN)
|
fazekasgy@37
|
93 {
|
fazekasgy@37
|
94 setValueError("Overflow error. Object can not be converted to float.",m_strict);
|
fazekasgy@37
|
95 return 0.0;
|
fazekasgy@37
|
96 }
|
fazekasgy@37
|
97 return (float) rValue;
|
fazekasgy@37
|
98 }
|
fazekasgy@37
|
99 */
|
fazekasgy@37
|
100 // convert string
|
fazekasgy@37
|
101 if (PyString_Check(pyValue))
|
fazekasgy@37
|
102 {
|
fazekasgy@37
|
103 PyObject* pyFloat = PyFloat_FromString(pyValue,NULL);
|
fazekasgy@37
|
104 if (!pyFloat)
|
fazekasgy@37
|
105 {
|
fazekasgy@37
|
106 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
|
fazekasgy@37
|
107 setValueError("String value can not be converted to float.",m_strict);
|
fazekasgy@37
|
108 return 0.0;
|
fazekasgy@37
|
109 }
|
fazekasgy@37
|
110 float rValue = (float) PyFloat_AS_DOUBLE(pyFloat);
|
fazekasgy@37
|
111 if (PyErr_Occurred())
|
fazekasgy@37
|
112 {
|
fazekasgy@37
|
113 PyErr_Print(); PyErr_Clear();
|
fazekasgy@37
|
114 Py_CLEAR(pyFloat);
|
fazekasgy@37
|
115 setValueError("Error while converting float object.",m_strict);
|
fazekasgy@37
|
116 return 0.0;
|
fazekasgy@37
|
117 }
|
fazekasgy@37
|
118 Py_DECREF(pyFloat);
|
fazekasgy@37
|
119 return rValue;
|
fazekasgy@37
|
120 }
|
fazekasgy@37
|
121
|
fazekasgy@37
|
122 // convert the first element of any iterable sequence (for convenience and backwards compatibility)
|
cannam@41
|
123 if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0)
|
fazekasgy@37
|
124 {
|
fazekasgy@37
|
125 PyObject* item = PySequence_GetItem(pyValue,0);
|
fazekasgy@37
|
126 if (item)
|
fazekasgy@37
|
127 {
|
fazekasgy@37
|
128 float rValue = this->PyValue_To_Float(item);
|
fazekasgy@37
|
129 if (!m_error) {
|
fazekasgy@37
|
130 Py_DECREF(item);
|
fazekasgy@37
|
131 return rValue;
|
fazekasgy@37
|
132 } else {
|
fazekasgy@37
|
133 Py_CLEAR(item);
|
fazekasgy@37
|
134 std::string msg = "Could not convert sequence element to float. ";
|
fazekasgy@37
|
135 setValueError(msg,m_strict);
|
fazekasgy@37
|
136 return 0.0;
|
fazekasgy@37
|
137 }
|
fazekasgy@37
|
138 }
|
fazekasgy@37
|
139 }
|
fazekasgy@37
|
140
|
fazekasgy@37
|
141 // give up
|
fazekasgy@37
|
142 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
|
fazekasgy@37
|
143 std::string msg = "Conversion from " + PyValue_Get_TypeName(pyValue) + " to float is not possible.";
|
fazekasgy@37
|
144 setValueError(msg,m_strict);
|
fazekasgy@37
|
145 #ifdef _DEBUG
|
Chris@71
|
146 cerr << "PyTypeConversions::PyValue_To_Float failed. " << msg << endl;
|
fazekasgy@37
|
147 #endif
|
fazekasgy@37
|
148 return 0.0;
|
fazekasgy@37
|
149 }
|
fazekasgy@37
|
150
|
fazekasgy@37
|
151 /// size_t (unsigned integer types)
|
fazekasgy@37
|
152 size_t
|
Chris@71
|
153 PyTypeConversions::PyValue_To_Size_t(PyObject* pyValue) const
|
fazekasgy@37
|
154 {
|
fazekasgy@37
|
155 // convert objects supporting the number protocol
|
fazekasgy@37
|
156 if (PyNumber_Check(pyValue))
|
fazekasgy@37
|
157 {
|
fazekasgy@37
|
158 if (m_strict && !PyInt_Check(pyValue) && !PyLong_Check(pyValue))
|
fazekasgy@37
|
159 setValueError("Strict conversion error: object is not integer type.",m_strict);
|
fazekasgy@37
|
160 // Note: this function handles Bool,Int,Long,Float
|
fazekasgy@37
|
161 // speed is not critical in the use of this type by Vamp
|
fazekasgy@37
|
162 // PEP353: Py_ssize_t is size_t but signed !
|
fazekasgy@37
|
163 Py_ssize_t rValue = PyInt_AsSsize_t(pyValue);
|
fazekasgy@37
|
164 if (PyErr_Occurred())
|
fazekasgy@37
|
165 {
|
fazekasgy@37
|
166 PyErr_Print(); PyErr_Clear();
|
fazekasgy@37
|
167 setValueError("Error while converting integer object.",m_strict);
|
fazekasgy@37
|
168 return 0;
|
fazekasgy@37
|
169 }
|
Chris@70
|
170 // this test is nonsense -- neither part can occur
|
Chris@70
|
171 // owing to range of data types -- size_t is at least
|
Chris@70
|
172 // as big as long, and unsigned is always non-negative
|
Chris@70
|
173 /*
|
fazekasgy@37
|
174 if ((unsigned long)rValue > SIZE_T_MAX || (unsigned long)rValue < 0)
|
fazekasgy@37
|
175 {
|
fazekasgy@37
|
176 setValueError("Overflow error. Object can not be converted to size_t.",m_strict);
|
fazekasgy@37
|
177 return 0;
|
fazekasgy@37
|
178 }
|
Chris@70
|
179 */
|
fazekasgy@37
|
180 return (size_t) rValue;
|
fazekasgy@37
|
181 }
|
fazekasgy@37
|
182
|
fazekasgy@37
|
183 // in strict mode we will not try harder and throw an exception
|
fazekasgy@37
|
184 // then the caller should decide what to do with it
|
fazekasgy@37
|
185 if (m_strict) {
|
fazekasgy@37
|
186 setValueError("Strict conversion error: object is not integer.",m_strict);
|
fazekasgy@37
|
187 return 0;
|
fazekasgy@37
|
188 }
|
fazekasgy@37
|
189
|
fazekasgy@37
|
190 // convert string
|
fazekasgy@37
|
191 if (PyString_Check(pyValue))
|
fazekasgy@37
|
192 {
|
fazekasgy@37
|
193 PyObject* pyLong = PyNumber_Long(pyValue);
|
fazekasgy@37
|
194 if (!pyLong)
|
fazekasgy@37
|
195 {
|
fazekasgy@37
|
196 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
|
fazekasgy@37
|
197 setValueError("String object can not be converted to size_t.",m_strict);
|
fazekasgy@37
|
198 return 0;
|
fazekasgy@37
|
199 }
|
fazekasgy@37
|
200 size_t rValue = this->PyValue_To_Size_t(pyLong);
|
fazekasgy@37
|
201 if (!m_error) {
|
fazekasgy@37
|
202 Py_DECREF(pyLong);
|
fazekasgy@37
|
203 return rValue;
|
fazekasgy@37
|
204 } else {
|
fazekasgy@37
|
205 Py_CLEAR(pyLong);
|
fazekasgy@37
|
206 setValueError ("Error converting string to size_t.",m_strict);
|
fazekasgy@37
|
207 return 0;
|
fazekasgy@37
|
208 }
|
fazekasgy@37
|
209 }
|
fazekasgy@37
|
210
|
fazekasgy@37
|
211 // convert the first element of iterable sequences
|
cannam@41
|
212 if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0)
|
fazekasgy@37
|
213 {
|
fazekasgy@37
|
214 PyObject* item = PySequence_GetItem(pyValue,0);
|
fazekasgy@37
|
215 if (item)
|
fazekasgy@37
|
216 {
|
fazekasgy@37
|
217 size_t rValue = this->PyValue_To_Size_t(item);
|
fazekasgy@37
|
218 if (!m_error) {
|
fazekasgy@37
|
219 Py_DECREF(item);
|
fazekasgy@37
|
220 return rValue;
|
fazekasgy@37
|
221 } else {
|
fazekasgy@37
|
222 Py_CLEAR(item);
|
fazekasgy@37
|
223 setValueError("Could not convert sequence element to size_t. ",m_strict);
|
fazekasgy@37
|
224 return 0;
|
fazekasgy@37
|
225 }
|
fazekasgy@37
|
226 }
|
fazekasgy@37
|
227 }
|
fazekasgy@37
|
228
|
fazekasgy@37
|
229 // give up
|
fazekasgy@37
|
230 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
|
fazekasgy@37
|
231 std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to size_t is not possible.";
|
fazekasgy@37
|
232 setValueError(msg,m_strict);
|
fazekasgy@37
|
233 #ifdef _DEBUG
|
Chris@71
|
234 cerr << "PyTypeConversions::PyValue_To_Size_t failed. " << msg << endl;
|
fazekasgy@37
|
235 #endif
|
fazekasgy@37
|
236 return 0;
|
fazekasgy@37
|
237 }
|
fazekasgy@37
|
238
|
fazekasgy@37
|
239 /// long and int
|
fazekasgy@37
|
240 long
|
Chris@71
|
241 PyTypeConversions::PyValue_To_Long(PyObject* pyValue) const
|
fazekasgy@37
|
242 {
|
fazekasgy@37
|
243 // most common case: convert int (faster)
|
fazekasgy@37
|
244 if (pyValue && PyInt_Check(pyValue)) {
|
fazekasgy@37
|
245 // if the object is not NULL and verified, this macro just extracts the value.
|
fazekasgy@37
|
246 return PyInt_AS_LONG(pyValue);
|
fazekasgy@37
|
247 }
|
fazekasgy@37
|
248
|
fazekasgy@37
|
249 // long
|
fazekasgy@37
|
250 if (PyLong_Check(pyValue)) {
|
fazekasgy@37
|
251 long rValue = PyLong_AsLong(pyValue);
|
fazekasgy@37
|
252 if (PyErr_Occurred()) {
|
fazekasgy@37
|
253 PyErr_Print(); PyErr_Clear();
|
fazekasgy@37
|
254 setValueError("Error while converting long object.",m_strict);
|
fazekasgy@37
|
255 return 0;
|
fazekasgy@37
|
256 }
|
fazekasgy@37
|
257 return rValue;
|
fazekasgy@37
|
258 }
|
fazekasgy@37
|
259
|
fazekasgy@37
|
260 if (m_strict) {
|
fazekasgy@37
|
261 setValueError("Strict conversion error: object is not integer or long integer.",m_strict);
|
fazekasgy@37
|
262 return 0;
|
fazekasgy@37
|
263 }
|
fazekasgy@37
|
264
|
fazekasgy@37
|
265 // convert all objects supporting the number protocol
|
fazekasgy@37
|
266 if (PyNumber_Check(pyValue))
|
fazekasgy@37
|
267 {
|
fazekasgy@37
|
268 // Note: this function handles Bool,Int,Long,Float
|
fazekasgy@37
|
269 // PEP353: Py_ssize_t is size_t but signed !
|
fazekasgy@37
|
270 Py_ssize_t rValue = PyInt_AsSsize_t(pyValue);
|
fazekasgy@37
|
271 if (PyErr_Occurred())
|
fazekasgy@37
|
272 {
|
fazekasgy@37
|
273 PyErr_Print(); PyErr_Clear();
|
fazekasgy@37
|
274 setValueError("Error while converting integer object.",m_strict);
|
fazekasgy@37
|
275 return 0;
|
fazekasgy@37
|
276 }
|
fazekasgy@37
|
277 if (rValue > LONG_MAX || rValue < LONG_MIN)
|
fazekasgy@37
|
278 {
|
fazekasgy@37
|
279 setValueError("Overflow error. Object can not be converted to size_t.",m_strict);
|
fazekasgy@37
|
280 return 0;
|
fazekasgy@37
|
281 }
|
fazekasgy@37
|
282 return (long) rValue;
|
fazekasgy@37
|
283 }
|
fazekasgy@37
|
284
|
fazekasgy@37
|
285 // convert string
|
fazekasgy@37
|
286 if (PyString_Check(pyValue))
|
fazekasgy@37
|
287 {
|
fazekasgy@37
|
288 PyObject* pyLong = PyNumber_Long(pyValue);
|
fazekasgy@37
|
289 if (!pyLong)
|
fazekasgy@37
|
290 {
|
fazekasgy@37
|
291 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
|
fazekasgy@37
|
292 setValueError("String object can not be converted to long.",m_strict);
|
fazekasgy@37
|
293 return 0;
|
fazekasgy@37
|
294 }
|
fazekasgy@37
|
295 long rValue = this->PyValue_To_Long(pyLong);
|
fazekasgy@37
|
296 if (!m_error) {
|
fazekasgy@37
|
297 Py_DECREF(pyLong);
|
fazekasgy@37
|
298 return rValue;
|
fazekasgy@37
|
299 } else {
|
fazekasgy@37
|
300 Py_CLEAR(pyLong);
|
fazekasgy@37
|
301 setValueError ("Error converting string to long.",m_strict);
|
fazekasgy@37
|
302 return 0;
|
fazekasgy@37
|
303 }
|
fazekasgy@37
|
304 }
|
fazekasgy@37
|
305
|
fazekasgy@37
|
306 // convert the first element of iterable sequences
|
cannam@46
|
307 if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0)
|
fazekasgy@37
|
308 {
|
fazekasgy@37
|
309 PyObject* item = PySequence_GetItem(pyValue,0);
|
fazekasgy@37
|
310 if (item)
|
fazekasgy@37
|
311 {
|
fazekasgy@37
|
312 size_t rValue = this->PyValue_To_Long(item);
|
fazekasgy@37
|
313 if (!m_error) {
|
fazekasgy@37
|
314 Py_DECREF(item);
|
fazekasgy@37
|
315 return rValue;
|
fazekasgy@37
|
316 } else {
|
fazekasgy@37
|
317 Py_CLEAR(item);
|
fazekasgy@37
|
318 setValueError("Could not convert sequence element to long. ",m_strict);
|
fazekasgy@37
|
319 return 0;
|
fazekasgy@37
|
320 }
|
fazekasgy@37
|
321 }
|
fazekasgy@37
|
322 }
|
fazekasgy@37
|
323
|
fazekasgy@37
|
324 // give up
|
fazekasgy@37
|
325 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
|
fazekasgy@37
|
326 std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to long is not possible.";
|
fazekasgy@37
|
327 setValueError(msg,m_strict);
|
fazekasgy@37
|
328 #ifdef _DEBUG
|
Chris@71
|
329 cerr << "PyTypeConversions::PyValue_To_Long failed. " << msg << endl;
|
fazekasgy@37
|
330 #endif
|
fazekasgy@37
|
331 return 0;
|
fazekasgy@37
|
332 }
|
fazekasgy@37
|
333
|
fazekasgy@37
|
334
|
fazekasgy@37
|
335 bool
|
Chris@71
|
336 PyTypeConversions::PyValue_To_Bool(PyObject* pyValue) const
|
fazekasgy@37
|
337 {
|
fazekasgy@37
|
338 // convert objects supporting the number protocol
|
fazekasgy@37
|
339 // Note: PyBool is a subclass of PyInt
|
fazekasgy@37
|
340 if (PyNumber_Check(pyValue))
|
fazekasgy@37
|
341 {
|
fazekasgy@37
|
342 if (m_strict && !PyBool_Check(pyValue))
|
fazekasgy@37
|
343 setValueError
|
fazekasgy@37
|
344 ("Strict conversion error: object is not boolean type.",m_strict);
|
fazekasgy@37
|
345
|
fazekasgy@37
|
346 // Note: this function handles Bool,Int,Long,Float
|
fazekasgy@37
|
347 Py_ssize_t rValue = PyInt_AsSsize_t(pyValue);
|
fazekasgy@37
|
348 if (PyErr_Occurred())
|
fazekasgy@37
|
349 {
|
fazekasgy@37
|
350 PyErr_Print(); PyErr_Clear();
|
fazekasgy@37
|
351 setValueError ("Error while converting boolean object.",m_strict);
|
fazekasgy@37
|
352 }
|
fazekasgy@37
|
353 if (rValue != 1 && rValue != 0)
|
fazekasgy@37
|
354 {
|
fazekasgy@37
|
355 setValueError ("Overflow error. Object can not be converted to boolean.",m_strict);
|
fazekasgy@37
|
356 }
|
fazekasgy@37
|
357 return (bool) rValue;
|
fazekasgy@37
|
358 }
|
fazekasgy@37
|
359
|
fazekasgy@37
|
360 if (m_strict) {
|
fazekasgy@37
|
361 setValueError ("Strict conversion error: object is not numerical type.",m_strict);
|
fazekasgy@37
|
362 return false;
|
fazekasgy@37
|
363 }
|
fazekasgy@37
|
364
|
fazekasgy@37
|
365 // convert iterables: the rule is the same as in the interpreter:
|
fazekasgy@37
|
366 // empty sequence evaluates to False, anything else is True
|
fazekasgy@37
|
367 if (PySequence_Check(pyValue))
|
fazekasgy@37
|
368 {
|
fazekasgy@37
|
369 return PySequence_Size(pyValue)?true:false;
|
fazekasgy@37
|
370 }
|
fazekasgy@37
|
371
|
fazekasgy@37
|
372 // give up
|
fazekasgy@37
|
373 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
|
fazekasgy@37
|
374 std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to boolean is not possible.";
|
fazekasgy@37
|
375 setValueError(msg,m_strict);
|
fazekasgy@37
|
376 #ifdef _DEBUG
|
Chris@71
|
377 cerr << "PyTypeConversions::PyValue_To_Bool failed. " << msg << endl;
|
fazekasgy@37
|
378 #endif
|
fazekasgy@37
|
379 return false;
|
fazekasgy@37
|
380 }
|
fazekasgy@37
|
381
|
fazekasgy@37
|
382 /// string and objects that support .__str__()
|
fazekasgy@37
|
383 /// TODO: check unicode objects
|
fazekasgy@37
|
384 std::string
|
Chris@71
|
385 PyTypeConversions::PyValue_To_String(PyObject* pyValue) const
|
fazekasgy@37
|
386 {
|
fazekasgy@37
|
387 // convert string
|
fazekasgy@37
|
388 if (PyString_Check(pyValue))
|
fazekasgy@37
|
389 {
|
fazekasgy@37
|
390 char *cstr = PyString_AS_STRING(pyValue);
|
fazekasgy@37
|
391 if (!cstr)
|
fazekasgy@37
|
392 {
|
fazekasgy@37
|
393 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
394 setValueError("Error while converting string object.",m_strict);
|
fazekasgy@37
|
395 return std::string();
|
fazekasgy@37
|
396 }
|
fazekasgy@37
|
397 return std::string(cstr);
|
fazekasgy@37
|
398 }
|
fazekasgy@37
|
399 // TODO: deal with unicode here (argh!)
|
fazekasgy@37
|
400
|
fazekasgy@37
|
401 // in strict mode we will not try harder
|
fazekasgy@37
|
402 if (m_strict) {
|
fazekasgy@37
|
403 setValueError("Strict conversion error: object is not string.",m_strict);
|
fazekasgy@37
|
404 return std::string();
|
fazekasgy@37
|
405 }
|
fazekasgy@37
|
406
|
fazekasgy@37
|
407 // accept None as empty string
|
fazekasgy@37
|
408 if (pyValue == Py_None) return std::string();
|
fazekasgy@37
|
409
|
fazekasgy@37
|
410 // convert list or tuple: empties are turned into empty strings conventionally
|
fazekasgy@37
|
411 if (PyList_Check(pyValue) || PyTuple_Check(pyValue))
|
fazekasgy@37
|
412 {
|
fazekasgy@37
|
413 if (!PySequence_Size(pyValue)) return std::string();
|
fazekasgy@37
|
414 PyObject* item = PySequence_GetItem(pyValue,0);
|
fazekasgy@37
|
415 if (item)
|
fazekasgy@37
|
416 {
|
fazekasgy@37
|
417 std::string rValue = this->PyValue_To_String(item);
|
fazekasgy@37
|
418 if (!m_error) {
|
fazekasgy@37
|
419 Py_DECREF(item);
|
fazekasgy@37
|
420 return rValue;
|
fazekasgy@37
|
421 } else {
|
fazekasgy@37
|
422 Py_CLEAR(item);
|
fazekasgy@37
|
423 setValueError("Could not convert sequence element to string.",m_strict);
|
fazekasgy@37
|
424 return std::string();
|
fazekasgy@37
|
425 }
|
fazekasgy@37
|
426 }
|
fazekasgy@37
|
427 }
|
fazekasgy@37
|
428
|
fazekasgy@37
|
429 // convert any other object that has .__str__() or .__repr__()
|
fazekasgy@37
|
430 PyObject* pyString = PyObject_Str(pyValue);
|
fazekasgy@37
|
431 if (pyString && !PyErr_Occurred())
|
fazekasgy@37
|
432 {
|
fazekasgy@37
|
433 std::string rValue = this->PyValue_To_String(pyString);
|
fazekasgy@37
|
434 if (!m_error) {
|
fazekasgy@37
|
435 Py_DECREF(pyString);
|
fazekasgy@37
|
436 return rValue;
|
fazekasgy@37
|
437 } else {
|
fazekasgy@37
|
438 Py_CLEAR(pyString);
|
fazekasgy@37
|
439 std::string msg = "Object " + this->PyValue_Get_TypeName(pyValue) +" can not be represented as string. ";
|
fazekasgy@37
|
440 setValueError (msg,m_strict);
|
fazekasgy@37
|
441 return std::string();
|
fazekasgy@37
|
442 }
|
fazekasgy@37
|
443 }
|
fazekasgy@37
|
444
|
fazekasgy@37
|
445 // give up
|
fazekasgy@37
|
446 PyErr_Print(); PyErr_Clear();
|
fazekasgy@37
|
447 std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to string is not possible.";
|
fazekasgy@37
|
448 setValueError(msg,m_strict);
|
fazekasgy@37
|
449 #ifdef _DEBUG
|
Chris@71
|
450 cerr << "PyTypeConversions::PyValue_To_String failed. " << msg << endl;
|
fazekasgy@37
|
451 #endif
|
fazekasgy@37
|
452 return std::string();
|
fazekasgy@37
|
453 }
|
fazekasgy@37
|
454
|
fazekasgy@37
|
455 /* C Values to Py Values */
|
fazekasgy@37
|
456
|
fazekasgy@37
|
457
|
fazekasgy@37
|
458 PyObject*
|
Chris@71
|
459 PyTypeConversions::PyValue_From_CValue(const char* cValue) const
|
fazekasgy@37
|
460 {
|
fazekasgy@37
|
461 // returns new reference
|
fazekasgy@37
|
462 #ifdef _DEBUG
|
fazekasgy@37
|
463 if (!cValue) {
|
Chris@71
|
464 std::string msg = "PyTypeConversions::PyValue_From_CValue: Null pointer encountered while converting from const char* .";
|
fazekasgy@37
|
465 cerr << msg << endl;
|
fazekasgy@37
|
466 setValueError(msg,m_strict);
|
fazekasgy@37
|
467 return NULL;
|
fazekasgy@37
|
468 }
|
fazekasgy@37
|
469 #endif
|
fazekasgy@37
|
470 PyObject *pyValue = PyString_FromString(cValue);
|
fazekasgy@37
|
471 if (!pyValue)
|
fazekasgy@37
|
472 {
|
fazekasgy@37
|
473 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
474 setValueError("Error while converting from char* or string.",m_strict);
|
fazekasgy@37
|
475 #ifdef _DEBUG
|
Chris@71
|
476 cerr << "PyTypeConversions::PyValue_From_CValue: Interpreter failed to convert from const char*" << endl;
|
fazekasgy@37
|
477 #endif
|
fazekasgy@37
|
478 return NULL;
|
fazekasgy@37
|
479 }
|
fazekasgy@37
|
480 return pyValue;
|
fazekasgy@37
|
481 }
|
fazekasgy@37
|
482
|
fazekasgy@37
|
483 PyObject*
|
Chris@71
|
484 PyTypeConversions::PyValue_From_CValue(size_t cValue) const
|
fazekasgy@37
|
485 {
|
fazekasgy@37
|
486 // returns new reference
|
fazekasgy@37
|
487 PyObject *pyValue = PyInt_FromSsize_t((Py_ssize_t)cValue);
|
fazekasgy@37
|
488 if (!pyValue)
|
fazekasgy@37
|
489 {
|
fazekasgy@37
|
490 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
491 setValueError("Error while converting from size_t.",m_strict);
|
fazekasgy@37
|
492 #ifdef _DEBUG
|
Chris@71
|
493 cerr << "PyTypeConversions::PyValue_From_CValue: Interpreter failed to convert from size_t" << endl;
|
fazekasgy@37
|
494 #endif
|
fazekasgy@37
|
495 return NULL;
|
fazekasgy@37
|
496 }
|
fazekasgy@37
|
497 return pyValue;
|
fazekasgy@37
|
498 }
|
fazekasgy@37
|
499
|
fazekasgy@37
|
500 PyObject*
|
Chris@71
|
501 PyTypeConversions::PyValue_From_CValue(double cValue) const
|
fazekasgy@37
|
502 {
|
fazekasgy@37
|
503 // returns new reference
|
fazekasgy@37
|
504 PyObject *pyValue = PyFloat_FromDouble(cValue);
|
fazekasgy@37
|
505 if (!pyValue)
|
fazekasgy@37
|
506 {
|
fazekasgy@37
|
507 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
508 setValueError("Error while converting from float or double.",m_strict);
|
fazekasgy@37
|
509 #ifdef _DEBUG
|
Chris@71
|
510 cerr << "PyTypeConversions::PyValue_From_CValue: Interpreter failed to convert from float or double" << endl;
|
fazekasgy@37
|
511 #endif
|
fazekasgy@37
|
512 return NULL;
|
fazekasgy@37
|
513 }
|
fazekasgy@37
|
514 return pyValue;
|
fazekasgy@37
|
515 }
|
fazekasgy@37
|
516
|
fazekasgy@37
|
517 PyObject*
|
Chris@71
|
518 PyTypeConversions::PyValue_From_CValue(bool cValue) const
|
fazekasgy@37
|
519 {
|
fazekasgy@37
|
520 // returns new reference
|
fazekasgy@37
|
521 PyObject *pyValue = PyBool_FromLong((long)cValue);
|
fazekasgy@37
|
522 if (!pyValue)
|
fazekasgy@37
|
523 {
|
fazekasgy@37
|
524 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
525 setValueError("Error while converting from bool.",m_strict);
|
fazekasgy@37
|
526 #ifdef _DEBUG
|
Chris@71
|
527 cerr << "PyTypeConversions::PyValue_From_CValue: Interpreter failed to convert from bool" << endl;
|
fazekasgy@37
|
528 #endif
|
fazekasgy@37
|
529 return NULL;
|
fazekasgy@37
|
530 }
|
fazekasgy@37
|
531 return pyValue;
|
fazekasgy@37
|
532 }
|
fazekasgy@37
|
533
|
fazekasgy@37
|
534
|
fazekasgy@37
|
535 /* Sequence Types to C++ Types */
|
fazekasgy@37
|
536
|
fazekasgy@37
|
537 //convert Python list to C++ vector of strings
|
fazekasgy@37
|
538 std::vector<std::string>
|
Chris@71
|
539 PyTypeConversions::PyValue_To_StringVector (PyObject *pyList) const
|
fazekasgy@37
|
540 {
|
fazekasgy@37
|
541
|
fazekasgy@37
|
542 std::vector<std::string> Output;
|
fazekasgy@37
|
543 std::string ListElement;
|
fazekasgy@37
|
544 PyObject *pyString = NULL;
|
fazekasgy@37
|
545
|
fazekasgy@37
|
546 if (PyList_Check(pyList)) {
|
fazekasgy@37
|
547
|
fazekasgy@37
|
548 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) {
|
fazekasgy@37
|
549 //Get next list item (Borrowed Reference)
|
fazekasgy@37
|
550 pyString = PyList_GET_ITEM(pyList,i);
|
fazekasgy@37
|
551 ListElement = (string) PyString_AsString(PyObject_Str(pyString));
|
fazekasgy@37
|
552 Output.push_back(ListElement);
|
fazekasgy@37
|
553 }
|
fazekasgy@37
|
554 return Output;
|
fazekasgy@37
|
555 }
|
fazekasgy@51
|
556
|
fazekasgy@51
|
557 // #ifdef _DEBUG
|
Chris@71
|
558 // cerr << "PyTypeConversions::PyValue_To_StringVector: Warning: Value is not list of strings." << endl;
|
fazekasgy@51
|
559 // #endif
|
fazekasgy@37
|
560
|
fazekasgy@37
|
561 /// Assume a single value that can be casted as string
|
fazekasgy@37
|
562 /// this allows to write e.g. Feature.label = 5.2 instead of ['5.2']
|
fazekasgy@37
|
563 Output.push_back(PyValue_To_String(pyList));
|
fazekasgy@37
|
564 if (m_error) {
|
fazekasgy@37
|
565 std::string msg = "Value is not list of strings nor can be casted as string. ";
|
fazekasgy@37
|
566 setValueError(msg,m_strict);
|
fazekasgy@37
|
567 #ifdef _DEBUG
|
Chris@71
|
568 cerr << "PyTypeConversions::PyValue_To_StringVector failed. " << msg << endl;
|
fazekasgy@37
|
569 #endif
|
fazekasgy@37
|
570 }
|
fazekasgy@37
|
571 return Output;
|
fazekasgy@37
|
572 }
|
fazekasgy@37
|
573
|
fazekasgy@37
|
574 //convert PyFeature.value (typically a list or numpy array) to C++ vector of floats
|
fazekasgy@37
|
575 std::vector<float>
|
Chris@71
|
576 PyTypeConversions::PyValue_To_FloatVector (PyObject *pyValue) const
|
fazekasgy@37
|
577 {
|
fazekasgy@37
|
578
|
fazekasgy@37
|
579 #ifdef HAVE_NUMPY
|
fazekasgy@51
|
580 if (m_numpyInstalled)
|
fazekasgy@51
|
581 {
|
fazekasgy@37
|
582 // there are four types of values we may receive from a numpy process:
|
fazekasgy@37
|
583 // * a python scalar,
|
fazekasgy@37
|
584 // * an array scalar, (e.g. numpy.float32)
|
fazekasgy@37
|
585 // * an array with nd = 0 (0D array)
|
fazekasgy@37
|
586 // * an array with nd > 0
|
fazekasgy@37
|
587
|
fazekasgy@37
|
588 /// check for scalars
|
fazekasgy@37
|
589 if (PyArray_CheckScalar(pyValue) || PyFloat_Check(pyValue)) {
|
fazekasgy@37
|
590
|
fazekasgy@37
|
591 std::vector<float> Output;
|
fazekasgy@37
|
592
|
fazekasgy@37
|
593 // we rely on the behaviour the scalars are either floats
|
fazekasgy@37
|
594 // or support the number protocol
|
fazekasgy@37
|
595 // TODO: a potential optimisation is to handle them directly
|
fazekasgy@37
|
596 Output.push_back(PyValue_To_Float(pyValue));
|
fazekasgy@37
|
597 return Output;
|
fazekasgy@37
|
598 }
|
fazekasgy@37
|
599
|
fazekasgy@37
|
600 /// numpy array
|
fazekasgy@37
|
601 if (PyArray_CheckExact(pyValue))
|
fazekasgy@37
|
602 return PyArray_To_FloatVector(pyValue);
|
fazekasgy@51
|
603 }
|
fazekasgy@37
|
604 #endif
|
fazekasgy@37
|
605
|
fazekasgy@37
|
606 /// python list of floats (backward compatible)
|
fazekasgy@37
|
607 if (PyList_Check(pyValue)) {
|
fazekasgy@37
|
608 return PyList_To_FloatVector(pyValue);
|
fazekasgy@37
|
609 }
|
fazekasgy@37
|
610
|
fazekasgy@37
|
611 std::vector<float> Output;
|
fazekasgy@37
|
612
|
fazekasgy@37
|
613 /// finally assume a single value supporting the number protocol
|
fazekasgy@37
|
614 /// this allows to write e.g. Feature.values = 5 instead of [5.00]
|
fazekasgy@37
|
615 Output.push_back(PyValue_To_Float(pyValue));
|
fazekasgy@37
|
616 if (m_error) {
|
fazekasgy@37
|
617 std::string msg = "Value is not list or array of floats nor can be casted as float. ";
|
fazekasgy@37
|
618 setValueError(msg,m_strict);
|
fazekasgy@37
|
619 #ifdef _DEBUG
|
Chris@71
|
620 cerr << "PyTypeConversions::PyValue_To_FloatVector failed. " << msg << endl;
|
fazekasgy@37
|
621 #endif
|
fazekasgy@37
|
622 }
|
fazekasgy@37
|
623 return Output;
|
fazekasgy@37
|
624 }
|
fazekasgy@37
|
625
|
fazekasgy@37
|
626 //convert a list of python floats
|
fazekasgy@37
|
627 std::vector<float>
|
Chris@71
|
628 PyTypeConversions::PyList_To_FloatVector (PyObject *inputList) const
|
fazekasgy@37
|
629 {
|
fazekasgy@37
|
630 std::vector<float> Output;
|
fazekasgy@37
|
631
|
fazekasgy@37
|
632 #ifdef _DEBUG
|
fazekasgy@37
|
633 // This is a low level function normally called from
|
fazekasgy@37
|
634 // PyValue_To_FloatVector(). Checking for list is not required.
|
fazekasgy@37
|
635 if (!PyList_Check(inputList)) {
|
fazekasgy@37
|
636 std::string msg = "Value is not list.";
|
fazekasgy@37
|
637 setValueError(msg,true);
|
Chris@71
|
638 cerr << "PyTypeConversions::PyList_To_FloatVector failed. " << msg << endl;
|
fazekasgy@37
|
639 return Output;
|
fazekasgy@37
|
640 }
|
fazekasgy@37
|
641 #endif
|
fazekasgy@37
|
642
|
fazekasgy@37
|
643 float ListElement;
|
fazekasgy@37
|
644 PyObject *pyFloat = NULL;
|
fazekasgy@37
|
645 PyObject **pyObjectArray = PySequence_Fast_ITEMS(inputList);
|
fazekasgy@37
|
646
|
fazekasgy@37
|
647 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) {
|
fazekasgy@37
|
648
|
fazekasgy@37
|
649 // pyFloat = PyList_GET_ITEM(inputList,i);
|
fazekasgy@37
|
650 pyFloat = pyObjectArray[i];
|
fazekasgy@37
|
651
|
fazekasgy@37
|
652 #ifdef _DEBUG
|
fazekasgy@37
|
653 if (!pyFloat) {
|
fazekasgy@37
|
654 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
Chris@71
|
655 cerr << "PyTypeConversions::PyList_To_FloatVector: Could not obtain list element: "
|
fazekasgy@37
|
656 << i << " PyList_GetItem returned NULL! Skipping value." << endl;
|
fazekasgy@37
|
657 continue;
|
fazekasgy@37
|
658 }
|
fazekasgy@37
|
659 #endif
|
fazekasgy@37
|
660
|
fazekasgy@37
|
661 // ListElement = (float) PyFloat_AS_DOUBLE(pyFloat);
|
fazekasgy@37
|
662 ListElement = PyValue_To_Float(pyFloat);
|
fazekasgy@37
|
663
|
fazekasgy@37
|
664
|
fazekasgy@37
|
665 #ifdef _DEBUG_VALUES
|
fazekasgy@37
|
666 cerr << "value: " << ListElement << endl;
|
fazekasgy@37
|
667 #endif
|
fazekasgy@37
|
668 Output.push_back(ListElement);
|
fazekasgy@37
|
669 }
|
fazekasgy@37
|
670 return Output;
|
fazekasgy@37
|
671 }
|
fazekasgy@37
|
672
|
fazekasgy@51
|
673 // if numpy is not installed this will not be called,
|
fazekasgy@51
|
674 // therefor we do not check again
|
fazekasgy@51
|
675 #ifdef HAVE_NUMPY
|
fazekasgy@37
|
676 std::vector<float>
|
Chris@71
|
677 PyTypeConversions::PyArray_To_FloatVector (PyObject *pyValue) const
|
fazekasgy@37
|
678 {
|
fazekasgy@37
|
679 std::vector<float> Output;
|
fazekasgy@37
|
680
|
fazekasgy@37
|
681 #ifdef _DEBUG
|
fazekasgy@37
|
682 // This is a low level function, normally called from
|
fazekasgy@37
|
683 // PyValue_To_FloatVector(). Checking the array here is not required.
|
fazekasgy@37
|
684 if (!PyArray_Check(pyValue)) {
|
Chris@71
|
685 std::string msg = "Object has no array conversions.";
|
fazekasgy@37
|
686 setValueError(msg,true);
|
Chris@71
|
687 cerr << "PyTypeConversions::PyArray_To_FloatVector failed. " << msg << endl;
|
fazekasgy@37
|
688 return Output;
|
fazekasgy@37
|
689 }
|
fazekasgy@37
|
690 #endif
|
fazekasgy@37
|
691
|
fazekasgy@37
|
692 PyArrayObject* pyArray = (PyArrayObject*) pyValue;
|
Chris@66
|
693 PyArray_Descr* descr = PyArray_DESCR(pyArray);
|
fazekasgy@37
|
694
|
fazekasgy@37
|
695 /// check raw data and descriptor pointers
|
Chris@66
|
696 if (PyArray_DATA(pyArray) == 0 || descr == 0) {
|
fazekasgy@37
|
697 std::string msg = "NumPy array with NULL data or descriptor pointer encountered.";
|
fazekasgy@37
|
698 setValueError(msg,m_strict);
|
fazekasgy@37
|
699 #ifdef _DEBUG
|
Chris@71
|
700 cerr << "PyTypeConversions::PyArray_To_FloatVector failed. Error: " << msg << endl;
|
fazekasgy@37
|
701 #endif
|
fazekasgy@37
|
702 return Output;
|
fazekasgy@37
|
703 }
|
fazekasgy@37
|
704
|
fazekasgy@37
|
705 /// check dimensions
|
Chris@66
|
706 if (PyArray_NDIM(pyArray) != 1) {
|
fazekasgy@37
|
707 std::string msg = "NumPy array must be a one dimensional vector.";
|
fazekasgy@37
|
708 setValueError(msg,m_strict);
|
fazekasgy@37
|
709 #ifdef _DEBUG
|
Chris@71
|
710 cerr << "PyTypeConversions::PyArray_To_FloatVector failed. Error: " << msg << " Dims: " << (int) PyArray_NDIM(pyArray) << endl;
|
fazekasgy@37
|
711 #endif
|
fazekasgy@37
|
712 return Output;
|
fazekasgy@37
|
713 }
|
fazekasgy@37
|
714
|
fazekasgy@37
|
715 #ifdef _DEBUG_VALUES
|
Chris@71
|
716 cerr << "PyTypeConversions::PyArray_To_FloatVector: Numpy array verified." << endl;
|
fazekasgy@37
|
717 #endif
|
fazekasgy@37
|
718
|
fazekasgy@37
|
719 /// check strides (useful if array is not continuous)
|
Chris@66
|
720 size_t strides = *((size_t*) PyArray_STRIDES(pyArray));
|
fazekasgy@37
|
721
|
fazekasgy@37
|
722 /// convert the array
|
fazekasgy@37
|
723 switch (descr->type_num)
|
fazekasgy@37
|
724 {
|
fazekasgy@37
|
725 case NPY_FLOAT : // dtype='float32'
|
Chris@66
|
726 return PyArray_Convert<float,float>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
|
fazekasgy@37
|
727 case NPY_DOUBLE : // dtype='float64'
|
Chris@66
|
728 return PyArray_Convert<float,double>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
|
fazekasgy@37
|
729 case NPY_INT : // dtype='int'
|
Chris@66
|
730 return PyArray_Convert<float,int>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
|
fazekasgy@37
|
731 case NPY_LONG : // dtype='long'
|
Chris@66
|
732 return PyArray_Convert<float,long>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
|
fazekasgy@37
|
733 default :
|
fazekasgy@37
|
734 std::string msg = "Unsupported value type in NumPy array object.";
|
fazekasgy@37
|
735 setValueError(msg,m_strict);
|
fazekasgy@37
|
736 #ifdef _DEBUG
|
Chris@71
|
737 cerr << "PyTypeConversions::PyArray_To_FloatVector failed. Error: " << msg << endl;
|
fazekasgy@37
|
738 #endif
|
fazekasgy@37
|
739 return Output;
|
fazekasgy@37
|
740 }
|
fazekasgy@37
|
741 }
|
fazekasgy@37
|
742 #endif
|
fazekasgy@37
|
743
|
fazekasgy@37
|
744
|
fazekasgy@37
|
745
|
fazekasgy@37
|
746 /* Error handling */
|
fazekasgy@37
|
747
|
fazekasgy@37
|
748 void
|
Chris@71
|
749 PyTypeConversions::setValueError (std::string message, bool strict) const
|
fazekasgy@37
|
750 {
|
fazekasgy@37
|
751 m_error = true;
|
fazekasgy@37
|
752 m_errorQueue.push(ValueError(message,strict));
|
fazekasgy@37
|
753 }
|
fazekasgy@37
|
754
|
fazekasgy@37
|
755 /// return a reference to the last error or creates a new one.
|
Chris@71
|
756 ValueError&
|
Chris@71
|
757 PyTypeConversions::lastError() const
|
fazekasgy@37
|
758 {
|
fazekasgy@37
|
759 m_error = false;
|
fazekasgy@37
|
760 if (!m_errorQueue.empty()) return m_errorQueue.back();
|
fazekasgy@37
|
761 else {
|
fazekasgy@37
|
762 m_errorQueue.push(ValueError("Type conversion error.",m_strict));
|
fazekasgy@37
|
763 return m_errorQueue.back();
|
fazekasgy@37
|
764 }
|
fazekasgy@37
|
765 }
|
fazekasgy@37
|
766
|
fazekasgy@37
|
767 /// helper function to iterate over the error message queue:
|
fazekasgy@37
|
768 /// pops the oldest item
|
Chris@71
|
769 ValueError
|
Chris@71
|
770 PyTypeConversions::getError() const
|
fazekasgy@37
|
771 {
|
fazekasgy@37
|
772 if (!m_errorQueue.empty()) {
|
Chris@71
|
773 ValueError e = m_errorQueue.front();
|
fazekasgy@37
|
774 m_errorQueue.pop();
|
fazekasgy@37
|
775 if (m_errorQueue.empty()) m_error = false;
|
fazekasgy@37
|
776 return e;
|
fazekasgy@37
|
777 }
|
fazekasgy@37
|
778 else {
|
fazekasgy@37
|
779 m_error = false;
|
Chris@71
|
780 return ValueError();
|
fazekasgy@37
|
781 }
|
fazekasgy@37
|
782 }
|
fazekasgy@37
|
783
|
fazekasgy@37
|
784 /* Utilities */
|
fazekasgy@37
|
785
|
fazekasgy@37
|
786 /// get the type name of an object
|
fazekasgy@37
|
787 std::string
|
Chris@71
|
788 PyTypeConversions::PyValue_Get_TypeName(PyObject* pyValue) const
|
fazekasgy@37
|
789 {
|
fazekasgy@37
|
790 PyObject *pyType = PyObject_Type(pyValue);
|
fazekasgy@37
|
791 if (!pyType)
|
fazekasgy@37
|
792 {
|
fazekasgy@37
|
793 cerr << "Warning: Object type name could not be found." << endl;
|
fazekasgy@37
|
794 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
795 return std::string ("< unknown type >");
|
fazekasgy@37
|
796 }
|
fazekasgy@37
|
797 PyObject *pyString = PyObject_Str(pyType);
|
fazekasgy@37
|
798 if (!pyString)
|
fazekasgy@37
|
799 {
|
fazekasgy@37
|
800 cerr << "Warning: Object type name could not be found." << endl;
|
fazekasgy@37
|
801 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
802 Py_CLEAR(pyType);
|
fazekasgy@37
|
803 return std::string ("< unknown type >");
|
fazekasgy@37
|
804 }
|
fazekasgy@37
|
805 char *cstr = PyString_AS_STRING(pyString);
|
fazekasgy@37
|
806 if (!cstr)
|
fazekasgy@37
|
807 {
|
fazekasgy@37
|
808 cerr << "Warning: Object type name could not be found." << endl;
|
fazekasgy@37
|
809 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
810 Py_DECREF(pyType);
|
fazekasgy@37
|
811 Py_CLEAR(pyString);
|
fazekasgy@37
|
812 return std::string("< unknown type >");
|
fazekasgy@37
|
813 }
|
fazekasgy@37
|
814 Py_DECREF(pyType);
|
fazekasgy@37
|
815 Py_DECREF(pyString);
|
fazekasgy@37
|
816 return std::string(cstr);
|
fazekasgy@37
|
817
|
fazekasgy@37
|
818 }
|