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