Search code examples
pyqt5pyinstallerpyside6pyqt6

How can I convert my python ( .py) file into an executable (.exe) file using pyinstaller?


I am working on a PySide6 application that consists of multiple Python files and folders. When I run the project using python main.py, everything works perfectly. However, I’m struggling to convert it into a standalone .exe file that includes all the necessary files and assets.

Here is the structure of my project:

MyProject/  # A folder
├── main.py  # Entry point of the application
├── models.py  # A file
├── staff.db # A file
├── utils.py  # A file
├── photos/  # Contains image resources
├── views/ # A folder
│   ├── __init__.py
│   ├── main_app.py  # Contains the MainApp class used in main.py
│   ├── admin_views/ # A folder
│   │   ├── __init__.py # A file
│   │   ├── admin_file1.py # A file
│   │   ├── admin_file2.py # A file
│   │   ├── ...  # Other files in admin_views
│   ├── ...  # Other Python files related to the views

When I attempt to open the generated .exe, I get the following error:

ModuleNotFoundError: No module named 'views'

The application starts with main.py, which imports the MainApp class from views/main_app.py. This file interacts with other files and resources within the views folder and other parts of the project.

I used the following PyInstaller command to convert my main.py file into an executable:

pyinstaller --name "MyProject" --onefile --windowed --icon=resources/icon.ico main.py

After running the .exe, I get an error message box that says:

ModuleNotFoundError: No module named 'views'

This suggests that PyInstaller is not including the views folder (or other assets) in the final build.

Observations

  • The application works perfectly when I run it using python main.py.

  • I suspect PyInstaller is not bundling all the files, folders, and dependencies in my project.

  • The views folder contains multiple Python files, and main.py relies on the MainApp class from views/main_app.py.

  • There’s also an admin_views folder inside views, containing additional modules that are required.

Questions

  1. How do I ensure PyInstaller includes all the files, folders, and assets in my project during the conversion process?

  2. Is there a specific PyInstaller configuration or approach for multi-file projects like mine?

  3. Should I be using --onefile, or is there a better approach to handle this kind of project?

Any guidance or solutions to successfully bundle my entire project into an .exe would be greatly appreciated!


I used the following PyInstaller command to generate the executable:

pyinstaller --name "MyProject" --onefile --windowed --icon=resources/icon.ico main.py

After running the .exe, I encountered the error mentioned above.

Additionally, I tried the following to resolve the issue:

  1. Added __init__.py files to the relevant folders to make them proper Python modules.

  2. Checked if PyInstaller automatically includes the folders like views and admin_views.

  3. Ran PyInstaller with the --paths flag to explicitly include the views folder

What I Am Expecting

I want to create a standalone .exe file that includes all the files and dependencies in my project, such that the application behaves the same way as it does when I run python main.py. Specifically:

  1. The .exe should find and use the views and admin_views modules without errors.

  2. All assets, like the database (staff.db) and resources (photos folder), should be packaged within the executable.


Solution

  • # MyProject.spec
    
    # -*- mode: python ; coding: utf-8 -*-
    
    block_cipher = None
    
    a = Analysis(
        ['main.py'],
        pathex=['.'],
        binaries=[],
        datas=[('photos', 'photos'), ('staff.db', '.')],
        hiddenimports=[],
        hookspath=[],
        runtime_hooks=[],
        excludes=[],
        win_no_prefer_redirects=False,
        win_private_assemblies=False,
        cipher=block_cipher,
    )
    pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
    
    exe = EXE(
        pyz,
        a.scripts,
        [],
        exclude_binaries=True,
        name='MyProject',
        debug=False,
        bootloader_ignore_signals=False,
        strip=False,
        upx=True,
        upx_exclude=[],
        runtime_tmpdir=None,
        console=False,
        icon='resources/icon.ico',
    )
    coll = COLLECT(
        exe,
        a.binaries,
        a.zipfiles,
        a.datas,
        strip=False,
        upx=True,
        upx_exclude=[],
        name='MyProject',
    )