ctkAbstractPythonManager.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  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.commontk.org/LICENSE
  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. ctkAbstractPythonManager::ctkAbstractPythonManager(QObject* _parent) : Superclass(_parent)
  33. {
  34. this->InitFunction = 0;
  35. }
  36. //-----------------------------------------------------------------------------
  37. ctkAbstractPythonManager::~ctkAbstractPythonManager()
  38. {
  39. if (Py_IsInitialized())
  40. {
  41. PyThreadState* state = PyThreadState_Get();
  42. Py_EndInterpreter(state);
  43. }
  44. PythonQt::cleanup();
  45. }
  46. //-----------------------------------------------------------------------------
  47. PythonQtObjectPtr ctkAbstractPythonManager::mainContext()
  48. {
  49. if (!PythonQt::self())
  50. {
  51. this->initPythonQt();
  52. }
  53. if (PythonQt::self())
  54. {
  55. return PythonQt::self()->getMainModule();
  56. }
  57. return PythonQtObjectPtr();
  58. }
  59. //-----------------------------------------------------------------------------
  60. void ctkAbstractPythonManager::initPythonQt()
  61. {
  62. PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
  63. // Python maps SIGINT (control-c) to its own handler. We will remap it
  64. // to the default so that control-c works.
  65. #ifdef SIGINT
  66. signal(SIGINT, SIG_DFL);
  67. #endif
  68. PythonQtObjectPtr _mainContext = PythonQt::self()->getMainModule();
  69. this->connect(PythonQt::self(), SIGNAL(pythonStdOut(const QString&)),
  70. SLOT(printStdout(const QString&)));
  71. this->connect(PythonQt::self(), SIGNAL(pythonStdErr(const QString&)),
  72. SLOT(printStderr(const QString&)));
  73. PythonQt_init_QtBindings();
  74. QStringList initCode;
  75. // Update 'sys.path'
  76. initCode << "import sys";
  77. foreach (QString path, this->pythonPaths())
  78. {
  79. initCode << QString("sys.path.append('%1')").arg(QDir::fromNativeSeparators(path));
  80. }
  81. _mainContext.evalScript(initCode.join("\n"));
  82. this->preInitialization();
  83. if (this->InitFunction)
  84. {
  85. (*this->InitFunction)();
  86. }
  87. emit this->pythonPreInitialized();
  88. this->executeInitializationScripts();
  89. emit this->pythonInitialized();
  90. }
  91. //-----------------------------------------------------------------------------
  92. QStringList ctkAbstractPythonManager::pythonPaths()
  93. {
  94. return QStringList();
  95. }
  96. //-----------------------------------------------------------------------------
  97. void ctkAbstractPythonManager::preInitialization()
  98. {
  99. }
  100. //-----------------------------------------------------------------------------
  101. void ctkAbstractPythonManager::executeInitializationScripts()
  102. {
  103. }
  104. //-----------------------------------------------------------------------------
  105. void ctkAbstractPythonManager::registerPythonQtDecorator(QObject* decorator)
  106. {
  107. PythonQt::self()->addDecorators(decorator);
  108. }
  109. //-----------------------------------------------------------------------------
  110. void ctkAbstractPythonManager::registerClassForPythonQt(const QMetaObject* metaobject)
  111. {
  112. PythonQt::self()->registerClass(metaobject);
  113. }
  114. //-----------------------------------------------------------------------------
  115. void ctkAbstractPythonManager::registerCPPClassForPythonQt(const char* name)
  116. {
  117. PythonQt::self()->registerCPPClass(name);
  118. }
  119. //-----------------------------------------------------------------------------
  120. QVariant ctkAbstractPythonManager::executeString(const QString& code)
  121. {
  122. QVariant ret;
  123. PythonQtObjectPtr main = ctkAbstractPythonManager::mainContext();
  124. if (main)
  125. {
  126. ret = main.evalScript(code, Py_file_input);
  127. }
  128. return ret;
  129. }
  130. //-----------------------------------------------------------------------------
  131. void ctkAbstractPythonManager::executeFile(const QString& filename)
  132. {
  133. PythonQtObjectPtr main = ctkAbstractPythonManager::mainContext();
  134. if (main)
  135. {
  136. main.evalFile(filename);
  137. }
  138. }
  139. //-----------------------------------------------------------------------------
  140. void ctkAbstractPythonManager::setInitializationFunction(void (*initFunction)())
  141. {
  142. this->InitFunction = initFunction;
  143. }
  144. //----------------------------------------------------------------------------
  145. QStringList ctkAbstractPythonManager::pythonAttributes(const QString& pythonVariableName,
  146. const QString& module,
  147. bool appendParenthesis) const
  148. {
  149. Q_ASSERT(PyThreadState_GET()->interp);
  150. PyObject* dict = PyImport_GetModuleDict();
  151. // Split module by '.' and retrieve the object associated if the last module
  152. PyObject* object = 0;
  153. PyObject* prevObject = 0;
  154. QStringList moduleList = module.split(".", QString::SkipEmptyParts);
  155. foreach(const QString& module, moduleList)
  156. {
  157. object = PyDict_GetItemString(dict, module.toAscii().data());
  158. if (prevObject) { Py_DECREF(prevObject); }
  159. if (!object)
  160. {
  161. break;
  162. }
  163. Py_INCREF(object);
  164. dict = PyModule_GetDict(object);
  165. prevObject = object;
  166. }
  167. if (!object)
  168. {
  169. return QStringList();
  170. }
  171. // PyObject* object = PyDict_GetItemString(dict, module.toAscii().data());
  172. // if (!object)
  173. // {
  174. // return QStringList();
  175. // }
  176. // Py_INCREF(object);
  177. if (!pythonVariableName.isEmpty())
  178. {
  179. QStringList tmpNames = pythonVariableName.split('.');
  180. for (int i = 0; i < tmpNames.size() && object; ++i)
  181. {
  182. QByteArray tmpName = tmpNames.at(i).toLatin1();
  183. PyObject* prevObj = object;
  184. if (PyDict_Check(object))
  185. {
  186. object = PyDict_GetItemString(object, tmpName.data());
  187. Py_XINCREF(object);
  188. }
  189. else
  190. {
  191. object = PyObject_GetAttrString(object, tmpName.data());
  192. }
  193. Py_DECREF(prevObj);
  194. }
  195. PyErr_Clear();
  196. }
  197. QStringList results;
  198. if (object)
  199. {
  200. PyObject* keys = PyObject_Dir(object);
  201. if (keys)
  202. {
  203. PyObject* key;
  204. PyObject* value;
  205. int nKeys = PyList_Size(keys);
  206. for (int i = 0; i < nKeys; ++i)
  207. {
  208. key = PyList_GetItem(keys, i);
  209. value = PyObject_GetAttr(object, key);
  210. if (!value)
  211. {
  212. continue;
  213. }
  214. QString key_str(PyString_AsString(key));
  215. // Append "()" if the associated object is a function
  216. if (appendParenthesis && PyCallable_Check(value))
  217. {
  218. key_str.append("()");
  219. }
  220. results << key_str;
  221. Py_DECREF(value);
  222. }
  223. Py_DECREF(keys);
  224. }
  225. Py_DECREF(object);
  226. }
  227. return results;
  228. }
  229. //-----------------------------------------------------------------------------
  230. void ctkAbstractPythonManager::addObjectToPythonMain(const QString& name, QObject* obj)
  231. {
  232. PythonQtObjectPtr main = ctkAbstractPythonManager::mainContext();
  233. if (main && obj)
  234. {
  235. main.addObject(name, obj);
  236. }
  237. }
  238. //-----------------------------------------------------------------------------
  239. QVariant ctkAbstractPythonManager::getVariable(const QString& name)
  240. {
  241. PythonQtObjectPtr main = ctkAbstractPythonManager::mainContext();
  242. if (main)
  243. {
  244. return PythonQt::self()->getVariable(main, name);
  245. }
  246. return QVariant();
  247. }
  248. //-----------------------------------------------------------------------------
  249. void ctkAbstractPythonManager::printStdout(const QString& text)
  250. {
  251. std::cout << qPrintable(text);
  252. }
  253. //-----------------------------------------------------------------------------
  254. void ctkAbstractPythonManager::printStderr(const QString& text)
  255. {
  256. std::cout << qPrintable(text);
  257. }