Search code examples
pythonqmlpyqt5kde-plasma

Deploy a QtQuick QML Python project on KDE Linux


I need advice on how to specify the paths to my QML and resources (icon) in my simple QtQuick QML Python application on KDE. The only related question I found here was: Deploy a Qt project on linux

My question is different. My only target for deploying my application is KDE; therefore, I do not need to bundle Qt libraries and my application has no other dependencies. I only need to deploy my python and QML files and an application icon (png).

One other wrinkle is that, in the future, I want to be able to provide certain updates via QML files only. I plan to push out, when needed, a single new QML file without having to deploy a new version of the application.

This leads me to believe that I should not use Qt resource system. However, lacking any experience with that system or with deploying applications in general, I seek advice.

I do not want to hard code the path to my icon and main QML file in my main.py file upon deploying. Furthermore, the following code does not give me the location of any of my application's files:

QCoreApplication.applicationDirPath()

It returns /usr/bin (the location of python) which is not a location suitable for my QML file or application icon.

How can I locate my QML and resource files within the executing __main__ method?

Here is my main.py:

import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QUrl
from PyQt5.QtQml import QQmlApplicationEngine
from PyQt5.QtGui import QIcon


if __name__ == '__main__':
    app = QApplication(sys.argv)

    engine = QQmlApplicationEngine()
    engine.load(QUrl.fromLocalFile('view.qml'))
    app.setWindowIcon(QIcon('appicon.png'))

    if not engine.rootObjects():
        sys.exit(-1)
    sys.exit(app.exec_())

Here is my view.qml

import QtQuick.Window 2.2
import QtQuick 2.2
import QtQuick.Controls 2.14

Window {
    id: root
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")
    }

This code works when I execute python main.py from the local directory. However, if I deploy my python, qml and icon files to, say, /usr/local/bin I have to hard-code that path into the python file as follows.

    engine.load(QUrl.fromLocalFile('/usr/local/bin/view.qml'))
    app.setWindowIcon(QIcon('/usr/local/bin/appicon.png'))

I do not want to do this. I am looking for other alternatives that do not involve hard-coding the path.

This question is not about distribution-specific packaging. Assume I will use something like the "generic" method discussed here -- such as a shell script (and assume the installing user will have sudo rights).


Solution

  • The idea in this case is to create absolute paths using relative paths with respect to a main element. For example in this case you could use the main.py directory path (which can be obtained by the solutions provided to this answer: How do I get the path and name of the file that is currently executing?) to obtain the other paths.

    import os
    import sys
    
    from PyQt5.QtCore import QUrl
    from PyQt5.QtGui import QIcon
    from PyQt5.QtWidgets import QApplication
    from PyQt5.QtQml import QQmlApplicationEngine
    
    
    CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
    
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
    
        engine = QQmlApplicationEngine()
        engine.load(QUrl.fromLocalFile(os.path.join(CURRENT_DIR, "view.qml")))
        app.setWindowIcon(QIcon(os.path.join(CURRENT_DIR, "appicon.png")))
    
        if not engine.rootObjects():
            sys.exit(-1)
        sys.exit(app.exec_())
    ├── appicon.png
    ├── main.py
    └── view.qml