Search code examples
pythonsvgpyqtpyqt5py2exe

Certain icon files do not display in a frozen PyQt5 application


I have been working on a PyQt5 GUI application that we'd like to share widely, so I've been attempting to get everything packaged using py2exe. All of the program functionality seems to be working fine in package form, with the lone exception that some custom SVG icons are not displayed.

In searching for answers to my problem, I discovered PyQt's imageformats plugins thanks to this answer. Including imageformats in my distribution did not alleviate the problem, however.

Here is the relevant content from my setup file:

import sys
import os
from setuptools import setup
import py2exe

VERSION = '1.0.0'

includes = [
    "PyQt5",
    "PyQt5.QtCore",
    "PyQt5.QtGui",
    "PyQt5.sip",
]

PYTHON_DIRECTORY = sys.exec_prefix
PYQT_PATH = os.path.join(
    PYTHON_DIRECTORY,
    'Lib',
    'site-packages',
    'PyQt5',
    'Qt5'
)

datafiles = [
    ("platforms", [os.path.join(PYQT_PATH, 'plugins', 'platforms', 'qwindows.dll')]),
    ("imageformats", [os.path.join(PYQT_PATH, 'plugins', 'imageformats', format) for format in os.listdir(os.path.join(PYQT_PATH, 'plugins', 'imageformats'))]),
    (
        "", [
            r"c:\windows\syswow64\MSVCP100.dll",
            r"c:\windows\syswow64\MSVCR100.dll",
            os.path.join(PYQT_PATH, 'bin', 'Qt5Widgets.dll'),
            os.path.join(PYQT_PATH, 'bin', 'Qt5Core.dll'),
            os.path.join(PYQT_PATH, 'bin', 'Qt5Gui.dll'),
        ]
    )
]

setup(
    name='application',
    version=VERSION,
    packages=['model', 'view'],
    url='',
    license='',
    windows=[{"script": "main.py"}],
    scripts=['main.py'],
    data_files=datafiles,
    install_requires=[],
    options={
        "py2exe":{
            "includes": includes,
        }
    }
)

Solution

  • SVG icons in PyQt5 require Qt5Svg.dll in addition to the imageformats plugins in order to be displayed. Adding the following to setup.py should fix the issue:

    datafiles = [
        ...
        (
            "", [
                ...
                os.path.join(PYQT_PATH, 'bin', 'Qt5Svg.dll'),
            ]
        )
    ]
    

    Useful tip for further py2exe debugging: Sysinternals ProcMon is super useful for discovering missing DLLs. Simply filter on your application's name and look for similar "NAME NOT FOUND" entries: Sample usage of procmon.exe, which shows the missing Qt5Svg.dll file