pythonpyqtpyqt5pyinstallerqsettings

QSettings doesn't work after building onefile using pyinstaller


I am having an issue when building pyinstaller onefile version of my script my checkbox state doesn't get saved, but in the other hand when pyinstaller building normal exe with files the checkbox state is saved and works perfectly.

Note that I am using resources(package)>__init__.py to store my icons and config.ini and the icons works in both cases onefile or normal build.

Project files picture

__init__.py contents

from pathlib import Path

resources = Path(__file__).parent

config_ini = resources / "config.ini"

My PyQt5 Gui.

import sys

from PyQt5.QtCore import QSettings

import resources

import PyQt5.QtCore
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *



settings = QSettings(str(resources.config_ini), QSettings.IniFormat)


class Window(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.main_ui()
        self.buttons()
        self.layout()
        self.show()
        settings.sync()


    def main_ui(self):
        self.setWindowTitle("Files Organizer")

    def buttons(self):
        self.checkbox_startup = QCheckBox("Run on start up")

        self.checkbox_startup.setChecked(False)
        self.checkbox_startup.setChecked(settings.value("startup_state", type=bool))

        self.checkbox_startup.toggled.connect(self.startup_settings)

    def layout(self):
        self.horizontalGroupBox_options = QGroupBox("Options", self)
        verticalbox_options = QVBoxLayout()
        verticalbox_options.addWidget(self.checkbox_startup)
        self.horizontalGroupBox_options.setLayout(verticalbox_options)
        self.horizontalGroupBox_options.resize(360, 80)
        self.horizontalGroupBox_options.move(20, 110)

    def startup_settings(self):
        startup_state = self.checkbox_startup.isChecked()
        settings.setValue("startup_state", startup_state)
        print("startup state is ", settings.value("startup_state", type=bool))


if __name__ == "__main__":
    app = QApplication(sys.argv)
    screen = Window()
    screen.show()
    app.exec()


Solution

  • Answered outside of stackoverflow at Python Discord by user Numerlor

    onefile works by extracting it's contents to a temp directory, that has its path stored in sys._MEIPASS. So you setting the values in resources.config_ini only changes the extracted file, which is removed after you close the program

    qt has a bunch of paths under QtCore.QStandardPaths.writableLocation that might be where you want to store config, like QtCore.QStandardPaths.writableLocation(QtCore.QStandardPaths.AppConfigLocation) which returns .../appdata/local/{org}/{app}

    These lines are added at the begging of the GUI.

    # This return .../appdata/local
    local_path = QStandardPaths.writableLocation(QStandardPaths.AppConfigLocation) 
    # Make directory for my program
    os.makedirs(local_path + "\\" + "FilesOrganizer", exist_ok=True) 
    # Making config.ini file.
    config_path = local_path + "\\" + "FilesOrganizer" + "\\" + "config.ini" 
    settings = QSettings(config_path, QSettings.IniFormat)