ctkAbstractPythonManager.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) Kitware Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0.txt
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. =========================================================================*/
  14. // Qt includes
  15. #include <QDir>
  16. #include <QDebug>
  17. // CTK includes
  18. #include "ctkAbstractPythonManager.h"
  19. #include "ctkScriptingPythonCoreConfigure.h"
  20. // PythonQT includes
  21. #include <PythonQt.h>
  22. #include <PythonQt_QtBindings.h>
  23. // STD includes
  24. #include <csignal>
  25. #ifdef __GNUC__
  26. // Disable warnings related to signal() function
  27. // See http://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html
  28. // Note: Ideally the incriminated functions and macros should be fixed upstream ...
  29. #pragma GCC diagnostic ignored "-Wold-style-cast"
  30. #endif
  31. //-----------------------------------------------------------------------------
  32. class ctkAbstractPythonManagerPrivate
  33. {
  34. Q_DECLARE_PUBLIC(ctkAbstractPythonManager);
  35. protected:
  36. ctkAbstractPythonManager* q_ptr;
  37. public:
  38. ctkAbstractPythonManagerPrivate(ctkAbstractPythonManager& object);
  39. virtual ~ctkAbstractPythonManagerPrivate();
  40. void (*InitFunction)();
  41. int PythonQtInitializationFlags;
  42. };
  43. //-----------------------------------------------------------------------------
  44. // ctkAbstractPythonManagerPrivate methods
  45. //-----------------------------------------------------------------------------
  46. ctkAbstractPythonManagerPrivate::ctkAbstractPythonManagerPrivate(ctkAbstractPythonManager &object) :
  47. q_ptr(&object)
  48. {
  49. this->InitFunction = 0;
  50. this->PythonQtInitializationFlags = PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut;
  51. }
  52. //-----------------------------------------------------------------------------
  53. ctkAbstractPythonManagerPrivate::~ctkAbstractPythonManagerPrivate()
  54. {
  55. }
  56. //-----------------------------------------------------------------------------
  57. // ctkAbstractPythonManager methods
  58. //-----------------------------------------------------------------------------
  59. ctkAbstractPythonManager::ctkAbstractPythonManager(QObject* _parent) : Superclass(_parent),
  60. d_ptr(new ctkAbstractPythonManagerPrivate(*this))
  61. {
  62. }
  63. //-----------------------------------------------------------------------------
  64. ctkAbstractPythonManager::~ctkAbstractPythonManager()
  65. {
  66. if (Py_IsInitialized())
  67. {
  68. Py_Finalize();
  69. }
  70. PythonQt::cleanup();
  71. }
  72. //-----------------------------------------------------------------------------
  73. void ctkAbstractPythonManager::setInitializationFlags(int flags)
  74. {
  75. Q_D(ctkAbstractPythonManager);
  76. if (PythonQt::self())
  77. {
  78. return;
  79. }
  80. d->PythonQtInitializationFlags = flags;
  81. }
  82. //-----------------------------------------------------------------------------
  83. int ctkAbstractPythonManager::initializationFlags()const
  84. {
  85. Q_D(const ctkAbstractPythonManager);
  86. return d->PythonQtInitializationFlags;
  87. }
  88. //-----------------------------------------------------------------------------
  89. bool ctkAbstractPythonManager::initialize()
  90. {
  91. Q_D(ctkAbstractPythonManager);
  92. if (!PythonQt::self())
  93. {
  94. this->initPythonQt(d->PythonQtInitializationFlags);
  95. }
  96. return this->isPythonInitialized();
  97. }
  98. //-----------------------------------------------------------------------------
  99. PythonQtObjectPtr ctkAbstractPythonManager::mainContext()
  100. {
  101. bool initalized = this->initialize();
  102. if (initalized)
  103. {
  104. return PythonQt::self()->getMainModule();
  105. }
  106. return PythonQtObjectPtr();
  107. }
  108. //-----------------------------------------------------------------------------
  109. void ctkAbstractPythonManager::initPythonQt(int flags)
  110. {
  111. Q_D(ctkAbstractPythonManager);
  112. PythonQt::init(flags);
  113. // Python maps SIGINT (control-c) to its own handler. We will remap it
  114. // to the default so that control-c works.
  115. #ifdef SIGINT
  116. signal(SIGINT, SIG_DFL);
  117. #endif
  118. // Forward signal from PythonQt::self() to this instance of ctkAbstractPythonManager
  119. this->connect(PythonQt::self(), SIGNAL(systemExitExceptionRaised(int)),
  120. SIGNAL(systemExitExceptionRaised(int)));
  121. this->connect(PythonQt::self(), SIGNAL(pythonStdOut(QString)),
  122. SLOT(printStdout(QString)));
  123. this->connect(PythonQt::self(), SIGNAL(pythonStdErr(QString)),
  124. SLOT(printStderr(QString)));
  125. PythonQt_init_QtBindings();
  126. QStringList initCode;
  127. // Update 'sys.path'
  128. initCode << "import sys";
  129. foreach (const QString& path, this->pythonPaths())
  130. {
  131. initCode << QString("sys.path.append('%1')").arg(QDir::fromNativeSeparators(path));
  132. }
  133. PythonQtObjectPtr _mainContext = PythonQt::self()->getMainModule();
  134. _mainContext.evalScript(initCode.join("\n"));
  135. this->preInitialization();
  136. if (d->InitFunction)
  137. {
  138. (*d->InitFunction)();
  139. }
  140. emit this->pythonPreInitialized();
  141. this->executeInitializationScripts();
  142. emit this->pythonInitialized();
  143. }
  144. //-----------------------------------------------------------------------------
  145. bool ctkAbstractPythonManager::isPythonInitialized()const
  146. {
  147. return PythonQt::self() != 0;
  148. }
  149. //-----------------------------------------------------------------------------
  150. bool ctkAbstractPythonManager::pythonErrorOccured()const
  151. {
  152. if (!PythonQt::self())
  153. {
  154. qWarning() << Q_FUNC_INFO << " failed: PythonQt is not initialized";
  155. return false;
  156. }
  157. return PythonQt::self()->hadError();
  158. }
  159. //-----------------------------------------------------------------------------
  160. void ctkAbstractPythonManager::resetErrorFlag()
  161. {
  162. if (!PythonQt::self())
  163. {
  164. qWarning() << Q_FUNC_INFO << " failed: PythonQt is not initialized";
  165. return;
  166. }
  167. PythonQt::self()->clearError();
  168. }
  169. //-----------------------------------------------------------------------------
  170. QStringList ctkAbstractPythonManager::pythonPaths()
  171. {
  172. return QStringList();
  173. }
  174. //-----------------------------------------------------------------------------
  175. void ctkAbstractPythonManager::preInitialization()
  176. {
  177. }
  178. //-----------------------------------------------------------------------------
  179. void ctkAbstractPythonManager::executeInitializationScripts()
  180. {
  181. }
  182. //-----------------------------------------------------------------------------
  183. void ctkAbstractPythonManager::registerPythonQtDecorator(QObject* decorator)
  184. {
  185. if (!PythonQt::self())
  186. {
  187. qWarning() << Q_FUNC_INFO << " failed: PythonQt is not initialized";
  188. return;
  189. }
  190. PythonQt::self()->addDecorators(decorator);
  191. }
  192. //-----------------------------------------------------------------------------
  193. void ctkAbstractPythonManager::registerClassForPythonQt(const QMetaObject* metaobject)
  194. {
  195. if (!PythonQt::self())
  196. {
  197. qWarning() << Q_FUNC_INFO << " failed: PythonQt is not initialized";
  198. return;
  199. }
  200. PythonQt::self()->registerClass(metaobject);
  201. }
  202. //-----------------------------------------------------------------------------
  203. void ctkAbstractPythonManager::registerCPPClassForPythonQt(const char* name)
  204. {
  205. if (!PythonQt::self())
  206. {
  207. qWarning() << Q_FUNC_INFO << " failed: PythonQt is not initialized";
  208. return;
  209. }
  210. PythonQt::self()->registerCPPClass(name);
  211. }
  212. //-----------------------------------------------------------------------------
  213. bool ctkAbstractPythonManager::systemExitExceptionHandlerEnabled()const
  214. {
  215. if (!PythonQt::self())
  216. {
  217. qWarning() << Q_FUNC_INFO << " failed: PythonQt is not initialized";
  218. return false;
  219. }
  220. return PythonQt::self()->systemExitExceptionHandlerEnabled();
  221. }
  222. //-----------------------------------------------------------------------------
  223. void ctkAbstractPythonManager::setSystemExitExceptionHandlerEnabled(bool value)
  224. {
  225. if (!PythonQt::self())
  226. {
  227. qWarning() << Q_FUNC_INFO << " failed: PythonQt is not initialized";
  228. return;
  229. }
  230. PythonQt::self()->setSystemExitExceptionHandlerEnabled(value);
  231. }
  232. //-----------------------------------------------------------------------------
  233. QVariant ctkAbstractPythonManager::executeString(const QString& code,
  234. ctkAbstractPythonManager::ExecuteStringMode mode)
  235. {
  236. int start = -1;
  237. switch(mode)
  238. {
  239. case ctkAbstractPythonManager::FileInput: start = Py_file_input; break;
  240. case ctkAbstractPythonManager::SingleInput: start = Py_single_input; break;
  241. case ctkAbstractPythonManager::EvalInput:
  242. default: start = Py_eval_input; break;
  243. }
  244. QVariant ret;
  245. PythonQtObjectPtr main = ctkAbstractPythonManager::mainContext();
  246. if (main)
  247. {
  248. ret = main.evalScript(code, start);
  249. }
  250. return ret;
  251. }
  252. //-----------------------------------------------------------------------------
  253. void ctkAbstractPythonManager::executeFile(const QString& filename)
  254. {
  255. PythonQtObjectPtr main = ctkAbstractPythonManager::mainContext();
  256. if (main)
  257. {
  258. QString path = QFileInfo(filename).absolutePath();
  259. // See http://nedbatchelder.com/blog/200711/rethrowing_exceptions_in_python.html
  260. QStringList code = QStringList()
  261. << "import sys"
  262. << QString("sys.path.insert(0, '%1')").arg(path)
  263. << "_updated_globals = globals()"
  264. << QString("_updated_globals['__file__'] = '%1'").arg(filename)
  265. << "_ctk_executeFile_exc_info = None"
  266. << "try:"
  267. << QString(" execfile('%1', _updated_globals)").arg(filename)
  268. << "except Exception, e:"
  269. << " _ctk_executeFile_exc_info = sys.exc_info()"
  270. << "finally:"
  271. << " del _updated_globals"
  272. << QString(" if sys.path[0] == '%1': sys.path.pop(0)").arg(path)
  273. << " if _ctk_executeFile_exc_info:"
  274. << " raise _ctk_executeFile_exc_info[1], None, _ctk_executeFile_exc_info[2]";
  275. this->executeString(code.join("\n"));
  276. //PythonQt::self()->handleError(); // Clear errorOccured flag
  277. }
  278. }
  279. //-----------------------------------------------------------------------------
  280. void ctkAbstractPythonManager::setInitializationFunction(void (*initFunction)())
  281. {
  282. Q_D(ctkAbstractPythonManager);
  283. d->InitFunction = initFunction;
  284. }
  285. //-----------------------------------------------------------------------------
  286. QStringList ctkAbstractPythonManager::dir_object(PyObject* object,
  287. bool appendParenthesis)
  288. {
  289. QStringList results;
  290. if (!object)
  291. {
  292. return results;
  293. }
  294. PyObject* keys = PyObject_Dir(object);
  295. if (keys)
  296. {
  297. PyObject* key;
  298. PyObject* value;
  299. int nKeys = PyList_Size(keys);
  300. for (int i = 0; i < nKeys; ++i)
  301. {
  302. key = PyList_GetItem(keys, i);
  303. value = PyObject_GetAttr(object, key);
  304. if (!value)
  305. {
  306. continue;
  307. }
  308. QString key_str(PyString_AsString(key));
  309. // Append "()" if the associated object is a function
  310. if (appendParenthesis && PyCallable_Check(value))
  311. {
  312. key_str.append("()");
  313. }
  314. results << key_str;
  315. Py_DECREF(value);
  316. }
  317. Py_DECREF(keys);
  318. }
  319. return results;
  320. }
  321. QStringList ctkAbstractPythonManager::splitByDotOutsideParenthesis(const QString& pythonVariableName)
  322. {
  323. QStringList tmpNames;
  324. int last_pos_dot = pythonVariableName.length();
  325. int numberOfParenthesisClosed = 0;
  326. bool betweenSingleQuotes = false;
  327. bool betweenDoubleQuotes = false;
  328. for (int i = pythonVariableName.length()-1; i >= 0; --i)
  329. {
  330. QChar c = pythonVariableName.at(i);
  331. if (c == '\'' && !betweenDoubleQuotes)
  332. {
  333. betweenSingleQuotes = !betweenSingleQuotes;
  334. }
  335. if (c == '"' && !betweenSingleQuotes)
  336. {
  337. betweenDoubleQuotes = !betweenDoubleQuotes;
  338. }
  339. // note that we must not count parenthesis if they are between quote...
  340. if (!betweenSingleQuotes && !betweenDoubleQuotes)
  341. {
  342. if (c == '(')
  343. {
  344. if (numberOfParenthesisClosed>0)
  345. {
  346. numberOfParenthesisClosed--;
  347. }
  348. }
  349. if (c == ')')
  350. {
  351. numberOfParenthesisClosed++;
  352. }
  353. }
  354. // if we are outside parenthesis and we find a dot, then split
  355. if ((c == '.' && numberOfParenthesisClosed<=0)
  356. || i == 0)
  357. {
  358. if (i == 0) {i--;} // last case where we have to split the begging this time
  359. QString textToSplit = pythonVariableName.mid(i+1,last_pos_dot-(i+1));
  360. if (!textToSplit.isEmpty())
  361. {
  362. tmpNames.push_front(textToSplit);
  363. }
  364. last_pos_dot =i;
  365. }
  366. }
  367. return tmpNames;
  368. }
  369. //----------------------------------------------------------------------------
  370. QStringList ctkAbstractPythonManager::pythonAttributes(const QString& pythonVariableName,
  371. const QString& module,
  372. bool appendParenthesis) const
  373. {
  374. Q_ASSERT(PyThreadState_GET()->interp);
  375. PyObject* dict = PyImport_GetModuleDict();
  376. // Split module by '.' and retrieve the object associated if the last module
  377. QString precedingModule = module;
  378. PyObject* object = ctkAbstractPythonManager::pythonModule(precedingModule);
  379. PyObject* prevObject = 0;
  380. QStringList moduleList = module.split(".", QString::SkipEmptyParts);
  381. foreach(const QString& module, moduleList)
  382. {
  383. object = PyDict_GetItemString(dict, module.toLatin1().data());
  384. if (prevObject) { Py_DECREF(prevObject); }
  385. if (!object)
  386. {
  387. break;
  388. }
  389. Py_INCREF(object);
  390. dict = PyModule_GetDict(object);
  391. prevObject = object;
  392. }
  393. if (!object)
  394. {
  395. return QStringList();
  396. }
  397. // PyObject* object = PyDict_GetItemString(dict, module.toLatin1().data());
  398. // if (!object)
  399. // {
  400. // return QStringList();
  401. // }
  402. // Py_INCREF(object);
  403. PyObject* main_object = object; // save the modue object (usually __main__ or __main__.__builtins__)
  404. QString instantiated_class_name = "_ctkAbstractPythonManager_autocomplete_tmp";
  405. QStringList results; // the list of attributes to return
  406. QString line_code="";
  407. if (!pythonVariableName.isEmpty())
  408. {
  409. // Split the pythonVariableName at every dot
  410. // /!\ // CAREFUL to don't take dot which are between parenthesis
  411. // To avoid the problem: split by dots in a smarter way!
  412. QStringList tmpNames = splitByDotOutsideParenthesis(pythonVariableName);
  413. for (int i = 0; i < tmpNames.size() && object; ++i)
  414. {
  415. // fill the line step by step
  416. // For example: pythonVariableName = d.foo_class().instantiate_bar().
  417. // line_code will be filled first by 'd.' and then, line_code = 'd.foo_class().', etc
  418. line_code.append(tmpNames[i]);
  419. line_code.append(".");
  420. QByteArray tmpName = tmpNames.at(i).toLatin1();
  421. if (tmpName.contains('(') && tmpName.contains(')'))
  422. {
  423. tmpNames[i] = tmpNames[i].left(tmpName.indexOf('('));
  424. tmpName = tmpNames.at(i).toLatin1();
  425. // Attempt to instantiate the associated python class
  426. PyObject* classToInstantiate;
  427. if (PyDict_Check(dict))
  428. classToInstantiate = PyDict_GetItemString(dict, tmpName.data());
  429. else
  430. classToInstantiate = PyObject_GetAttrString(object, tmpName.data());
  431. if (classToInstantiate)
  432. {
  433. QString code = " = ";
  434. code.prepend(instantiated_class_name);
  435. line_code.remove(line_code.size()-1,1); // remove the last char which is a dot
  436. code.append(line_code);
  437. // create a temporary attribute which will instantiate the class
  438. // For example: code = '_ctkAbstractPythonManager_autocomplete_tmp = d.foo_class()'
  439. PyRun_SimpleString(code.toLatin1().data());
  440. line_code.append('.'); // add the point again in case we need to continue to fill line_code
  441. object = PyObject_GetAttrString(main_object,instantiated_class_name.toLatin1().data());
  442. dict = object;
  443. results = ctkAbstractPythonManager::dir_object(object,appendParenthesis);
  444. }
  445. }
  446. else
  447. {
  448. PyObject* prevObj = object;
  449. if (PyDict_Check(object))
  450. {
  451. object = PyDict_GetItemString(object, tmpName.data());
  452. Py_XINCREF(object);
  453. }
  454. else
  455. {
  456. object = PyObject_GetAttrString(object, tmpName.data());
  457. dict = object;
  458. }
  459. Py_DECREF(prevObj);
  460. if (object)
  461. {
  462. results = ctkAbstractPythonManager::dir_object(object,appendParenthesis);
  463. }
  464. }
  465. }
  466. PyErr_Clear();
  467. }
  468. // By default if pythonVariable is empty, return the attributes of the module
  469. else
  470. {
  471. results = ctkAbstractPythonManager::dir_object(object,appendParenthesis);
  472. }
  473. if (object)
  474. {
  475. Py_DECREF(object);
  476. }
  477. // remove the temporary attribute (created to instantiate a class) from the module object
  478. if (PyObject_HasAttrString(main_object,instantiated_class_name.toLatin1().data()))
  479. {
  480. PyObject_DelAttrString(main_object,instantiated_class_name.toLatin1().data());
  481. }
  482. return results;
  483. }
  484. //-----------------------------------------------------------------------------
  485. PyObject* ctkAbstractPythonManager::pythonObject(const QString& variableNameAndFunction)
  486. {
  487. QStringList variableNameAndFunctionList = variableNameAndFunction.split(".");
  488. QString compareFunction = variableNameAndFunctionList.last();
  489. variableNameAndFunctionList.removeLast();
  490. QString pythonVariableName = variableNameAndFunctionList.last();
  491. variableNameAndFunctionList.removeLast();
  492. QString precedingModules = variableNameAndFunctionList.join(".");
  493. Q_ASSERT(PyThreadState_GET()->interp);
  494. PyObject* object = ctkAbstractPythonManager::pythonModule(precedingModules);
  495. if (!object)
  496. {
  497. return NULL;
  498. }
  499. if (!pythonVariableName.isEmpty())
  500. {
  501. QStringList tmpNames = pythonVariableName.split('.');
  502. for (int i = 0; i < tmpNames.size() && object; ++i)
  503. {
  504. QByteArray tmpName = tmpNames.at(i).toLatin1();
  505. PyObject* prevObj = object;
  506. if (PyDict_Check(object))
  507. {
  508. object = PyDict_GetItemString(object, tmpName.data());
  509. Py_XINCREF(object);
  510. }
  511. else
  512. {
  513. object = PyObject_GetAttrString(object, tmpName.data());
  514. }
  515. Py_DECREF(prevObj);
  516. }
  517. }
  518. PyObject* finalPythonObject = NULL;
  519. if (object)
  520. {
  521. PyObject* keys = PyObject_Dir(object);
  522. if (keys)
  523. {
  524. PyObject* key;
  525. PyObject* value;
  526. int nKeys = PyList_Size(keys);
  527. for (int i = 0; i < nKeys; ++i)
  528. {
  529. key = PyList_GetItem(keys, i);
  530. value = PyObject_GetAttr(object, key);
  531. if (!value)
  532. {
  533. continue;
  534. }
  535. QString keyStr = PyString_AsString(key);
  536. if (keyStr.operator ==(compareFunction.toLatin1()))
  537. {
  538. finalPythonObject = value;
  539. break;
  540. }
  541. Py_DECREF(value);
  542. }
  543. Py_DECREF(keys);
  544. }
  545. Py_DECREF(object);
  546. }
  547. return finalPythonObject;
  548. }
  549. //-----------------------------------------------------------------------------
  550. PyObject* ctkAbstractPythonManager::pythonModule(const QString& module)
  551. {
  552. PyObject* dict = PyImport_GetModuleDict();
  553. PyObject* object = 0;
  554. PyObject* prevObject = 0;
  555. QStringList moduleList = module.split(".", QString::KeepEmptyParts);
  556. if (!dict)
  557. {
  558. return object;
  559. }
  560. foreach(const QString& module, moduleList)
  561. {
  562. object = PyDict_GetItemString(dict, module.toLatin1().data());
  563. if (prevObject)
  564. {
  565. Py_DECREF(prevObject);
  566. }
  567. if (!object)
  568. {
  569. break;
  570. }
  571. Py_INCREF(object); // This is required, otherwise python destroys object.
  572. if (PyObject_HasAttrString(object, "__dict__"))
  573. {
  574. dict = PyObject_GetAttrString(object, "__dict__");
  575. }\
  576. prevObject = object;
  577. }
  578. return object;
  579. }
  580. //-----------------------------------------------------------------------------
  581. void ctkAbstractPythonManager::addObjectToPythonMain(const QString& name, QObject* obj)
  582. {
  583. PythonQtObjectPtr main = ctkAbstractPythonManager::mainContext();
  584. if (main && obj)
  585. {
  586. main.addObject(name, obj);
  587. }
  588. }
  589. //-----------------------------------------------------------------------------
  590. void ctkAbstractPythonManager::addWrapperFactory(PythonQtForeignWrapperFactory* factory)
  591. {
  592. if (!PythonQt::self())
  593. {
  594. qWarning() << Q_FUNC_INFO << " failed: PythonQt is not initialized";
  595. return;
  596. }
  597. PythonQt::self()->addWrapperFactory(factory);
  598. }
  599. //-----------------------------------------------------------------------------
  600. QVariant ctkAbstractPythonManager::getVariable(const QString& name)
  601. {
  602. PythonQtObjectPtr main = ctkAbstractPythonManager::mainContext();
  603. if (main)
  604. {
  605. return PythonQt::self()->getVariable(main, name);
  606. }
  607. return QVariant();
  608. }
  609. //-----------------------------------------------------------------------------
  610. void ctkAbstractPythonManager::printStdout(const QString& text)
  611. {
  612. std::cout << qPrintable(text);
  613. }
  614. //-----------------------------------------------------------------------------
  615. void ctkAbstractPythonManager::printStderr(const QString& text)
  616. {
  617. std::cerr << qPrintable(text);
  618. }