Hello world! My name is Tilman and I have been an intern with The Qt Company in Berlin for the last few weeks. During my time here, I have worked on enabling Python extensibility for the QtCreator and I am happy to announce, that a first proof of concept version is available today!
So, what exactly do the Python extensions do? Well, the goal is to eventually be able to do about anything a native C++ plugin could do. But for now, the scope is much narrower and only a very small part of the C++ API is exposed.
A Technical Perspective
The main goal for me was to explore how this vision could be implemented. For now the project focuses on getting the integration and setup right, rather than having as many bindings as possible.
Everything starts with a new QtCreator plugin, which initializes Python bindings and then loads the user provided Python extensions. This is done by executing their Python scripts in an embedded CPython interpreter. Getting this to work requires two main things:
- Bindings (and a mechanism for loading bindings only if the relevant plugins are loaded)
- A system for discovering, and running Python extensions
Some of you may be familiar with Qt for Python. This project enables developers to create Qt applications in Python by generating Python bindings for Qt’s C++ code. To do this, it uses a binding generator called Shiboken.
To generate the bindings for QtCreators APIs, I used the same tool. This means, that on top of all the QtCreator specific bindings, anything from Qt for Python is also available from Python.
Plugins in QtCreator can be disabled by the user. Thus, we can only expose bindings for the Core plugin and things like the Utils library directly without incurring dependencies. This is quite a harsh restriction on the bindings we can use.
To circumvent this problem, any other QtCreator plugin may provide an additional library, which is then dynamically loaded by the Python extensions plugin as necessary. These libraries will eventually be provided for all plugins maintained by the QtCompany. For now, there is one example of such a library available for the Project Explorer plugin.
The Embedded Interpreter
Python extensions are nothing but a directory containing a
main.py file, which represents the entry point of the extension.
My main design goal was to make Python extensions ‘feel’ as if they were normal Python scripts, run from within their extension directory. Since all the extensions run in the same embedded Python, there is a good deal of code devoted to making sure extensions seem isolated, as well as setting the appropriate
sys.path for each extension.
This means you can do things like
import other files from your extensions directory or mess with
sys.path, just like you would with a normal Python program.
If your extensions depend on any other Python modules, there is also a facility for loading these dependencies. By including a
requirements.txt, all your dependencies are ‘pip installed’ before your extension is first run. Should you need to do any other setup before your
main.py can run, you can also provide an optional
setup.py, which is run before, and separately from, your main script.
While a lot of heavy lifting still needs to be done, the main challenges of this project are now solved. If you are interested in trying things out yourself, I highly encourage you to check out the projects git repository. There, you can also have a look at the code and a more in-depth documentation.
On top of the C++ code, build instructions and some initial documentation, you will find several examples of Python extensions that give a taste of what will be possible.