given an existing python object instance, invoke one of its methods grabs mutex to prevent need for Python GIL
| 454 | // given an existing python object instance, invoke one of its methods |
| 455 | // grabs mutex to prevent need for Python GIL |
| 456 | QVariant EmbeddedPython::callPyObjMethod(PyObjectPtr &pyobj, |
| 457 | const QString &methname, |
| 458 | const QVariantList &args, |
| 459 | int *rv, |
| 460 | QString &tb, |
| 461 | bool ret_python_object) |
| 462 | { |
| 463 | EmbeddedPython::m_mutex.lock(); |
| 464 | PyGILState_STATE gstate = PyGILState_Ensure(); |
| 465 | |
| 466 | QVariant res = QVariant(QString()); |
| 467 | PyObject* obj = pyobj.object(); |
| 468 | PyObject* func = NULL; |
| 469 | PyObject* pyargs = NULL; |
| 470 | PyObject* pyres = NULL; |
| 471 | int idx = 0; |
| 472 | |
| 473 | func = PyObject_GetAttrString(obj,methname.toUtf8().constData()); |
| 474 | if (func == NULL) { |
| 475 | *rv = -1; |
| 476 | goto cleanup; |
| 477 | } |
| 478 | |
| 479 | if (!PyCallable_Check(func)) { |
| 480 | *rv = -2; |
| 481 | goto cleanup; |
| 482 | } |
| 483 | |
| 484 | // Build up Python argument List from args |
| 485 | pyargs = PyTuple_New(args.size()); |
| 486 | idx = 0; |
| 487 | foreach(QVariant arg, args) { |
| 488 | PyTuple_SetItem(pyargs, idx, QVariantToPyObject(arg)); |
| 489 | idx++; |
| 490 | } |
| 491 | |
| 492 | pyres = PyObject_CallObject(func, pyargs); |
| 493 | if (pyres == NULL) { |
| 494 | *rv = -3; |
| 495 | goto cleanup; |
| 496 | } |
| 497 | |
| 498 | *rv = 0; |
| 499 | |
| 500 | res = PyObjectToQVariant(pyres, ret_python_object); |
| 501 | |
| 502 | cleanup: |
| 503 | if (PyErr_Occurred() != NULL) { |
| 504 | QString default_error = "Python Object Method Invocation Error: " + methname; |
| 505 | tb = getPythonErrorTraceback(default_error); |
| 506 | } |
| 507 | Py_XDECREF(pyres); |
| 508 | Py_XDECREF(pyargs); |
| 509 | Py_XDECREF(func); |
| 510 | |
| 511 | PyGILState_Release(gstate); |
| 512 | EmbeddedPython::m_mutex.unlock(); |
| 513 | return res; |
no test coverage detected