Changeset View
Changeset View
Standalone View
Standalone View
plugins/extensions/pykrita/plugin/utilities.cpp
Context not available. | |||||
25 | 25 | | |||
---|---|---|---|---|---|
26 | #include "config.h" | 26 | #include "config.h" | ||
27 | #include "utilities.h" | 27 | #include "utilities.h" | ||
28 | #include "PythonPluginManager.h" | ||||
28 | 29 | | |||
29 | #include <algorithm> | 30 | #include <algorithm> | ||
30 | 31 | | |||
31 | #include <cmath> | 32 | #include <cmath> | ||
32 | #include <Python.h> | 33 | #include <Python.h> | ||
33 | 34 | | |||
34 | | ||||
35 | #include <QDir> | 35 | #include <QDir> | ||
36 | #include <QLibrary> | 36 | #include <QLibrary> | ||
37 | #include <QString> | 37 | #include <QString> | ||
Context not available. | |||||
45 | 45 | | |||
46 | #include <kis_debug.h> | 46 | #include <kis_debug.h> | ||
47 | 47 | | |||
48 | #include "PykritaModule.h" | ||||
49 | | ||||
48 | #define THREADED 1 | 50 | #define THREADED 1 | ||
49 | 51 | | |||
50 | namespace PyKrita | 52 | namespace PyKrita | ||
51 | { | 53 | { | ||
52 | namespace | 54 | static InitResult initStatus = INIT_UNINITIALIZED; | ||
55 | static QScopedPointer<PythonPluginManager> pluginManagerInstance; | ||||
56 | | ||||
57 | InitResult initialize() | ||||
58 | { | ||||
59 | // Already initialized? | ||||
60 | if (initStatus == INIT_OK) return INIT_OK; | ||||
61 | | ||||
62 | dbgScript << "Initializing Python plugin for Python" << PY_MAJOR_VERSION << "," << PY_MINOR_VERSION; | ||||
63 | | ||||
64 | if (!Python::libraryLoad()) { | ||||
65 | return INIT_CANNOT_LOAD_PYTHON_LIBRARY; | ||||
66 | } | ||||
67 | | ||||
68 | // Update PYTHONPATH | ||||
69 | // 0) custom plugin directories (prefer local dir over systems') | ||||
70 | // 1) shipped krita module's dir | ||||
71 | QStringList pluginDirectories = KoResourcePaths::findDirs("pythonscripts"); | ||||
72 | dbgScript << "Plugin Directories: " << pluginDirectories; | ||||
73 | if (!Python::setPath(pluginDirectories)) { | ||||
74 | initStatus = INIT_CANNOT_SET_PYTHON_PATHS; | ||||
75 | return initStatus; | ||||
76 | } | ||||
77 | | ||||
78 | if (0 != PyImport_AppendInittab(Python::PYKRITA_ENGINE, PyInit_pykrita)) { | ||||
79 | initStatus = INIT_CANNOT_LOAD_PYKRITA_MODULE; | ||||
80 | return initStatus; | ||||
81 | } | ||||
82 | | ||||
83 | Python::ensureInitialized(); | ||||
84 | Python py = Python(); | ||||
85 | | ||||
86 | PyRun_SimpleString( | ||||
87 | "import sip\n" | ||||
88 | "sip.setapi('QDate', 2)\n" | ||||
89 | "sip.setapi('QTime', 2)\n" | ||||
90 | "sip.setapi('QDateTime', 2)\n" | ||||
91 | "sip.setapi('QUrl', 2)\n" | ||||
92 | "sip.setapi('QTextStream', 2)\n" | ||||
93 | "sip.setapi('QString', 2)\n" | ||||
94 | "sip.setapi('QVariant', 2)\n" | ||||
95 | ); | ||||
96 | | ||||
97 | // Initialize 'plugins' dict of module 'pykrita' | ||||
98 | PyObject* plugins = PyDict_New(); | ||||
99 | py.itemStringSet("plugins", plugins); | ||||
100 | | ||||
101 | pluginManagerInstance.reset(new PythonPluginManager()); | ||||
102 | | ||||
103 | // Initialize our built-in module. | ||||
104 | auto pykritaModule = PyInit_pykrita(); | ||||
105 | | ||||
106 | if (!pykritaModule) { | ||||
107 | initStatus = INIT_CANNOT_LOAD_PYKRITA_MODULE; | ||||
108 | return initStatus; | ||||
109 | //return i18nc("@info:tooltip ", "No <icode>pykrita</icode> built-in module"); | ||||
110 | } | ||||
111 | | ||||
112 | initStatus = INIT_OK; | ||||
113 | return initStatus; | ||||
114 | } | ||||
115 | | ||||
116 | PythonPluginManager *pluginManager() | ||||
117 | { | ||||
118 | auto pluginManager = pluginManagerInstance.data(); | ||||
119 | KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(pluginManager, nullptr); | ||||
120 | return pluginManager; | ||||
121 | } | ||||
122 | | ||||
123 | void finalize() { | ||||
124 | dbgScript << "Going to destroy the Python engine"; | ||||
125 | | ||||
126 | // Notify Python that engine going to die | ||||
127 | { | ||||
128 | PyKrita::Python py = PyKrita::Python(); | ||||
129 | py.functionCall("_pykritaUnloading"); | ||||
130 | } | ||||
131 | pluginManagerInstance->unloadAllModules(); | ||||
132 | | ||||
133 | PyKrita::Python::maybeFinalize(); | ||||
134 | PyKrita::Python::libraryUnload(); | ||||
135 | | ||||
136 | pluginManagerInstance.reset(); | ||||
137 | initStatus = INIT_UNINITIALIZED; | ||||
138 | } | ||||
139 | | ||||
140 | namespace | ||||
53 | { | 141 | { | ||
54 | #ifndef Q_OS_WIN | 142 | #ifndef Q_OS_WIN | ||
55 | QLibrary* s_pythonLibrary = 0; | 143 | QLibrary* s_pythonLibrary = 0; | ||
Context not available. | |||||
500 | #endif | 588 | #endif | ||
501 | } | 589 | } | ||
502 | 590 | | |||
503 | void Python::updateConfigurationFromDictionary(KConfigBase* const config, PyObject* const dictionary) | | |||
504 | { | | |||
505 | PyObject* groupKey; | | |||
506 | PyObject* groupDictionary; | | |||
507 | Py_ssize_t position = 0; | | |||
508 | while (PyDict_Next(dictionary, &position, &groupKey, &groupDictionary)) { | | |||
509 | if (!isUnicode(groupKey)) { | | |||
510 | traceback(QString("Configuration group name not a string")); | | |||
511 | continue; | | |||
512 | } | | |||
513 | QString groupName = unicode(groupKey); | | |||
514 | if (!PyDict_Check(groupDictionary)) { | | |||
515 | traceback(QString("Configuration group %1 top level key not a dictionary").arg(groupName)); | | |||
516 | continue; | | |||
517 | } | | |||
518 | | ||||
519 | // There is a group per module. | | |||
520 | KConfigGroup group = config->group(groupName); | | |||
521 | PyObject* key; | | |||
522 | PyObject* value; | | |||
523 | Py_ssize_t x = 0; | | |||
524 | while (PyDict_Next(groupDictionary, &x, &key, &value)) { | | |||
525 | if (!isUnicode(key)) { | | |||
526 | traceback(QString("Configuration group %1 itemKey not a string").arg(groupName)); | | |||
527 | continue; | | |||
528 | } | | |||
529 | PyObject* arguments = Py_BuildValue("(Oi)", value, 0); | | |||
530 | PyObject* pickled = functionCall("dumps", "pickle", arguments); | | |||
531 | if (pickled) { | | |||
532 | #if PY_MAJOR_VERSION < 3 | | |||
533 | QString ascii(unicode(pickled)); | | |||
534 | #else | | |||
535 | QString ascii(PyBytes_AsString(pickled)); | | |||
536 | #endif | | |||
537 | group.writeEntry(unicode(key), ascii); | | |||
538 | Py_DECREF(pickled); | | |||
539 | } else { | | |||
540 | errScript << "Cannot write" << groupName << unicode(key) << unicode(PyObject_Str(value)); | | |||
541 | } | | |||
542 | } | | |||
543 | } | | |||
544 | } | | |||
545 | | ||||
546 | void Python::updateDictionaryFromConfiguration(PyObject* const dictionary, const KConfigBase* const config) | | |||
547 | { | | |||
548 | qDebug() << config->groupList(); | | |||
549 | Q_FOREACH(QString groupName, config->groupList()) { | | |||
550 | KConfigGroup group = config->group(groupName); | | |||
551 | PyObject* groupDictionary = PyDict_New(); | | |||
552 | PyDict_SetItemString(dictionary, PQ(groupName), groupDictionary); | | |||
553 | Q_FOREACH(QString key, group.keyList()) { | | |||
554 | QString pickled = group.readEntry(key); | | |||
555 | #if PY_MAJOR_VERSION < 3 | | |||
556 | PyObject* arguments = Py_BuildValue("(s)", PQ(pickled)); | | |||
557 | #else | | |||
558 | PyObject* arguments = Py_BuildValue("(y)", PQ(pickled)); | | |||
559 | #endif | | |||
560 | PyObject* value = functionCall("loads", "pickle", arguments); | | |||
561 | if (value) { | | |||
562 | PyDict_SetItemString(groupDictionary, PQ(key), value); | | |||
563 | Py_DECREF(value); | | |||
564 | } else { | | |||
565 | errScript << "Cannot read" << groupName << key << pickled; | | |||
566 | } | | |||
567 | } | | |||
568 | Py_DECREF(groupDictionary); | | |||
569 | } | | |||
570 | } | | |||
571 | | ||||
572 | bool Python::prependPythonPaths(const QString& path) | 591 | bool Python::prependPythonPaths(const QString& path) | ||
573 | { | 592 | { | ||
574 | PyObject* sys_path = itemString("path", "sys"); | 593 | PyObject* sys_path = itemString("path", "sys"); | ||
Context not available. |