Summary:
I developed a UI app with Pyside2 and it works when ran from Pycharm, but when I package it using PyInstaller the .exe doesnt read the .ui file included. It yields this error.
C:\Users\JULIAN~1.MIL\AppData\Local\Temp\_MEI6322\relevantUI.ui
QIODevice::read (QFile, "C:\Users\JULIAN~1.MIL\AppData\Local\Temp\_MEI6322\relevantUI.ui"): device not open
Designer: An error has occurred while reading the UI file at line 1, column 0: Premature end of document.
Traceback (most recent call last):
File "relevantUI.py", line 84, in <module>
File "relevantUI.py", line 49, in __init__
RuntimeError: Unable to open/read ui device
[19160] Failed to execute script relevantUI
The relevant code is this (im changing some naming for privacy purposes):
import PySide2
from PySide2 import QtXml
from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import QApplication, QWidget, QPushButton, QMessageBox, QComboBox
from PySide2.QtCore import QFile, QObject
import sys, os
import relevantClass
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
class Form(QObject):
def __init__(self, ui_file, parent= None):
super(Form, self).__init__(parent)
ui_file = QFile(ui_file)
ui_file.open(QFile.ReadOnly)
loader = QUiLoader()
self.window = loader.load(ui_file)
ui_file.close()
btn_launch = self.window.Launch
btn_upload = self.window.UploadFile
btn_quit = self.window.Quit
combo_map = self.window.MapComboBox
combo_samples = self.window.SamplesComboBox
btn_launch.clicked.connect(lambda: relevantClass.server_call(combo_map.currentIndex(),combo_samples.currentIndex()))
btn_upload.clicked.connect(lambda: relevantClass.database_call(combo_map.currentIndex()))
btn_quit.clicked.connect(self.quit_app)
self.window.show()
def quit_app(self):
app.quit()
if __name__ == '__main__':
# the path to the .ui is defined. We use resource_path to avoid absolute path problems using pyinstaller.
filename = resource_path('relevantTemplateUI.ui')
app = QApplication(sys.argv)
form = Form(filename)
sys.exit(app.exec_())
Then I call PyInstaller from install.py like follows:
import PyInstaller.__main__
PyInstaller.__main__.run([
'relevantUI.py',
'--onefile',
#'--windowed',
'--debug=all',
])
It creates the .exe but it yields the error quoted at the beginning.
Some comments.
Im installing from a script because using the auto_py_to_exe app has problems with global addresses, which are fixed with the function resource_path
I know, and I did, convert the original relevantTemplateUI.ui file to a .py file, but I encountered some very weird issues that are preventing me to use the file. For example this is the header of the converted .ui file:
from PySide2.QtCore import * from PySide2.QtGui import * from PySide2.QtWidgets import *
from pyside_test import Form
That pyside_test library is coming seemingly out of nowhere, i really dont know and it breaks the importing when using it inside relevantUI.py I can't simply comment it as in any case Form is instanced inside the class anyway. It is really weird, I really dont understand.
- The relevantClass.py contains some subprocess routines, but those doesnt seem to be the problem, im pretty sure is related to Pyside2.
The question would be: how to make sure that PyInstaller is reading the .ui file device and package it correctly.
Note: just to be sure, relevantUI.py is the name of the main file of the app, the one I want to compile, relevantTemplateUI.ui is the file coming from QTDesigner, relevantClass.py is a class used by the app. Again, I need to change naming due privacy purposes.