annotate PyTypeConversions.cpp @ 26:014c48d6f360

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