Access fbs resource files in non-GUI code

834 Views Asked by At

Using fbs to package a PyQt5 app, what could be the cleanest way to access resource files from non-GUI code?

In the example below, I made a simple PyQt5 app with one window containing one button. The button triggers a function that will read a .json resource file and print its attribute message in the console. The function print_data() defined in logic.py should also work without the GUI app, for example to be used by other python scripts. Therefore, it cannot be move as a method of the MainWindow class.

It is easy and handy to use the application context's get_resource() method to get the path to mainwindow.ui. Unfortunately, it cannot be used by print_data() to get the path to static_data.json as the function has no access to the application context.

What would be the best solution?

  • Use fbs's resources system only for gui-related resource files and keep static_data.json with the python files?
  • Try to access the application context outside of the MainWindow class?
  • Use another python resources library such as pkg_resources to handle non gui-related resource files?
  • Use another tool such as cx_freeze to package the app?

Directory structure:

|-- src
|  |-- main
|  |  |-- python
|  |  |  |-- main.py
|  |  |  |-- gui.py
|  |  |  |-- logic.py
|  |  |-- resources
|  |  |  |-- base
|  |  |  |  |-- mainwindow.ui
|  |  |  |  |-- static_data.json

Content of main.py:

from fbs_runtime.application_context.PyQt5 import ApplicationContext
import sys
from gui import MainWindow

if __name__ == '__main__':
    appctxt = ApplicationContext()
    window = MainWindow(appctxt)
    window.show()
    exit_code = appctxt.app.exec_()
    sys.exit(exit_code)

Content of gui.py:

from PyQt5.QtWidgets import QMainWindow
from PyQt5 import uic

from logic import print_data


class MainWindow(QMainWindow):
    def __init__(self, context):
        super().__init__()

        # Loading the .ui file from the resources
        self.ui = uic.loadUi(context.get_resource("mainwindow.ui"), self)

        # Binding the button to the print_data function defined in logic.py
        self.main_button.clicked.connect(print_data)

Content of logic.py:

import json


def print_data():

    # Getting the resource data filepath
    filepath = "../resources/base/static_data.json"

    # Processing the resource file
    with open(filepath) as file:
        data = json.load(file)
        print(data["message"])
1

There are 1 best solutions below

0
On BEST ANSWER
python
├── base.py
├── gui.py
├── logic.py
└── main.py

One possible solution is to create the context in a file where everyone can access that variable:

base.py

from fbs_runtime.application_context.PyQt5 import ApplicationContext

context = ApplicationContext()

Then it is used in the other classes:

gui.py

from PyQt5.QtWidgets import QMainWindow
from PyQt5 import uic

from base import context

from logic import print_data


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        # Loading the .ui file from the resources
        self.ui = uic.loadUi(context.get_resource("mainwindow.ui"), self)

        # Binding the button to the print_data function defined in logic.py
        self.main_button.clicked.connect(print_data)

logic.py

import json

from base import context


def print_data():
    # Getting the resource data filepath
    filepath = context.get_resource("static_data.json")

    # Processing the resource file
    with open(filepath) as file:
        data = json.load(file)
        print(data["message"])

main.py

import sys

from base import context
from gui import MainWindow

if __name__ == "__main__":
    window = MainWindow()
    window.resize(250, 150)
    window.show()
    exit_code = context.app.exec_()
    sys.exit(exit_code)