annotate 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
rev   line source
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 }