Python PyQt5 Program Bundling With PyInstaller

Python PyQt5 Program Bundling With PyInstaller

·

5 min read

Basic GUI Program

We use pyqt5 to build the demo GUI program. The program only have a button with a callback to write current time stamp into a file.

First install pyqt5.

pip install pyqt5

Then the demo code.

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

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

        self.setWindowTitle("Times")

        self.btn = QPushButton(self)
        self.btn.setText("Run")
        self.btn.clicked.connect(self.handleClick)

    def handleClick(self):
        with open("times.txt", "a+", encoding="utf8") as f:
            data = f.read()
            data += str(time.time()) + "\n"
            f.write(data)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec()

Now we can start this program with python main.py and click the button to check if time stamp is written into the file.

Bundling With PyInstaller

PyInstaller is a bundling tool for python program. We can use it to bundle our GUI program into executable files.

First let's install it.

pip install pyinstaller

Then create a build.py file, which contains all the options for bundling.

import PyInstaller.__main__

PyInstaller.__main__.run([
    'main.py',
    # '--onefile',
    '--noconsole',
    "--name", "Times",
    "--add-data", "times.txt;."
])

The --onefile option is to bundle program into a one file executable. By default, we will bundle program into a one dir output. --noconsole option is to make sure no console shows when start the program. --name is used to specify the name of the application. --add-data is used to copy files into the bundling output. There are also many other options, you can check the documentation for details.

Now we can bundle this application, run the command below.

python build.py

Then the bundling process begins.

> python .\build.py
1417 INFO: PyInstaller: 5.3
1417 INFO: Python: 3.9.12 (conda)
1481 INFO: Platform: Windows-10-10.0.18363-SP0
1481 INFO: wrote C:\Users\yao\Desktop\code\Times.spec
1498 INFO: UPX is not available.
1514 INFO: Extending PYTHONPATH with paths
['C:\\Users\\yao\\Desktop\\code']
2894 INFO: checking Analysis
2902 INFO: Building Analysis because Analysis-00.toc is non existent
2917 INFO: Initializing module dependency graph...
2933 INFO: Caching module graph hooks...
2980 INFO: Analyzing base_library.zip ...
11986 INFO: Processing pre-find module path hook distutils from 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks\\pre_find_module_path\\hook-distutils.py'.
11986 INFO: distutils: retargeting to non-venv dir 'C:\\Users\\yao\\miniconda3\\lib'
15705 INFO: Caching module dependency graph...
15942 INFO: running Analysis Analysis-00.toc
15973 INFO: Adding Microsoft.Windows.Common-Controls to dependent assemblies of final executable
  required by C:\Users\yao\miniconda3\python.exe
