From 6eed121d31bd5f37a32af6fad798bf17b203ce99 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 19 Sep 2018 16:49:02 +0200 Subject: Fix installation of requirements at first run If our custom site-packages path does not exist, the Python interpreter drops it from its list of directories to look for imports at some point. This results in packages not being found in the custom site-packages directory on the first run. Create the directory explicitly at first startup. Change-Id: Iaff4376890fb68828bbef4c1b05e2d4e7911406a Reviewed-by: Eike Ziller --- plugins/pythonextensions/pythonextensionsplugin.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/pythonextensions/pythonextensionsplugin.cpp b/plugins/pythonextensions/pythonextensionsplugin.cpp index 3547a59..a230924 100644 --- a/plugins/pythonextensions/pythonextensionsplugin.cpp +++ b/plugins/pythonextensions/pythonextensionsplugin.cpp @@ -162,10 +162,13 @@ QString PythonExtensionsPlugin::pythonPackagePath() void PythonExtensionsPlugin::initializePythonBindings() { // Add our custom module directory - if (extensionDir().exists()) { + if (extensionDir().exists()) PyUtil::addToSysPath(extensionDir().path().toStdString()); - PyUtil::addToSysPath(pythonPackagePath().toStdString()); - } + // Add directory for local python packages that are installed as requirements of extensions + // Need to create it first if it doesn't exist, otherwise python will ignore the path + if (!QFile::exists(pythonPackagePath())) + QDir().mkpath(pythonPackagePath()); + PyUtil::addToSysPath(pythonPackagePath().toStdString()); // Initialize the Python context and register global Qt Creator variable if (!PyUtil::bindShibokenModuleObject("PythonExtension", "QtCreator")) { qWarning() << "Python bindings could not be initialized"; -- cgit v1.2.3 From e7851e24ee7718df74a71a850a6f853e3c3e0e7a Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 20 Sep 2018 10:59:07 +0200 Subject: Fix compile issue with min/max macros on Windows When compiling the ProjectExplorer bindings. port.h(44): warning C4003: not enough arguments for function-like macro invocation 'max' Change-Id: If0850b928dbf72676e4ceb1bf5c189bbc5e3feef Reviewed-by: Eike Ziller --- optional/projectexplorer/projectexplorer.pro | 1 + 1 file changed, 1 insertion(+) diff --git a/optional/projectexplorer/projectexplorer.pro b/optional/projectexplorer/projectexplorer.pro index a60ac99..b998d93 100644 --- a/optional/projectexplorer/projectexplorer.pro +++ b/optional/projectexplorer/projectexplorer.pro @@ -18,6 +18,7 @@ QTC_PLUGIN_RECOMMENDS += \ include(../binding/binding.pri) INCLUDEPATH *= $$IDE_SOURCE_TREE/src/plugins/projectexplorer +win32: DEFINES += NOMINMAX # Shiboken binding generation setup -- cgit v1.2.3 From 2ab5bc0a257bd36f8abc39002d531ec6b15ba196 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 20 Sep 2018 11:40:48 +0200 Subject: Fix example extensions for Python 3 Implicit relative imports are no longer allowed and need to be made explicit. Change-Id: Ic4de2d98229149b4d2920057974f895d9600368b Reviewed-by: Eike Ziller --- examples/projects/__init__.py | 2 +- examples/smallmenu/__init__.py | 2 +- examples/transform/__init__.py | 4 ++-- examples/transform/actions.py | 3 ++- python/extensionmanager/__init__.py | 3 ++- python/extensionmanager/list.py | 3 ++- 6 files changed, 10 insertions(+), 7 deletions(-) diff --git a/examples/projects/__init__.py b/examples/projects/__init__.py index c7919fc..7a17d77 100644 --- a/examples/projects/__init__.py +++ b/examples/projects/__init__.py @@ -42,8 +42,8 @@ # project. It also includes a dependency on a plugin # that can be disabled. +from . import view import examples_common -import view from PythonExtension import QtCreator from PySide2.QtCore import QObject, SIGNAL diff --git a/examples/smallmenu/__init__.py b/examples/smallmenu/__init__.py index 5dcfef9..f01a8b0 100644 --- a/examples/smallmenu/__init__.py +++ b/examples/smallmenu/__init__.py @@ -41,7 +41,7 @@ # This example illustrates the use of action # containers to create new menus -from actions import hello, goodbye +from .actions import hello, goodbye import examples_common from PythonExtension import QtCreator diff --git a/examples/transform/__init__.py b/examples/transform/__init__.py index c58f4e6..4934e72 100644 --- a/examples/transform/__init__.py +++ b/examples/transform/__init__.py @@ -42,9 +42,9 @@ # user supplied function that executes on # a set of files specified by the user -import actions +from . import actions +from . import ui import examples_common -import ui from PythonExtension import QtCreator from PySide2.QtCore import QObject, SIGNAL diff --git a/examples/transform/actions.py b/examples/transform/actions.py index de54d94..da65b21 100644 --- a/examples/transform/actions.py +++ b/examples/transform/actions.py @@ -38,8 +38,9 @@ ## ############################################################################# +from . import ui + from PythonExtension import QtCreator -import ui # Apply a function to each file def run(code): diff --git a/python/extensionmanager/__init__.py b/python/extensionmanager/__init__.py index 7932118..8588796 100644 --- a/python/extensionmanager/__init__.py +++ b/python/extensionmanager/__init__.py @@ -40,10 +40,11 @@ # Entry point of the Python extension +from .list import * + from PythonExtension import QtCreator from PySide2.QtCore import * from PySide2.QtWidgets import * -from list import * # Actions def showExtensionList(): diff --git a/python/extensionmanager/list.py b/python/extensionmanager/list.py index 2996be3..d213c35 100644 --- a/python/extensionmanager/list.py +++ b/python/extensionmanager/list.py @@ -40,9 +40,10 @@ # Ui for extension list view +from . import actions + from PySide2 import QtCore, QtWidgets, QtGui from PythonExtension import PluginInstance as instance -import actions class ExtensionList(QtWidgets.QListWidget): def __init__(self): -- cgit v1.2.3 From e82fcad635c490732a23c2c0691991e876864186 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 21 Sep 2018 10:32:36 +0200 Subject: Ignore __pycache__ when looking for extensions Change-Id: I8cc0289e047ced546491639ea5a7b37b5cce0ac1 Reviewed-by: Eike Ziller --- plugins/pythonextensions/pythonextensionsplugin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/pythonextensions/pythonextensionsplugin.cpp b/plugins/pythonextensions/pythonextensionsplugin.cpp index a230924..bdb2687 100644 --- a/plugins/pythonextensions/pythonextensionsplugin.cpp +++ b/plugins/pythonextensions/pythonextensionsplugin.cpp @@ -141,7 +141,8 @@ QStringList PythonExtensionsPlugin::extensionList(const bool loadedOnly) return QStringList(); QStringList extension_list = extension_dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); - extension_list.removeOne("site-packages"); + extension_list.removeAll("site-packages"); + extension_list.removeAll("__pycache__"); return extension_list; } -- cgit v1.2.3 From 4d6487e753b8838f460769ff9758ac6c82a88a35 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 21 Sep 2018 10:36:30 +0200 Subject: Remove unused function Change-Id: Iac2afb005a8c76080862da4c5d75778b48511e60 Reviewed-by: Eike Ziller --- docs/extensions.md | 5 ----- plugins/pythonextensions/pythonextensionsplugin.cpp | 5 ----- plugins/pythonextensions/pythonextensionsplugin.h | 1 - 3 files changed, 11 deletions(-) diff --git a/docs/extensions.md b/docs/extensions.md index 7152ef6..ae5cb5c 100644 --- a/docs/extensions.md +++ b/docs/extensions.md @@ -25,11 +25,6 @@ inst.extensionDir() # where loaded successfully are returned inst.extensionList(loadedOnly = False) -# Mark an extension as loaded -# This should normally not be used and exists mainly -# for use by the extension manager -inst.flagAsLoaded("name_of_extension") - # Returns the path of the custom location to # where missing dependencies should be pip installed inst.pythonPackagePath() diff --git a/plugins/pythonextensions/pythonextensionsplugin.cpp b/plugins/pythonextensions/pythonextensionsplugin.cpp index bdb2687..3136bbc 100644 --- a/plugins/pythonextensions/pythonextensionsplugin.cpp +++ b/plugins/pythonextensions/pythonextensionsplugin.cpp @@ -146,11 +146,6 @@ QStringList PythonExtensionsPlugin::extensionList(const bool loadedOnly) return extension_list; } -void PythonExtensionsPlugin::flagAsLoaded(const QString &extension) -{ - m_loadedExtensions << extension; -} - QString PythonExtensionsPlugin::pythonPackagePath() { if (extensionDir().exists()) { diff --git a/plugins/pythonextensions/pythonextensionsplugin.h b/plugins/pythonextensions/pythonextensionsplugin.h index 29010d4..106ee63 100644 --- a/plugins/pythonextensions/pythonextensionsplugin.h +++ b/plugins/pythonextensions/pythonextensionsplugin.h @@ -51,7 +51,6 @@ public: QDir extensionDir(); QStringList extensionList(const bool loadedOnly = false); - void flagAsLoaded(const QString &extension); QString pythonPackagePath(); private: QStringList m_loadedExtensions; -- cgit v1.2.3 From 9ebe20ca27fbce2ca2934e40dfd1a7a21aaa6658 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 21 Sep 2018 13:15:47 +0200 Subject: Avoid scanning extension directory over and over again And get rid of separate management of a list of loaded extensions. Instead save the name and state of an extension in a separate class. It will probably get more information about the extension, like its location. The extension manager UI now can also iterate over that list once. Change-Id: I4872e55d621837a7d476e69b919f06aeb491ff03 Reviewed-by: Eike Ziller --- docs/extensions.md | 5 +- .../bindingheaders/pythonextensions_extension.h | 0 plugins/pythonextensions/pythonextensions.pro | 1 + .../pythonextensions/pythonextensionsplugin.cpp | 76 ++++++++++++++-------- plugins/pythonextensions/pythonextensionsplugin.h | 13 +++- plugins/pythonextensions/pyutil.h | 2 +- plugins/pythonextensions/typesystem_qtcreator.xml | 1 + python/extensionmanager/actions.py | 4 +- python/extensionmanager/list.py | 6 +- 9 files changed, 69 insertions(+), 39 deletions(-) create mode 100644 plugins/pythonextensions/bindingheaders/pythonextensions_extension.h diff --git a/docs/extensions.md b/docs/extensions.md index ae5cb5c..709acff 100644 --- a/docs/extensions.md +++ b/docs/extensions.md @@ -21,9 +21,8 @@ from PythonExtension import PluginInstance as inst inst.extensionDir() # Returns a list with the names of all Python extensions -# If loaded only is supplied as True, only extensions that -# where loaded successfully are returned -inst.extensionList(loadedOnly = False) +# Each extension has properties 'name' and 'loaded' +inst.extensionList() # Returns the path of the custom location to # where missing dependencies should be pip installed diff --git a/plugins/pythonextensions/bindingheaders/pythonextensions_extension.h b/plugins/pythonextensions/bindingheaders/pythonextensions_extension.h new file mode 100644 index 0000000..e69de29 diff --git a/plugins/pythonextensions/pythonextensions.pro b/plugins/pythonextensions/pythonextensions.pro index c8fe73d..e28b860 100644 --- a/plugins/pythonextensions/pythonextensions.pro +++ b/plugins/pythonextensions/pythonextensions.pro @@ -36,6 +36,7 @@ WRAPPED_CLASSES = \ bindingheaders/pythonextensions.h \ bindingheaders/pythonextensions_internal.h \ bindingheaders/pythonextensions_internal_pythonextensionsplugin.h \ + bindingheaders/pythonextensions_extension.h \ bindingheaders/core.h \ bindingheaders/core_actioncontainer.h \ bindingheaders/core_actionmanager.h \ diff --git a/plugins/pythonextensions/pythonextensionsplugin.cpp b/plugins/pythonextensions/pythonextensionsplugin.cpp index 3136bbc..b3730b4 100644 --- a/plugins/pythonextensions/pythonextensionsplugin.cpp +++ b/plugins/pythonextensions/pythonextensionsplugin.cpp @@ -39,6 +39,8 @@ #include #include +#include + #include #include #include @@ -131,19 +133,32 @@ QDir PythonExtensionsPlugin::extensionDir() return extension_dir; } -QStringList PythonExtensionsPlugin::extensionList(const bool loadedOnly) +static QVector getExtensionList(const QDir &directory) { - if (loadedOnly) - return m_loadedExtensions; + if (!directory.exists()) + return {}; + + QStringList entries = directory.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); + entries.removeAll("site-packages"); + entries.removeAll("__pycache__"); + return Utils::transform(entries, [](const QString &entry) { + return Extension({entry, false}); + }); +} - QDir extension_dir = extensionDir(); - if (!extension_dir.exists()) - return QStringList(); +QVector PythonExtensionsPlugin::extensionList() +{ + return extensionListRef(); +} - QStringList extension_list = extension_dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); - extension_list.removeAll("site-packages"); - extension_list.removeAll("__pycache__"); - return extension_list; +QVector &PythonExtensionsPlugin::extensionListRef() +{ + static bool initialized = false; + if (!initialized) { + m_extensions = getExtensionList(extensionDir()); + initialized = true; + } + return m_extensions; } QString PythonExtensionsPlugin::pythonPackagePath() @@ -207,16 +222,18 @@ void PythonExtensionsPlugin::installRequirements() if (!extension_dir.exists()) return; - QStringList extension_list = extensionList(); - for (const QString &extension : extension_list) { - QString extension_requirements(extension_dir.absolutePath() + "/" + extension + "/requirements.txt"); - if (QFileInfo::exists(extension_requirements) && !QFileInfo::exists(extension_requirements + ".installed")) { - if (!PyUtil::pipInstallRequirements( - extension_requirements.toStdString(), - pythonPackagePath().toStdString() - )) { - qWarning() << "Failed to install requirements for extension" << extension; - Core::MessageManager::write(Constants::MESSAGE_MANAGER_PREFIX + tr("Failed to install requirements for extension ") + extension); + QVector extension_list = extensionListRef(); + for (const Extension &extension : extension_list) { + QString extension_requirements(extension_dir.absolutePath() + "/" + extension.name + + "/requirements.txt"); + if (QFileInfo::exists(extension_requirements) + && !QFileInfo::exists(extension_requirements + ".installed")) { + if (!PyUtil::pipInstallRequirements(extension_requirements.toStdString(), + pythonPackagePath().toStdString())) { + qWarning() << "Failed to install requirements for extension" << extension.name; + Core::MessageManager::write(Constants::MESSAGE_MANAGER_PREFIX + + tr("Failed to install requirements for extension ") + + extension.name); } } } @@ -234,22 +251,25 @@ void PythonExtensionsPlugin::initializePythonExtensions() qDebug() << "Found Python extension directory at location" << extension_dir.absolutePath(); - QStringList extension_list = extensionList(); + QVector &extension_list = extensionListRef(); qDebug() << "Number of Python extensions found:" << extension_list.size(); + int loadedCount = 0; // Run the extension initialization code - for (const QString &extension : extension_list) { - qDebug() << "Trying to initialize extension" << extension; - if (!PyUtil::runScript("import " + extension.toStdString())) { - qWarning() << "Failed to initialize extension" << extension; - Core::MessageManager::write(Constants::MESSAGE_MANAGER_PREFIX + tr("Failed to initialize extension ") + extension); + for (Extension &extension : extension_list) { + qDebug() << "Trying to initialize extension" << extension.name; + if (PyUtil::runScript("import " + extension.name.toStdString())) { + extension.loaded = true; + ++loadedCount; } else { - m_loadedExtensions << extension; + qWarning() << "Failed to initialize extension" << extension.name; + Core::MessageManager::write(Constants::MESSAGE_MANAGER_PREFIX + + tr("Failed to initialize extension ") + extension.name); } } - qDebug() << "Number of Python extensions loaded:" << m_loadedExtensions.size(); + qDebug() << "Number of Python extensions loaded:" << loadedCount; } } // namespace Internal diff --git a/plugins/pythonextensions/pythonextensionsplugin.h b/plugins/pythonextensions/pythonextensionsplugin.h index 106ee63..1a4bce3 100644 --- a/plugins/pythonextensions/pythonextensionsplugin.h +++ b/plugins/pythonextensions/pythonextensionsplugin.h @@ -33,6 +33,13 @@ #include namespace PythonExtensions { + +class Extension { +public: + QString name; + bool loaded; +}; + namespace Internal { class PythonExtensionsPlugin : public ExtensionSystem::IPlugin @@ -50,14 +57,16 @@ public: ShutdownFlag aboutToShutdown() final; QDir extensionDir(); - QStringList extensionList(const bool loadedOnly = false); + QVector extensionList(); QString pythonPackagePath(); + private: - QStringList m_loadedExtensions; void initializePythonBindings(); void initializeOptionalBindings(); void installRequirements(); void initializePythonExtensions(); + QVector &extensionListRef(); + QVector m_extensions; }; // Util functions diff --git a/plugins/pythonextensions/pyutil.h b/plugins/pythonextensions/pyutil.h index 62a1622..23fdb37 100644 --- a/plugins/pythonextensions/pyutil.h +++ b/plugins/pythonextensions/pyutil.h @@ -37,7 +37,7 @@ namespace PyUtil { // Note: If modifying the bindings, check these types still align enum QtCreatorTypes { - PythonExtensionsPluginType = 33, // SBK_PYTHONEXTENSIONS_INTERNAL_PYTHONEXTENSIONSPLUGIN_IDX + PythonExtensionsPluginType = 34, // SBK_PYTHONEXTENSIONS_INTERNAL_PYTHONEXTENSIONSPLUGIN_IDX }; enum State diff --git a/plugins/pythonextensions/typesystem_qtcreator.xml b/plugins/pythonextensions/typesystem_qtcreator.xml index 736fe44..49dd794 100644 --- a/plugins/pythonextensions/typesystem_qtcreator.xml +++ b/plugins/pythonextensions/typesystem_qtcreator.xml @@ -47,6 +47,7 @@ + diff --git a/python/extensionmanager/actions.py b/python/extensionmanager/actions.py index 29d64cc..7f05e77 100644 --- a/python/extensionmanager/actions.py +++ b/python/extensionmanager/actions.py @@ -60,8 +60,8 @@ def install(path): # Make sure the extension manager does not overwrite # extensions that are already installed for ext in instance.extensionList(): - if extName == ext: - return "The extension \"{}\" is already installed. Uninstall it before trying again.".format(ext) + if extName == ext.name: + return "The extension \"{}\" is already installed. Uninstall it before trying again.".format(extName) extZip.extractall(instance.extensionDir().absolutePath()) extZip.close() except Exception as e: diff --git a/python/extensionmanager/list.py b/python/extensionmanager/list.py index d213c35..32002b1 100644 --- a/python/extensionmanager/list.py +++ b/python/extensionmanager/list.py @@ -58,11 +58,11 @@ class ExtensionList(QtWidgets.QListWidget): i = 0 for ext in instance.extensionList(): item = QtWidgets.QListWidgetItem(self) - if not ext in instance.extensionList(True): - item.setText(ext + " [did not load]") + if not ext.loaded: + item.setText(ext.name + " [did not load]") item.setIcon(QtGui.QIcon.fromTheme("dialog-error")) else: - item.setText(ext) + item.setText(ext.name) item.setIcon(QtGui.QIcon.fromTheme("applications-development")) if i % 2 == 1: item.setBackground(QtGui.QBrush(QtGui.QColor.fromRgb(240, 240, 240))) -- cgit v1.2.3 From ee72345d6c4f7a576f25f3d04a24e4e49585397b Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 21 Sep 2018 16:00:00 +0200 Subject: Fix compilation of ProjectExplorer bindings on Windows Enum classes that are returned from protected functions seem to create issues, so remove that for now. Change-Id: If7d62c0349ba24d93de8f82bf66d5f0c0681e021 Reviewed-by: Eike Ziller --- optional/projectexplorer/typesystem_projectexplorer.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/optional/projectexplorer/typesystem_projectexplorer.xml b/optional/projectexplorer/typesystem_projectexplorer.xml index b663619..0e0eeff 100644 --- a/optional/projectexplorer/typesystem_projectexplorer.xml +++ b/optional/projectexplorer/typesystem_projectexplorer.xml @@ -60,7 +60,9 @@ - + + + -- cgit v1.2.3 From 3c4cafdf834c9b683501efca72dbbe1093cf6f9a Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 24 Sep 2018 16:21:58 +0200 Subject: Allow single file extensions Change-Id: I0b9e04e9ba2d73f43fbf08515366bfa303f2557b Reviewed-by: Eike Ziller --- README.md | 14 +++-- examples/examples.pro | 4 +- examples/macroexpander.py | 66 ++++++++++++++++++++++ examples/macroexpander/__init__.py | 66 ---------------------- .../pythonextensions/pythonextensionsplugin.cpp | 13 ++++- 5 files changed, 86 insertions(+), 77 deletions(-) create mode 100644 examples/macroexpander.py delete mode 100644 examples/macroexpander/__init__.py diff --git a/README.md b/README.md index 58f2ee5..709dbc8 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ # Python Extensions for Qt Creator This plugin for Qt Creator makes it possible to extend the Qt Creator by -writing Python extensions. These extensions are simply Python packages, -so they are directories containing a `__init__.py` and any other Python -files necessary. They can be shared as zip archives, installed and managed +writing Python extensions. These extensions are simply Python modules or +packages, so they are either single Python files or directories containing a +`__init__.py` and any other Python files necessary. +They can be shared as zip archives, installed and managed through the included extension manager (which is a Python extension itself) and thus allow the Qt Creator to be easily extended with custom functionality. @@ -129,9 +130,10 @@ The following process allows the plugin to work: 2. When Qt Creator is executed, the C++ plugin searches the standard Qt Creator plugin directories for a directory named `python`, the first directory found is the Python extension directory. - Each python package in this directory represents it's own Python extension. - Each package is loaded with `import`, which executes the initialization - code in its `__init__.py`. + Each python module and package in this directory represents it's own Python + extension. Each extension is loaded with `import`, which executes the + module's initialization code (for extensions in the form of Python packages + that is the code in `__init__.py`). 3. Now all Python extensions have registered their actions / menus / etc., which can be triggered from the Qt Creator interface. diff --git a/examples/examples.pro b/examples/examples.pro index 57b1764..34b5843 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -7,7 +7,6 @@ include(../plugins/pythonextensions/qtcreator.pri) include($$IDE_SOURCE_TREE/qtcreator.pri) inst_examples.files = \ - macroexpander \ projects \ requirerequests \ smallmenu \ @@ -18,7 +17,8 @@ inst_examples.CONFIG += no_default_install directory INSTALLS += inst_examples inst_examplefiles.files = \ - examples_common.py + examples_common.py \ + macroexpander.py inst_examplefiles.path = $$IDE_PLUGIN_PATH/python inst_examplefiles.CONFIG += no_default_install diff --git a/examples/macroexpander.py b/examples/macroexpander.py new file mode 100644 index 0000000..20e10a3 --- /dev/null +++ b/examples/macroexpander.py @@ -0,0 +1,66 @@ +############################################################################# +## +## Copyright (C) 2018 The Qt Company Ltd. +## Contact: http://www.qt.io/licensing/ +## +## This file is part of the Python Extensions Plugin for Qt Creator. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + +# This example demonstrates how to use the macro expander +# API to register a macro that can evaluate Python expressions + +import examples_common + +from PySide2.QtCore import QObject, SIGNAL +from PySide2.QtWidgets import QInputDialog, QMessageBox, QAction +from PythonExtension import QtCreator + +# Register our macro (it can be used as %{Python:exp}) +QtCreator.Utils.MacroExpander().registerPrefix(b"Python", "Evaluate Python expressions.", lambda x: eval(x)) + +# Add a small menu item, that let's us test the macro +def act(): + text = QInputDialog.getMultiLineText(QtCreator.Core.ICore.dialogParent(), + "Input Text", "Input your text, including some macros", + "3 + 3 = %{Python:3+3}") + text = QtCreator.Utils.MacroExpander().expand(text[0]) + QMessageBox.information(QtCreator.Core.ICore.dialogParent(), "Result", text) + +# Add this to the "Tools" menu +action = QAction("Test Macro Expander...") +command = QtCreator.Core.ActionManager.registerAction(action, 'PythonExtensions.Examples.MacroExpander') +QObject.connect(action, SIGNAL('triggered()'), act) + +examples_common.addExampleItem(command) diff --git a/examples/macroexpander/__init__.py b/examples/macroexpander/__init__.py deleted file mode 100644 index 20e10a3..0000000 --- a/examples/macroexpander/__init__.py +++ /dev/null @@ -1,66 +0,0 @@ -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: http://www.qt.io/licensing/ -## -## This file is part of the Python Extensions Plugin for Qt Creator. -## -## $QT_BEGIN_LICENSE:BSD$ -## You may use this file under the terms of the BSD license as follows: -## -## "Redistribution and use in source and binary forms, with or without -## modification, are permitted provided that the following conditions are -## met: -## * Redistributions of source code must retain the above copyright -## notice, this list of conditions and the following disclaimer. -## * Redistributions in binary form must reproduce the above copyright -## notice, this list of conditions and the following disclaimer in -## the documentation and/or other materials provided with the -## distribution. -## * Neither the name of The Qt Company Ltd nor the names of its -## contributors may be used to endorse or promote products derived -## from this software without specific prior written permission. -## -## -## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -## -## $QT_END_LICENSE$ -## -############################################################################# - -# This example demonstrates how to use the macro expander -# API to register a macro that can evaluate Python expressions - -import examples_common - -from PySide2.QtCore import QObject, SIGNAL -from PySide2.QtWidgets import QInputDialog, QMessageBox, QAction -from PythonExtension import QtCreator - -# Register our macro (it can be used as %{Python:exp}) -QtCreator.Utils.MacroExpander().registerPrefix(b"Python", "Evaluate Python expressions.", lambda x: eval(x)) - -# Add a small menu item, that let's us test the macro -def act(): - text = QInputDialog.getMultiLineText(QtCreator.Core.ICore.dialogParent(), - "Input Text", "Input your text, including some macros", - "3 + 3 = %{Python:3+3}") - text = QtCreator.Utils.MacroExpander().expand(text[0]) - QMessageBox.information(QtCreator.Core.ICore.dialogParent(), "Result", text) - -# Add this to the "Tools" menu -action = QAction("Test Macro Expander...") -command = QtCreator.Core.ActionManager.registerAction(action, 'PythonExtensions.Examples.MacroExpander') -QObject.connect(action, SIGNAL('triggered()'), act) - -examples_common.addExampleItem(command) diff --git a/plugins/pythonextensions/pythonextensionsplugin.cpp b/plugins/pythonextensions/pythonextensionsplugin.cpp index b3730b4..893819c 100644 --- a/plugins/pythonextensions/pythonextensionsplugin.cpp +++ b/plugins/pythonextensions/pythonextensionsplugin.cpp @@ -141,9 +141,16 @@ static QVector getExtensionList(const QDir &directory) QStringList entries = directory.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); entries.removeAll("site-packages"); entries.removeAll("__pycache__"); - return Utils::transform(entries, [](const QString &entry) { - return Extension({entry, false}); - }); + const QVector packageExtensions + = Utils::transform(entries, [](const QString &entry) { + return Extension({entry, false}); + }); + const QStringList fileEntries = directory.entryList({"*.py"}, QDir::Files); + const QVector fileExtensions + = Utils::transform(fileEntries, [](const QString &entry) { + return Extension({entry.left(entry.size() - 3), false}); + }); + return packageExtensions + fileExtensions; } QVector PythonExtensionsPlugin::extensionList() -- cgit v1.2.3 From 3412dc563119221bd730c1487937519df0761792 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 27 Sep 2018 15:00:08 +0200 Subject: Clean up import hierarchy PythonExtension.QtCreator.* -> QtCreator.* PythonExtension.PluginInstance -> QtCreator.PythonExtensions Also enables imports of the form "from QtCreator import Core" it is no longer necessary to write QtCreator.Core.... Change-Id: Ib9b433868dcc3fc7d1d534c6023bae7bf6d05fec Reviewed-by: Eike Ziller --- docs/extensions.md | 29 +++++++++++----------- examples/examples_common.py | 8 +++--- examples/macroexpander.py | 13 +++++----- examples/projects/__init__.py | 6 ++--- examples/projects/view.py | 6 ++--- examples/requirerequests/__init__.py | 6 ++--- examples/smallmenu/__init__.py | 8 +++--- examples/transform/__init__.py | 4 +-- examples/transform/actions.py | 4 +-- examples/transform/ui.py | 4 +-- optional/projectexplorer/binding.cpp | 2 +- optional/texteditor/binding.cpp | 2 +- plugins/pythonextensions/pythonextensions.pro | 2 +- .../pythonextensions/pythonextensionsplugin.cpp | 4 +-- plugins/pythonextensions/pyutil.cpp | 11 ++++---- plugins/pythonextensions/pyutil.h | 2 +- plugins/pythonextensions/typesystem_qtcreator.xml | 2 +- python/extensionmanager/__init__.py | 10 ++++---- python/extensionmanager/actions.py | 8 +++--- python/extensionmanager/list.py | 10 ++++---- 20 files changed, 72 insertions(+), 69 deletions(-) diff --git a/docs/extensions.md b/docs/extensions.md index 709acff..57a6f15 100644 --- a/docs/extensions.md +++ b/docs/extensions.md @@ -6,27 +6,28 @@ for Qt Creator. ## Importing Qt Creator specific modules Currently, the bindings are available from Python under the following names: ```Python -from PythonExtension import QtCreator # Imports the generated module for the typesystem -from PythonExtension import PluginInstance # Imports the plugin instance +from QtCreator import Utils # Imports Qt Creator's Utils helper library +from QtCreator import Core # Imports Qt Creator's Core plugin API +from QtCreator import PythonExtensions # Imports Python extension specific helper functions ``` -## `PythonExtension.PluginInstance` +## `QtCreator.PythonExtensions` This is the Python binding for the extension manager that works on the C++ side. It provides the -following functions, that can (and should) be used from Python: +following functions, that can be used from Python: ```Python -from PythonExtension import PluginInstance as inst +from QtCreator import PythonExtensions # Returns a PySide QDir which points to the extension directory -inst.extensionDir() +PythonExtensions.extensionDir() # Returns a list with the names of all Python extensions # Each extension has properties 'name' and 'loaded' -inst.extensionList() +PythonExtensions.extensionList() # Returns the path of the custom location to # where missing dependencies should be pip installed -inst.pythonPackagePath() +PythonExtensions.pythonPackagePath() ``` @@ -42,7 +43,7 @@ add a new action container, that holds a sub-menu. The following code snippet illustrates how to add a new menu. ```Python -from PythonExtension import QtCreator +from QtCreator import Core def hello(): print("Hello World.") @@ -50,24 +51,24 @@ def hello(): # By convention, the menuId starts with "Python" menuId = "Python.SmallMenu.Menu" -menu = QtCreator.Core.ActionManager.createMenu(menuId) +menu = Core.ActionManager.createMenu(menuId) menu.menu().setTitle("My menu") menu.menu().addAction("My action", hello) -# Add our new menu to the "Tools" menu in QtCreator -QtCreator.Core.ActionManager.actionContainer("QtCreator.Menu.Tools").addMenu(menu) +# Add our new menu to the "Tools" menu in Qt Creator +Core.ActionManager.actionContainer("QtCreator.Menu.Tools").addMenu(menu) ``` ### Adding a new action directly The following code snippet illustrates how to add a new action to an existing action container. ```Python -from PythonExtension import QtCreator +from QtCreator import Core def hello(): print("Hello World.") # Add a new action to the "Tools" menu -menu = QtCreator.Core.ActionManager.actionContainer("QtCreator.Menu.Tools") +menu = Core.ActionManager.actionContainer("QtCreator.Menu.Tools") menu.menu().addAction("My action", hello) ``` diff --git a/examples/examples_common.py b/examples/examples_common.py index db7f669..0bb93d4 100644 --- a/examples/examples_common.py +++ b/examples/examples_common.py @@ -38,15 +38,15 @@ ## ############################################################################# -from PythonExtension import QtCreator +from QtCreator import Core def ensureExamplesMenu(): menuId = 'PythonExtensions.Examples' - menu = QtCreator.Core.ActionManager.actionContainer(menuId) + menu = Core.ActionManager.actionContainer(menuId) if not menu: - menu = QtCreator.Core.ActionManager.createMenu(menuId) + menu = Core.ActionManager.createMenu(menuId) menu.menu().setTitle("Python Extensions Examples") - toolsMenu = QtCreator.Core.ActionManager.actionContainer("QtCreator.Menu.Tools") + toolsMenu = Core.ActionManager.actionContainer("QtCreator.Menu.Tools") toolsMenu.addMenu(menu) return menu diff --git a/examples/macroexpander.py b/examples/macroexpander.py index 20e10a3..17c30cc 100644 --- a/examples/macroexpander.py +++ b/examples/macroexpander.py @@ -45,22 +45,23 @@ import examples_common from PySide2.QtCore import QObject, SIGNAL from PySide2.QtWidgets import QInputDialog, QMessageBox, QAction -from PythonExtension import QtCreator +from QtCreator import Core +from QtCreator import Utils # Register our macro (it can be used as %{Python:exp}) -QtCreator.Utils.MacroExpander().registerPrefix(b"Python", "Evaluate Python expressions.", lambda x: eval(x)) +Utils.MacroExpander().registerPrefix(b"Python", "Evaluate Python expressions.", lambda x: eval(x)) # Add a small menu item, that let's us test the macro def act(): - text = QInputDialog.getMultiLineText(QtCreator.Core.ICore.dialogParent(), + text = QInputDialog.getMultiLineText(Core.ICore.dialogParent(), "Input Text", "Input your text, including some macros", "3 + 3 = %{Python:3+3}") - text = QtCreator.Utils.MacroExpander().expand(text[0]) - QMessageBox.information(QtCreator.Core.ICore.dialogParent(), "Result", text) + text = Utils.MacroExpander().expand(text[0]) + QMessageBox.information(Core.ICore.dialogParent(), "Result", text) # Add this to the "Tools" menu action = QAction("Test Macro Expander...") -command = QtCreator.Core.ActionManager.registerAction(action, 'PythonExtensions.Examples.MacroExpander') +command = Core.ActionManager.registerAction(action, 'PythonExtensions.Examples.MacroExpander') QObject.connect(action, SIGNAL('triggered()'), act) examples_common.addExampleItem(command) diff --git a/examples/projects/__init__.py b/examples/projects/__init__.py index 7a17d77..a618e5b 100644 --- a/examples/projects/__init__.py +++ b/examples/projects/__init__.py @@ -45,13 +45,13 @@ from . import view import examples_common -from PythonExtension import QtCreator +from QtCreator import Core from PySide2.QtCore import QObject, SIGNAL from PySide2.QtWidgets import QAction # When importing optional bindings, we can warn the user in case things go south try: - from PythonExtension.QtCreator import ProjectExplorer + from QtCreator import ProjectExplorer except ImportError: view.error("The extension \"projects\" could not be loaded, since it depends on a disabled plugin.") raise Exception("Dependencies missing") @@ -65,7 +65,7 @@ def showProjectPath(): view.error("Please open a project") action = QAction("Show Project Directory") -command = QtCreator.Core.ActionManager.registerAction(action, 'PythonExtensions.Examples.ShowProjectDirectory') +command = Core.ActionManager.registerAction(action, 'PythonExtensions.Examples.ShowProjectDirectory') QObject.connect(action, SIGNAL('triggered()'), showProjectPath) examples_common.addExampleItem(command) diff --git a/examples/projects/view.py b/examples/projects/view.py index 31dbbe6..df1eeb0 100644 --- a/examples/projects/view.py +++ b/examples/projects/view.py @@ -41,10 +41,10 @@ # This contains all the display logic from PySide2 import QtWidgets -from PythonExtension import QtCreator +from QtCreator import Core def error(text, title="Error"): - QtWidgets.QMessageBox.critical(QtCreator.Core.ICore.instance().dialogParent(), title, text) + QtWidgets.QMessageBox.critical(Core.ICore.instance().dialogParent(), title, text) def show(text, title="Result"): - QtWidgets.QMessageBox.information(QtCreator.Core.ICore.instance().dialogParent(), title, text) + QtWidgets.QMessageBox.information(Core.ICore.instance().dialogParent(), title, text) diff --git a/examples/requirerequests/__init__.py b/examples/requirerequests/__init__.py index acbf9e6..3fb14c7 100644 --- a/examples/requirerequests/__init__.py +++ b/examples/requirerequests/__init__.py @@ -44,7 +44,7 @@ import examples_common -from PythonExtension import QtCreator +from QtCreator import Core from PySide2.QtCore import QObject, SIGNAL from PySide2.QtWidgets import QAction, QMessageBox @@ -52,14 +52,14 @@ import requests def load(url): r = requests.get(url) - box = QMessageBox(QtCreator.Core.ICore.dialogParent()) + box = QMessageBox(Core.ICore.dialogParent()) box.setWindowTitle("Request results") box.setText("The request status is {}".format(r.status_code)) box.setDetailedText(r.text) box.exec_() action = QAction("Load from the web...") -command = QtCreator.Core.ActionManager.registerAction(action, 'PythonExtensions.Examples.LoadFromWeb') +command = Core.ActionManager.registerAction(action, 'PythonExtensions.Examples.LoadFromWeb') QObject.connect(action, SIGNAL('triggered()'), lambda: load("https://www.qt.io/")) examples_common.addExampleItem(command) diff --git a/examples/smallmenu/__init__.py b/examples/smallmenu/__init__.py index f01a8b0..f26b637 100644 --- a/examples/smallmenu/__init__.py +++ b/examples/smallmenu/__init__.py @@ -44,24 +44,24 @@ from .actions import hello, goodbye import examples_common -from PythonExtension import QtCreator +from QtCreator import Core from PySide2.QtCore import QObject, SIGNAL from PySide2.QtWidgets import QAction # Create submenu and add it to examples menu menuId = "PythonExtensions.Examples.SmallMenu" -menu = QtCreator.Core.ActionManager.createMenu(menuId) +menu = Core.ActionManager.createMenu(menuId) menu.menu().setTitle("Small Menu") examplesMenu = examples_common.ensureExamplesMenu() examplesMenu.addMenu(menu) # Add actions to our new menu helloAction = QAction("Say Hello") -command = QtCreator.Core.ActionManager.registerAction(helloAction, 'PythonExtensions.Examples.SayHello') +command = Core.ActionManager.registerAction(helloAction, 'PythonExtensions.Examples.SayHello') QObject.connect(helloAction, SIGNAL('triggered()'), hello) menu.addAction(command) goodbyeAction = QAction("Say Goodbye") -command = QtCreator.Core.ActionManager.registerAction(goodbyeAction, 'PythonExtensions.Examples.SayGoodbye') +command = Core.ActionManager.registerAction(goodbyeAction, 'PythonExtensions.Examples.SayGoodbye') QObject.connect(goodbyeAction, SIGNAL('triggered()'), goodbye) menu.addAction(command) diff --git a/examples/transform/__init__.py b/examples/transform/__init__.py index 4934e72..f2647dc 100644 --- a/examples/transform/__init__.py +++ b/examples/transform/__init__.py @@ -46,7 +46,7 @@ from . import actions from . import ui import examples_common -from PythonExtension import QtCreator +from QtCreator import Core from PySide2.QtCore import QObject, SIGNAL from PySide2.QtWidgets import QAction @@ -56,7 +56,7 @@ def transform(): actions.run(code[0]) action = QAction("Transform files...") -command = QtCreator.Core.ActionManager.registerAction(action, 'PythonExtensions.Examples.TransformFiles') +command = Core.ActionManager.registerAction(action, 'PythonExtensions.Examples.TransformFiles') QObject.connect(action, SIGNAL('triggered()'), transform) examples_common.addExampleItem(command) diff --git a/examples/transform/actions.py b/examples/transform/actions.py index da65b21..e459ab2 100644 --- a/examples/transform/actions.py +++ b/examples/transform/actions.py @@ -40,12 +40,12 @@ from . import ui -from PythonExtension import QtCreator +from QtCreator import Core # Apply a function to each file def run(code): try: - files = QtCreator.Core.DocumentManager.getOpenFileNames("") + files = Core.DocumentManager.getOpenFileNames("") if len(files) == 0: ui.error("No files were selected.") return diff --git a/examples/transform/ui.py b/examples/transform/ui.py index 21892ef..cc5b7f1 100644 --- a/examples/transform/ui.py +++ b/examples/transform/ui.py @@ -38,7 +38,7 @@ ## ############################################################################# -from PythonExtension import QtCreator +from QtCreator import Core from PySide2 import QtWidgets template = """# Parameters: @@ -53,7 +53,7 @@ filebody def getCode(): return QtWidgets.QInputDialog.getMultiLineText( - QtCreator.Core.ICore.dialogParent(), + Core.ICore.dialogParent(), "Input transformation expression", "Transform expression:", template diff --git a/optional/projectexplorer/binding.cpp b/optional/projectexplorer/binding.cpp index 325027b..ae1bbc7 100644 --- a/optional/projectexplorer/binding.cpp +++ b/optional/projectexplorer/binding.cpp @@ -59,7 +59,7 @@ void bind() // Bind module into interpreter bool pythonError = PyErr_Occurred() != nullptr; if (pythonInitialized && !pythonError) { - PyUtil::bindSubPyObject("PythonExtension.QtCreator", "ProjectExplorer", (void *)SbkQtCreatorBindingProjectExplorerModuleObject); + PyUtil::bindSubPyObject("QtCreator", "ProjectExplorer", (void *)SbkQtCreatorBindingProjectExplorerModuleObject); } else { if (pythonError) PyErr_Print(); diff --git a/optional/texteditor/binding.cpp b/optional/texteditor/binding.cpp index d2d5b83..6b9007f 100644 --- a/optional/texteditor/binding.cpp +++ b/optional/texteditor/binding.cpp @@ -59,7 +59,7 @@ void bind() // Bind module into interpreter bool pythonError = PyErr_Occurred() != nullptr; if (pythonInitialized && !pythonError) { - PyUtil::bindSubPyObject("PythonExtension.QtCreator", "TextEditor", (void *)SbkQtCreatorBindingTextEditorModuleObject); + PyUtil::bindSubPyObject("QtCreator", "TextEditor", (void *)SbkQtCreatorBindingTextEditorModuleObject); } else { if (pythonError) PyErr_Print(); diff --git a/plugins/pythonextensions/pythonextensions.pro b/plugins/pythonextensions/pythonextensions.pro index e28b860..334e029 100644 --- a/plugins/pythonextensions/pythonextensions.pro +++ b/plugins/pythonextensions/pythonextensions.pro @@ -24,7 +24,7 @@ include($$IDE_SOURCE_TREE/src/qtcreatorplugin.pri) # Qt Creator Core bindings WRAPPED_HEADER = $$PWD/wrappedclasses.h -WRAPPER_DIR = $$OUT_PWD/PythonExtension/QtCreator +WRAPPER_DIR = $$OUT_PWD/QtCreator TYPESYSTEM_FILE = typesystem_qtcreator.xml TYPESYSTEM_NAME = qtcreator SHIBOKEN_QT = core gui widgets diff --git a/plugins/pythonextensions/pythonextensionsplugin.cpp b/plugins/pythonextensions/pythonextensionsplugin.cpp index 893819c..59b32a1 100644 --- a/plugins/pythonextensions/pythonextensionsplugin.cpp +++ b/plugins/pythonextensions/pythonextensionsplugin.cpp @@ -188,13 +188,13 @@ void PythonExtensionsPlugin::initializePythonBindings() QDir().mkpath(pythonPackagePath()); PyUtil::addToSysPath(pythonPackagePath().toStdString()); // Initialize the Python context and register global Qt Creator variable - if (!PyUtil::bindShibokenModuleObject("PythonExtension", "QtCreator")) { + if (!PyUtil::bindCoreModules()) { qWarning() << "Python bindings could not be initialized"; Core::MessageManager::write(Constants::MESSAGE_MANAGER_PREFIX + tr("Python bindings could not be initialized")); return; } // Bind the plugin instance - PyUtil::bindObject("PythonExtension", "PluginInstance", PyUtil::PythonExtensionsPluginType, this); + PyUtil::bindObject("QtCreator", "PythonExtensions", PyUtil::PythonExtensionsPluginType, this); } void PythonExtensionsPlugin::initializeOptionalBindings() diff --git a/plugins/pythonextensions/pyutil.cpp b/plugins/pythonextensions/pyutil.cpp index b563c55..b992e36 100644 --- a/plugins/pythonextensions/pyutil.cpp +++ b/plugins/pythonextensions/pyutil.cpp @@ -56,10 +56,10 @@ extern "C" void initQtCreator(); // These variables store all Python types exported by QtCreators bindings, // as well as the types exported for QtWidgets. -extern PyTypeObject **SbkPythonExtension_QtCreatorTypes; +extern PyTypeObject **SbkQtCreatorTypes; // This variable stores the Python module generated by Shiboken -extern PyObject *SbkPythonExtension_QtCreatorModuleObject; +extern PyObject *SbkQtCreatorModuleObject; namespace PyUtil { @@ -157,7 +157,7 @@ bool bindObject(const QString &moduleName, const QString &name, int index, void return false; // Generate the type - PyTypeObject *typeObject = SbkPythonExtension_QtCreatorTypes[index]; + PyTypeObject *typeObject = SbkQtCreatorTypes[index]; PyObject *po = Shiboken::Conversions::pointerToPython(reinterpret_cast(typeObject), o); if (!po) { @@ -169,9 +169,10 @@ bool bindObject(const QString &moduleName, const QString &name, int index, void return bindPyObject(moduleName, name, po); } -bool bindShibokenModuleObject(const QString &moduleName, const QString &name) +bool bindCoreModules() { - return bindPyObject(moduleName, name, SbkPythonExtension_QtCreatorModuleObject); + return bindSubPyObject("QtCreator", "Utils", SbkQtCreatorModuleObject) + && bindSubPyObject("QtCreator", "Core", SbkQtCreatorModuleObject); } bool bindPyObject(const QString &moduleName, const QString &name, void *obj) diff --git a/plugins/pythonextensions/pyutil.h b/plugins/pythonextensions/pyutil.h index 23fdb37..ca58f6e 100644 --- a/plugins/pythonextensions/pyutil.h +++ b/plugins/pythonextensions/pyutil.h @@ -53,7 +53,7 @@ PYTHONEXTENSIONSSHARED_EXPORT bool createModule(const std::string &moduleName); bool bindObject(const QString &moduleName, const QString &name, int index, void *o); -bool bindShibokenModuleObject(const QString &moduleName, const QString &name); +bool bindCoreModules(); PYTHONEXTENSIONSSHARED_EXPORT bool bindPyObject(const QString &moduleName, const QString &name, void *obj); diff --git a/plugins/pythonextensions/typesystem_qtcreator.xml b/plugins/pythonextensions/typesystem_qtcreator.xml index 49dd794..69f051e 100644 --- a/plugins/pythonextensions/typesystem_qtcreator.xml +++ b/plugins/pythonextensions/typesystem_qtcreator.xml @@ -41,7 +41,7 @@ --> - + diff --git a/python/extensionmanager/__init__.py b/python/extensionmanager/__init__.py index 8588796..f6caa37 100644 --- a/python/extensionmanager/__init__.py +++ b/python/extensionmanager/__init__.py @@ -42,20 +42,20 @@ from .list import * -from PythonExtension import QtCreator +from QtCreator import Core from PySide2.QtCore import * from PySide2.QtWidgets import * # Actions def showExtensionList(): - dialog = ListView(QtCreator.Core.ICore.dialogParent()) + dialog = ListView(Core.ICore.dialogParent()) dialog.exec_() pythonExtensionsAction = QAction("About Python Extensions...") pythonExtensionsAction.setMenuRole(QAction.ApplicationSpecificRole) -pythonExtensionsCommand = QtCreator.Core.ActionManager.registerAction(pythonExtensionsAction, - "PythonExtensions.About") +pythonExtensionsCommand = Core.ActionManager.registerAction(pythonExtensionsAction, + "PythonExtensions.About") QObject.connect(pythonExtensionsAction, SIGNAL("triggered()"), showExtensionList) -helpMenu = QtCreator.Core.ActionManager.actionContainer("QtCreator.Menu.Help") +helpMenu = Core.ActionManager.actionContainer("QtCreator.Menu.Help") helpMenu.addAction(pythonExtensionsCommand, "QtCreator.Group.Help.About") diff --git a/python/extensionmanager/actions.py b/python/extensionmanager/actions.py index 7f05e77..48e5ae4 100644 --- a/python/extensionmanager/actions.py +++ b/python/extensionmanager/actions.py @@ -41,7 +41,7 @@ # Functions for installing and deleting extensions import sys, zipfile -from PythonExtension import PluginInstance as instance +from QtCreator import PythonExtensions from send2trash import send2trash def install(path): @@ -59,14 +59,14 @@ def install(path): return "The .zip file is malformed." # Make sure the extension manager does not overwrite # extensions that are already installed - for ext in instance.extensionList(): + for ext in PythonExtensions.extensionList(): if extName == ext.name: return "The extension \"{}\" is already installed. Uninstall it before trying again.".format(extName) - extZip.extractall(instance.extensionDir().absolutePath()) + extZip.extractall(PythonExtensions.extensionDir().absolutePath()) extZip.close() except Exception as e: return str(e) return True def uninstall(ext): - send2trash(instance.extensionDir().absolutePath() + "/" + ext) + send2trash(PythonExtensions.extensionDir().absolutePath() + "/" + ext) diff --git a/python/extensionmanager/list.py b/python/extensionmanager/list.py index 32002b1..c71b4d4 100644 --- a/python/extensionmanager/list.py +++ b/python/extensionmanager/list.py @@ -43,7 +43,7 @@ from . import actions from PySide2 import QtCore, QtWidgets, QtGui -from PythonExtension import PluginInstance as instance +from QtCreator import PythonExtensions class ExtensionList(QtWidgets.QListWidget): def __init__(self): @@ -56,7 +56,7 @@ class ExtensionList(QtWidgets.QListWidget): def loadExtensionList(self): i = 0 - for ext in instance.extensionList(): + for ext in PythonExtensions.extensionList(): item = QtWidgets.QListWidgetItem(self) if not ext.loaded: item.setText(ext.name + " [did not load]") @@ -79,7 +79,7 @@ class ListView(QtWidgets.QDialog): self.layout = QtWidgets.QVBoxLayout(self) self.label = QtWidgets.QLabel() - self.label.setText("Manage Python extensions installed to \"{0}\".".format(instance.extensionDir().absolutePath())) + self.label.setText("Manage Python extensions installed to \"{0}\".".format(PythonExtensions.extensionDir().absolutePath())) self.label.setWordWrap(True) self.layout.addWidget(self.label) @@ -116,7 +116,7 @@ class ListView(QtWidgets.QDialog): selected = self.list.selectedIndexes() if len(selected) >= 1: selected = selected[0].row() - ext = instance.extensionList()[selected] + ext = PythonExtensions.extensionList()[selected] if ext == "extensionmanager": QtWidgets.QMessageBox.warning(self, "Can not Uninstall", "The Extension Manager can not uninstall itself.") else: @@ -145,7 +145,7 @@ class ListView(QtWidgets.QDialog): "/", "Qt Creator Python Extensions (*.zip)" ) - oldExtensions = list(instance.extensionList()) + oldExtensions = list(PythonExtensions.extensionList()) result = actions.install(fileName[0]) if result == True: QtWidgets.QMessageBox.information( -- cgit v1.2.3