PyInstaller packed PySide6 application Cannot load qtquick2plugin.dll - qt

I have a PySide6 + QML application to pack to exe file with PyInstaller.
Here's my code:
main.qml
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
ApplicationWindow {
id: window
title: "Motor"
width: 500
height: 600
visible: true
maximumHeight: height
maximumWidth: width
minimumHeight: height
minimumWidth: width
}
main.py
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine
if __name__ == "__main__":
import sys
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine(parent=app)
engine.load("main.qml")
sys.exit(app.exec_())
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
motor.spec
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['main.py'],
pathex=['E:\\Projects\\motor\\GUI'],
binaries=[],
datas=[('main.qml', '.'), ('settings.ini', '.')],
hiddenimports=['PySide6.QtCore', 'PySide6.QtGui', 'PySide6.QtQml'],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='MotorGUI',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='MotorGUI')
After pack with pyinstaller motor.spec, I copied plugins, qml and translations folder from python/site-pack/PySide6 folder to the exe's PySide6 folder.
When I run the exe file, I got:
QQmlApplicationEngin failed to load component
file:///E:/Projects/motor/GUI/dist/MotorGUI/main.qml:1:1: Cannot load library E:\Projects\motor\GUI\dist\MotorGUI\PySide6\qml\QtQuick\qtquick2plugin.dll
The qtquick2plugin.dll actually exists.
my python version is 3.8.6
PySide==6.0.0
pyinstaller==4.2

PyInstaller (as of 4.2) does not yet support PySide6.
https://github.com/pyinstaller/pyinstaller/issues/5414

I've found the root cause. It lacks of dll of QT.
I fix this by copying all .dll file in the pyside Qt folder to the exe's folder.
Then it runs perfectly.
After that, I mamually remove redundant dll one by one to determine the minimal requirements.
Finally add the dll in spec file

Related

webdriver_manager error question (project using pyinstaller)

First, set up a virtual environment with anaconda, then install modules such as selenium,pyqt5, pyinstaller, and webdriver_manager in the virtual environment,
After creating the .spec file by setting pyinstaller.exe -w -F (project), the .spec file was modified as follows.
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
['GUI.py'],
pathex=[],
binaries=[],
datas=[('gui.ui','.'),('BHA_icon.png','.'),('process.py','.')],
hiddenimports=["webdriver_manager.chrome","selenium"],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='Baekjoon Hub Automation',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
icon=r'BHA_icon.ico',
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
After that, I built it as an exe file, and the program ran well with the console window below on my computer, but when I ran the exe file on another computer, the following error occurred.
enter image description here
enter image description here
and my console window : [13676:20232:0201/200946.234:ERROR:network_change_notifier_win.cc(224)] WSALookupServiceBegin failed with: 0
DevTools listening on ws://127.0.0.1:7831/devtools/browser/4cce63d7-9b48-420e-a020-ff714694c193
[16408:19512:0201/200946.366:ERROR:network_change_notifier_win.cc(224)] WSALookupServiceBegin failed with: 0
[13676:6804:0201/200947.548:ERROR:cert_issuer_source_aia.cc(34)] Error parsing cert retrieved from AIA (as DER):
ERROR: Couldn't read tbsCertificate as SEQUENCE
ERROR: Failed parsing Certificate
[13676:20232:0201/200950.547:ERROR:device_event_log_impl.cc(215)] [20:09:50.547] Bluetooth: bluetooth_adapter_winrt.cc:1205 Getting Radio failed. Chrome will be unable to change the power state by itself.
[13676:20232:0201/200950.565:ERROR:device_event_log_impl.cc(215)] [20:09:50.565] Bluetooth: bluetooth_adapter_winrt.cc:1283 OnPoweredRadioAdded(), Number of Powered Radios: 1
[13676:20232:0201/200950.566:ERROR:device_event_log_impl.cc(215)] [20:09:50.566] Bluetooth: bluetooth_adapter_winrt.cc:1298 OnPoweredRadiosEnumerated(), Number of Powered Radios: 1
[7568:21300:0201/201146.489:ERROR:gpu_init.cc(523)] Passthrough is not supported, GL is disabled, ANGLE is
[13676:20232:0201/202032.150:ERROR:device_event_log_impl.cc(215)] [20:20:32.148] USB: usb_service_win.cc:104 SetupDiGetDeviceProperty({{A45C254E-DF1C-4EFD-8020-67D146A850E0}, 6}) failed: 요소가 없습니다. (0x490)
[13676:20232:0201/202032.174:ERROR:device_event_log_impl.cc(215)] [20:20:32.173] USB: usb_service_win.cc:307 SetupDiEnumDeviceInterfaces: 사용 가능한 데이터가 없습니다. (0x103)
driver setting code
import time
from selenium.webdriver.common.by import By
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
def set_chrome_driver():
options = webdriver.ChromeOptions()
options.add_experimental_option("detach", True)
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
return driver
#####
def start_setting_BJ(id, pw, i, driver):
if i!=True:
url = 'https://www.acmicpc.net/login'
driver.get(url)
selector = "#submit_button"
time.sleep(1)
driver.find_element(By.NAME, 'login_user_id').send_keys(id)
driver.find_element(By.NAME, 'login_password').send_keys(pw)
elem = driver.find_element(By.CSS_SELECTOR, selector)
elem.click()
time.sleep(2)
login_check= driver.find_element(By.XPATH, "/html/body/div[2]/div[1]/div[1]/div/ul/li[3]/a") # 로그인 여부 확인용 "로그인" 텍스트 인식
if login_check.text=="로그인":
return -1
else:
driver.get('https://www.acmicpc.net/user/' + id)
Peoblem_list = '/html/body/div[2]/div[2]/div[3]/div[2]/div/div[2]/div[2]/div[2]/div'
time.sleep(1)
elem = driver.find_element(By.XPATH, Peoblem_list)
all = elem.text.split()
return all