17393 INFO: Analyzing C:\Users\yao\Desktop\code\main.py
17502 INFO: Processing module hooks...
17543 INFO: Loading module hook 'hook-difflib.py' from 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks'...
17575 INFO: Loading module hook 'hook-distutils.py' from 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks'...
17575 INFO: Loading module hook 'hook-distutils.util.py' from 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks'...
17583 INFO: Loading module hook 'hook-encodings.py' from 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks'...
18942 INFO: Loading module hook 'hook-heapq.py' from 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks'...
18942 INFO: Loading module hook 'hook-lib2to3.py' from 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks'...
19088 INFO: Loading module hook 'hook-multiprocessing.util.py' from 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks'...
19088 INFO: Loading module hook 'hook-pickle.py' from 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks'...
19096 INFO: Loading module hook 'hook-platform.py' from 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks'...
19096 INFO: Loading module hook 'hook-PyQt5.py' from 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks'...
19573 WARNING: Hidden import "sip" not found!
19573 INFO: Loading module hook 'hook-PyQt5.QtCore.py' from 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks'...
19960 INFO: Loading module hook 'hook-PyQt5.QtGui.py' from 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks'...
20641 INFO: Loading module hook 'hook-PyQt5.QtWidgets.py' from 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks'...
21310 INFO: Loading module hook 'hook-sysconfig.py' from 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks'...
21310 INFO: Loading module hook 'hook-xml.etree.cElementTree.py' from 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks'...
21325 INFO: Loading module hook 'hook-xml.py' from 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks'...
21403 INFO: Loading module hook 'hook-_tkinter.py' from 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks'...
22003 INFO: checking Tree
22003 INFO: Building Tree because Tree-00.toc is non existent
22003 INFO: Building Tree Tree-00.toc
22368 INFO: checking Tree
22368 INFO: Building Tree because Tree-01.toc is non existent
22368 INFO: Building Tree Tree-01.toc
22728 INFO: checking Tree
22728 INFO: Building Tree because Tree-02.toc is non existent
22728 INFO: Building Tree Tree-02.toc
22769 INFO: Looking for ctypes DLLs
22805 INFO: Analyzing run-time hooks ...
22813 INFO: Including run-time hook 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_subprocess.py'
22821 INFO: Including run-time hook 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pyqt5.py'
22829 INFO: Including run-time hook 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py'
22837 INFO: Including run-time hook 'C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py'
22853 INFO: Looking for dynamic libraries
26482 INFO: Looking for eggs
26482 INFO: Using Python library C:\Users\yao\miniconda3\python39.dll
26497 INFO: Found binding redirects:
[]
26498 INFO: Warnings written to C:\Users\yao\Desktop\code\build\Times\warn-Times.txt
26553 INFO: Graph cross-reference written to C:\Users\yao\Desktop\code\build\Times\xref-Times.html
26569 INFO: Appending 'datas' from .spec
26611 INFO: checking PYZ
26611 INFO: Building PYZ because PYZ-00.toc is non existent
26611 INFO: Building PYZ (ZlibArchive) C:\Users\yao\Desktop\code\build\Times\PYZ-00.pyz
27149 INFO: Building PYZ (ZlibArchive) C:\Users\yao\Desktop\code\build\Times\PYZ-00.pyz completed successfully.
27174 INFO: checking PKG
27174 INFO: Building PKG because PKG-00.toc is non existent
27175 INFO: Building PKG (CArchive) Times.pkg
27209 INFO: Building PKG (CArchive) Times.pkg completed successfully.
27209 INFO: Bootloader C:\Users\yao\miniconda3\lib\site-packages\PyInstaller\bootloader\Windows-64bit\runw.exe
27209 INFO: checking EXE
27209 INFO: Building EXE because EXE-00.toc is non existent
27209 INFO: Building EXE from EXE-00.toc
27209 INFO: Copying bootloader EXE to C:\Users\yao\Desktop\code\build\Times\Times.exe.notanexecutable
27338 INFO: Copying icon to EXE
27338 INFO: Copying icons from ['C:\\Users\\yao\\miniconda3\\lib\\site-packages\\PyInstaller\\bootloader\\images\\icon-windowed.ico']
27469 INFO: Writing RT_GROUP_ICON 0 resource with 104 bytes
27469 INFO: Writing RT_ICON 1 resource with 3752 bytes
27469 INFO: Writing RT_ICON 2 resource with 2216 bytes
27469 INFO: Writing RT_ICON 3 resource with 1384 bytes
27469 INFO: Writing RT_ICON 4 resource with 38188 bytes
27469 INFO: Writing RT_ICON 5 resource with 9640 bytes
27484 INFO: Writing RT_ICON 6 resource with 4264 bytes
27484 INFO: Writing RT_ICON 7 resource with 1128 bytes
27484 INFO: Copying 0 resources to EXE
27484 INFO: Embedding manifest in EXE
27484 INFO: Updating manifest in C:\Users\yao\Desktop\code\build\Times\Times.exe.notanexecutable
27640 INFO: Updating resource type 24 name 1 language 0
27640 INFO: Appending PKG archive to EXE
27655 INFO: Fixing EXE headers
28404 INFO: Building EXE from EXE-00.toc completed successfully.
28404 INFO: checking COLLECT
28404 INFO: Building COLLECT because COLLECT-00.toc is non existent
28412 INFO: Building COLLECT COLLECT-00.toc
35416 INFO: Building COLLECT COLLECT-00.toc completed successfully.

If everything goes well, below files/folders will be created.

Times.spec
build
dist

Times.spec contains all the actual parameters for bundling. build folder contains temporary bundling files for debugging purpose. dist folder contains the actual bundling output.

Finally, we can find the executable file in dist folder, and run it.

dist/Times/Times.exe