Search code examples
python-3.xpyinstallerexecx-freezepyside2

Python to EXE - PySide2 and Custom Modules


I'm trying to create an EXE from a Python project I built and I'm running into some issues. I've done this before with PyInstaller for simpler tools and cx-freeze for tools where I use custom modules but the way I used to set it up doesn't seem to be working anymore.

In this particular case I've tried:

  • cx-freeze==6.10
  • pyinstaller==4.10
  • py2exe==0.11.1.0
  • auto-py-to-exe==2.18.0
  • and a few others with no luck

Everything works perfectly fine through the Python 3.8 interpreter. I'm assuming it's either because of the way I'm importing PySide2 here (which I don't normally do but did for this project to see if it would speed up my programming time) or that the EXE modules can't find my custom modules. Here is a mock version of my program (names/paths changed for simplicity):

Example folder of my project ("C:\a\MyProjects\Project1"):

enter image description here

Example folder of the custom module I'm using. Each using various other built-in and/or 3rd party python modules. ("C:\a\path\to\external\modules"):

enter image description here

Example of my main file (C:\a\MyProjects\Project1\ui.py) I want to turn into an EXE:

import os
import sys
import colorsys
from PySide2.QtWidgets import *
from PySide2.QtCore import *
from PySide2.QtGui import *

import utils  # module in project ("C:\a\MyProjects\Project1\utils.py")
sys.path.append(r"C:\a\path\to\external\modules")  # custom module location for MyModule
from MyModule.foo import module1 as foo_mod1
from MyModule.foo import module2 as foo_mod2
from MyModule.bar import module1 as bar_mod1
from MyModule.bar import module2 as bar_mod2
from MyModule.baz import module1 as baz_mod1
from MyModule.baz import module2 as baz_mod2


class MainDialog(QDialog):
    [...code...]
    [...use of "dark.stylesheet"...]
    [...use of "images\image 1.png"...]
    [...use of "images\image 2.png"...]

def main():
    global win
    try:  # try to close existing instances
        win.close()
    except NameError:
        pass

    win = MainDialog()
    win.show()


if __name__ == "__main__":
    app = QApplication.instance()
    if not app:
        app = QApplication(sys.argv)

    main()
    sys.exit(app.exec_())

Can someone tell me the best module and method to make this into a windowed (console-less), if possible, single file application. This is one of the more complicated tools I've had to make into a desktop app so if I can figure this out I should be good for most of the other things I have to do.

Thanks in advance.

EDIT:

Example of cx-freeze setup.py file in project I tried (C:\a\MyProjects\Project1\setup.py):

from cx_Freeze import setup, Executable
import sys

setup(
    name="MyProject",
    version="1.0",
    options={'build_exe': {
        'excludes': ["Tkinter"],
        'includes': ["utils", "MyModule.foo", "MyModule.bar", "MyModule.baz"],
        'path': sys.path + [r"C:\a\path\to\external\modules"],
        'include_files': ["images\image 1.png", "images\image 2.png"],
        'packages': ["PySide2.QtWidgets", "PySide2.QtCore", "PySide2.QtGui"]}},
    executables=[Executable("ui.py", base="Win32GUI")]

Example of pyinstaller cmd command I tried:

cd C:\\a\MyProjects\Project1
pyinstaller -p "C:\a\path\to\external\modules" --onefile -w ui.py
# even tried this with a custom spec file like:
# pyinstaller --onefile -w ui.spec

Solution

  • This seems to have fixed itself after I got a new workstation and installed the latest Python (3.10) and Pyinstaller (5.1) versions.

    Also think having your custom Python Libraries in the PYTHONPATH and/or PATH Environment variables may be important for allowing Pyinstaller to find them.