Executable created using pyinstaller onefile option fail to run on another computer

I have created an executable file using --onefile option with pyinstaller (pyside6 app) and it works fine on the windows computer on which it is created. When I run this file on another windows machine, if get the following error:
qt.qpa.plugin: Could not load the Qt platform plugin "windows" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
Available platform plugins are: direct2d, minimal, offscreen, windows.
I have tried putting the platform folder with .dll files next to the executable but that doesn't solve this problem.
Further, none of the suggestions mentioned in PyInstaller generated exe file error : qt.qpa.plugin: could not load the qt platform plugin "windows" in "" even though it was found and the thread therein have helped.
Could you please let me know a possible way to fix this issue?
Below is an MWE having the two python source files and the pyinstaller spec file.
test_app.py
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'test_app.ui'
##
## Created by: Qt User Interface Compiler version 6.3.1
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QLabel, QLineEdit, QMainWindow,
QPushButton, QSizePolicy, QStatusBar, QWidget)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
if not MainWindow.objectName():
MainWindow.setObjectName(u"MainWindow")
MainWindow.resize(300, 150)
self.centralwidget = QWidget(MainWindow)
self.centralwidget.setObjectName(u"centralwidget")
self.label = QLabel(self.centralwidget)
self.label.setObjectName(u"label")
self.label.setGeometry(QRect(10, 39, 41, 21))
self.enteredName = QLineEdit(self.centralwidget)
self.enteredName.setObjectName(u"enteredName")
self.enteredName.setGeometry(QRect(70, 40, 113, 20))
self.showHi = QLineEdit(self.centralwidget)
self.showHi.setObjectName(u"showHi")
self.showHi.setGeometry(QRect(80, 100, 113, 20))
self.run = QPushButton(self.centralwidget)
self.run.setObjectName(u"run")
self.run.setGeometry(QRect(210, 40, 56, 17))
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QStatusBar(MainWindow)
self.statusbar.setObjectName(u"statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QMetaObject.connectSlotsByName(MainWindow)
# setupUi
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
self.label.setText(QCoreApplication.translate("MainWindow", u"Name", None))
self.run.setText(QCoreApplication.translate("MainWindow", u"Run", None))
# retranslateUi
The main file (test_MWE.py)
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QLineEdit, QFileDialog
from test_app import Ui_MainWindow
def showMessage():
window.ui.showHi.setText("HI "+window.ui.enteredName.text())
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
window.ui.run.clicked.connect(showMessage)
sys.exit(app.exec())
The test_MWE.spec file
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
['test_MWE.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='test_MWE',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
Recap, I am compiling the executable with --onefile option on windows 11. The resulting file is working as expected. On running the executable file on Windows 7, I am getting the error given above.
Qt6 was never intended to work on versions older than Windows 10, as explained in the early blog post about hosts and targets, and as can be seen in the official documentation about the supported platforms.
If you need your program to also work on Windows <10, you must use Qt5.

Pyinstaller with fastapi and database

This is folder structure of my fastapi app. I am using sqlalchemy to connect to Postgres database. I am using uvicorn server.
In my main.py:
functions.models.Base.metadata.create_all(bind=engine)
tasks.models.Base.metadata.create_all(bind=engine)
app= FastAPI()
app.include_router(functions.main.router)
app.include_router(tasks.main.router)
if __name__ == "__main__":
uvicorn.run(f"{Path(__file__).stem}:app", host='0.0.0.0', port=8127, workers=1)
I am trying to compile into exe with pyinstaller. This is my spec file, please advice what is wrong that main doesn't load:
a = Analysis(['main.py'],
pathex=['...\\app'],
binaries=[],
datas=[],
hiddenimports=['uvicorn.lifespan.off','uvicorn.lifespan.on','uvicorn.lifespan',
'uvicorn.protocols.websockets.auto','uvicorn.protocols.websockets.wsproto_impl',
'uvicorn.protocols.websockets_impl','uvicorn.protocols.http.auto',
'uvicorn.protocols.http.h11_impl','uvicorn.protocols.http.httptools_impl',
'uvicorn.protocols.websockets','uvicorn.protocols.http','uvicorn.protocols',
'uvicorn.loops.auto','uvicorn.loops.asyncio','uvicorn.loops.uvloop','uvicorn.loops',
'uvicorn.logging','app.database'],
hookspath=['extra-hooks'],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='main',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='main')
It seems that there is simply a problem with the current directory where PyInstaller is built. If the current directory where PyInstaller is built is always the same, you may want to use the following statement in your spec file.
import os
current_dir = os.getcwd()
work_dir = current_dir
source_dir = current_dir +'\\app\\(your source folder)'
sub_path_list = [
'\\(required path)',
...
]
pathex_list = [source_dir,t_dir] + [ source_dir+add_path for add_path in sub_path_list]
print(pathex_list)
a = Analysis([source_dir +'\\main.py'],
pathex=pathex_list,
...(omit)

Pyinstaller: Module not found when running .exe

I have a problem which I have reduced to a small program. The program tries to write a Pandas dataframe. This works find in PyCharm, but when I produce an exe using PyInstaller it errors at runtime:
.\pyinst_excel.exe
Traceback (most recent call last):
File "pyinst_excel.py", line 31, in <module>
File "pyinst_excel.py", line 25, in add_generated_files_row
File "site-packages\pandas\io\excel\_openpyxl.py", line 18, in __init__
ModuleNotFoundError: No module named 'openpyxl'
[11408] Failed to execute script pyinst_excel
Now I have tried explicitly importing openpyxl and that didn't work and I have also used --hidden-import:
call venv\Scripts\activate
pyinstaller --onefile --hidden-import _openpyxl --hidden-import openpyxl --clean pyinst_excel.py
The generated spec file looks like this:
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['pyinst_excel.py'],
pathex=['D:\\Development\\OEM-SR-Rules'],
binaries=[],
datas=[],
hiddenimports=['_openpyxl', 'openpyxl'],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='pyinst_excel',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True )
However this doesn't fix the problem. From the build/warnings file I see:
...
missing module named openpyxl - imported by pandas.io.excel._openpyxl (delayed, conditional), D:\Development\OEM-SR-Rules\pyinst_excel.py (top-level)
...
missing module named 'openpyxl.styles' - imported by pandas.io.excel._openpyxl (delayed)
missing module named 'openpyxl.style' - imported by pandas.io.excel._openpyxl (delayed)
Program code:
import argparse
from operator import attrgetter
import os
import sys
import json
import pandas as pd
import numpy as np
from pathlib import Path
import glob
import re
import time
from sys import exit
from shutil import copyfile
REPORT_DATE_FMT = '%d-%m-%Y %H.%M'
def add_generated_files_row(generated_excel, sequence: int, date_generated):
# gen_files_df = pd.read_excel(generated_files_excel, index_col=0)
gen_files_df = pd.DataFrame(columns=['Sequence', 'Date Generated'])
new_row = {'Sequence': sequence,
'Date Generated': date_generated}
gen_files_df = gen_files_df.append(new_row, ignore_index=True, sort=False)
writer = pd.ExcelWriter(generated_excel)
gen_files_df.to_excel(writer)
generated_files_excel = Path('D:\temp\test.xlsx')
date_generated = time.strftime(f"{REPORT_DATE_FMT}")
add_generated_files_row(generated_files_excel, 1, date_generated)
I am using Python 3.8 and PyInstaller 3.6.
I am out of ideas. Any help would be much appreciated.
Thanks,
Clive
The problem turned out to be caused PyInstaller being run from a different environment.
To solve this I had to do:
venv\Scripts\activate.bat
(venv) D:\Development\OEM-SR-Rules>pip install PyInstaller

QML FileDialog nameFilters case sensitive on Linux?

The following code will correctly display *.ext and *.EXT files on Windows and Mac. It does NOT display *.EXT (and of course *.Ext, *.eXt, *.exT...) files on Linux. What's my mistake?
import QtQuick 2.3
import QtQuick.Dialogs 1.1
FileDialog
{
title: "Please choose a file"
nameFilters: [ "Scene files (*.ext)" ]
selectMultiple: true
}
The Linux file system is case sensitive, and that is why it won't return *.EXT files.
The following should work:
nameFilters: [ "Scene files (*.ext *.EXT)" ]

Resources