| Server IP : 123.56.80.60 / Your IP : 216.73.216.78 Web Server : Apache/2.4.54 (Win32) OpenSSL/1.1.1s PHP/7.4.33 mod_fcgid/2.3.10-dev System : Windows NT iZhx3sob14hnz7Z 10.0 build 14393 (Windows Server 2016) i586 User : SYSTEM ( 0) PHP Version : 7.4.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : OFF | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : C:/Program Files/python/Lib/site-packages/PyInstaller/utils/hooks/ |
Upload File : |
# ----------------------------------------------------------------------------
# Copyright (c) 2005-2020, PyInstaller Development Team.
#
# Distributed under the terms of the GNU General Public License (version 2
# or later) with exception for distributing the bootloader.
#
# The full license is in the file COPYING.txt, distributed with this software.
#
# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)
#-----------------------------------------------------------------------------
import os
import sys
import json
import glob
from ..hooks import eval_statement, exec_statement, get_homebrew_path, \
get_module_file_attribute
from PyInstaller.depend.bindepend import getImports, getfullnameof
from ... import log as logging
from ...compat import is_py3, is_win, is_darwin, is_linux
from ...utils import misc
logger = logging.getLogger(__name__)
# Qt5LibraryInfo
# --------------
# This class uses introspection to determine the location of Qt5 files. This is
# essential to deal with the many variants of the PyQt5 package, each of which
# places files in a different location. Therefore, this class provides all
# members of `QLibraryInfo <http://doc.qt.io/qt-5/qlibraryinfo.html>`_.
class Qt5LibraryInfo:
def __init__(self, namespace):
if namespace not in ['PyQt5', 'PySide2']:
raise Exception('Invalid namespace: {0}'.format(namespace))
self.namespace = namespace
self.is_PyQt5 = namespace == 'PyQt5'
# Initialize most of this class only when values are first requested from
# it.
def __getattr__(self, name):
if 'version' not in self.__dict__:
# Get library path information from Qt. See QLibraryInfo_.
json_str = exec_statement("""
import sys
# exec_statement only captures stdout. If there are
# errors, capture them to stdout so they can be displayed to the
# user. Do this early, in case PyQt5 imports produce stderr
# output.
sys.stderr = sys.stdout
import json
try:
from %s.QtCore import QLibraryInfo, QCoreApplication
except:
print('False')
else:
# QLibraryInfo isn't always valid until a QCoreApplication is
# instantiated.
app = QCoreApplication(sys.argv)
paths = [x for x in dir(QLibraryInfo) if x.endswith('Path')]
location = {x: QLibraryInfo.location(getattr(QLibraryInfo, x))
for x in paths}
try:
version = QLibraryInfo.version().segments()
except AttributeError:
version = []
print(json.dumps({
'isDebugBuild': QLibraryInfo.isDebugBuild(),
'version': version,
'location': location,
}))
""" % self.namespace)
try:
qli = json.loads(json_str)
except Exception as e:
logger.warning('Cannot read QLibraryInfo output: raised %s when '
'decoding:\n%s', str(e), json_str)
qli = False
# If PyQt5/PySide2 can't be imported, record that.
if not qli:
self.version = None
else:
for k, v in qli.items():
setattr(self, k, v)
return getattr(self, name)
else:
raise AttributeError
# Provide single instances of this class to avoid each hook constructing its own.
pyqt5_library_info = Qt5LibraryInfo('PyQt5')
pyside2_library_info = Qt5LibraryInfo('PySide2')
def qt_plugins_dir(namespace):
"""
Return list of paths searched for plugins.
:param namespace: Import namespace, i.e., PyQt4, PyQt5, PySide, or PySide2
:return: Plugin directory paths
"""
if namespace not in ['PyQt4', 'PyQt5', 'PySide', 'PySide2']:
raise Exception('Invalid namespace: {0}'.format(namespace))
if namespace == 'PyQt5':
paths = [pyqt5_library_info.location['PluginsPath']]
elif namespace == 'PySide2':
paths = [pyside2_library_info.location['PluginsPath']]
else:
paths = eval_statement("""
from {0}.QtCore import QCoreApplication;
app = QCoreApplication([]);
# For Python 2 print would give <PyQt4.QtCore.QStringList
# object at 0x....>", so we need to convert each element separately
str = getattr(__builtins__, 'unicode', str); # for Python 2
print([str(p) for p in app.libraryPaths()])
""".format(namespace))
if not paths:
raise Exception('Cannot find {0} plugin directories'.format(namespace))
else:
valid_paths = []
for path in paths:
if os.path.isdir(path):
valid_paths.append(str(path)) # must be 8-bit chars for one-file builds
qt_plugin_paths = valid_paths
if not qt_plugin_paths:
raise Exception("""
Cannot find existing {0} plugin directories
Paths checked: {1}
""".format(namespace, ", ".join(paths)))
return qt_plugin_paths
def qt_plugins_binaries(plugin_type, namespace):
"""
Return list of dynamic libraries formatted for mod.binaries.
:param plugin_type: Plugin to look for
:param namespace: Import namespace, i.e., PyQt4, PyQt5, PySide, or PySide2
:return: Plugin directory path corresponding to the given plugin_type
"""
if namespace not in ['PyQt4', 'PyQt5', 'PySide', 'PySide2']:
raise Exception('Invalid namespace: {0}'.format(namespace))
pdir = qt_plugins_dir(namespace=namespace)
files = []
for path in pdir:
files.extend(misc.dlls_in_dir(os.path.join(path, plugin_type)))
# Windows:
#
# dlls_in_dir() grabs all files ending with ``*.dll``, ``*.so`` and
# ``*.dylib`` in a certain directory. On Windows this would grab debug
# copies of Qt plugins, which then causes PyInstaller to add a dependency on
# the Debug CRT *in addition* to the release CRT.
#
# Since on Windows debug copies of Qt4 plugins end with "d4.dll" and Qt5
# plugins end with "d.dll" we filter them out of the list.
if is_win and (namespace in ['PyQt4', 'PySide']):
files = [f for f in files if not f.endswith("d4.dll")]
elif is_win and namespace in ['PyQt5', 'PySide2']:
files = [f for f in files if not f.endswith("d.dll")]
logger.debug("Found plugin files %s for plugin %s", files, plugin_type)
if namespace in ['PyQt4', 'PySide']:
plugin_dir = 'qt4_plugins'
elif namespace == 'PyQt5':
plugin_dir = os.path.join('PyQt5', 'Qt', 'plugins')
else:
plugin_dir = os.path.join('PySide2', 'plugins')
dest_dir = os.path.join(plugin_dir, plugin_type)
binaries = [(f, dest_dir) for f in files]
return binaries
def qt_menu_nib_dir(namespace):
"""
Return path to Qt resource dir qt_menu.nib on OSX only.
:param namespace: Import namespace, i.e., PyQt4, PyQt5, PySide, or PySide2
:return: Directory containing qt_menu.nib for specified namespace
"""
if namespace not in ['PyQt4', 'PyQt5', 'PySide', 'PySide2']:
raise Exception('Invalid namespace: {0}'.format(namespace))
menu_dir = None
path = exec_statement("""
from {0}.QtCore import QLibraryInfo
path = QLibraryInfo.location(QLibraryInfo.LibrariesPath)
str = getattr(__builtins__, 'unicode', str) # for Python 2
print(str(path))
""".format(namespace))
anaconda_path = os.path.join(sys.exec_prefix, "python.app", "Contents",
"Resources")
paths = [os.path.join(path, 'Resources'),
os.path.join(path, 'QtGui.framework', 'Resources'), anaconda_path]
for location in paths:
# Check directory existence
path = os.path.join(location, 'qt_menu.nib')
if os.path.exists(path):
menu_dir = path
logger.debug('Found qt_menu.nib for %s at %s', namespace, path)
break
if not menu_dir:
raise Exception("""
Cannot find qt_menu.nib for {0}
Path checked: {1}
""".format(namespace, ", ".join(paths)))
return menu_dir
def get_qmake_path(version=''):
"""
Try to find the path to qmake with version given by the argument as a
string.
:param version: qmake version
"""
import subprocess
# Use QT[45]DIR if specified in the environment
if 'QT5DIR' in os.environ and version[0] == '5':
logger.debug('Using $QT5DIR/bin as qmake path')
return os.path.join(os.environ['QT5DIR'], 'bin', 'qmake')
if 'QT4DIR' in os.environ and version[0] == '4':
logger.debug('Using $QT4DIR/bin as qmake path')
return os.path.join(os.environ['QT4DIR'], 'bin', 'qmake')
# try the default $PATH
dirs = ['']
# try homebrew paths
for formula in ('qt', 'qt5'):
homebrewqtpath = get_homebrew_path(formula)
if homebrewqtpath:
dirs.append(homebrewqtpath)
for directory in dirs:
try:
qmake = os.path.join(directory, 'bin', 'qmake')
versionstring = subprocess.check_output([qmake, '-query',
'QT_VERSION']).strip()
if is_py3:
# version string is probably just ASCII
versionstring = versionstring.decode('utf8')
if versionstring.find(version) == 0:
logger.debug('Found qmake version "%s" at "%s".',
versionstring, qmake)
return qmake
except (OSError, subprocess.CalledProcessError):
pass
logger.debug('Could not find qmake matching version "%s".', version)
return None
# Qt deployment approach
# ----------------------
# This is the core of PyInstaller's approach to Qt deployment. It's based on:
#
# - Discovering the location of Qt5 libraries by introspection, using
# Qt5LibraryInfo_. This provides compatibility with many variants of Qt5
# (conda, self-compiled, provided by a Linux distro, etc.) and many versions
# of Qt5, all of which vary in the location of Qt5 files.
# - Placing all frozen PyQt5/Qt5 files in a standard subdirectory layout, which
# matches the layout of the PyQt5 wheel on PyPI. This is necessary to support
# Qt5 installs which are not in a subdirectory of the PyQt5 wrappers. See
# ``loader/rthooks/pyi_rth_qt5.py`` for the use of environment variables to
# establish this layout.
# - Emitting warnings on missing QML and translation files which some
# installations don't have.
# - Determining additional files needed for deployment by following the Qt
# deployment process using `_qt_dynamic_dependencies_dict`_ and
# add_qt5_dependencies_.
#
# _qt_dynamic_dependencies_dict
# -----------------------------
# This dictionary provides dynamics dependencies (plugins and translations) that
# can't be discovered using ``getImports``. It was built by combining
# information from:
#
# - Qt `deployment <http://doc.qt.io/qt-5/deployment.html>`_ docs. Specifically:
#
# - The `deploying Qt for Linux/X11 <http://doc.qt.io/qt-5/linux-deployment.html#qt-plugins>`_
# page specifies including the Qt Platform Abstraction (QPA) plugin,
# ``libqxcb.so``. There's little other guidance provided.
# - The `Qt for Windows - Deployment <http://doc.qt.io/qt-5/windows-deployment.html#creating-the-application-package>`_
# page likewise specifies the ``qwindows.dll`` QPA. This is found by the
# dependency walker, so it doesn't need to explicitly specified.
#
# - For dynamic OpenGL applications, the ``libEGL.dll``,
# ``libGLESv2.dll``, ``d3dcompiler_XX.dll`` (the XX is a version
# number), and ``opengl32sw.dll`` libraries are also needed.
# - If Qt was configured to use ICU, the ``icudtXX.dll``,
# ``icuinXX.dll``, and ``icuucXX.dll`` libraries are needed.
#
# These are included by ``hook-PyQt5.py``.
#
# - The `Qt for macOS - Deployment <http://doc.qt.io/qt-5/osx-deployment.html#qt-plugins>`_
# page specifies the ``libqcocoa.dylib`` QPA, but little else. The
# `Mac deployment tool <http://doc.qt.io/qt-5/osx-deployment.html#the-mac-deployment-tool>`_
# provides the following rules:
#
# - The platform plugin is always deployed.
# - The image format plugins are always deployed.
# - The print support plugin is always deployed.
# - SQL driver plugins are deployed if the application uses the Qt SQL
# module.
# - Script plugins are deployed if the application uses the Qt Script
# module.
# - The SVG icon plugin is deployed if the application uses the Qt SVG
# module.
# - The accessibility plugin is always deployed.
#
# - Per the `Deploying QML Applications <http://doc.qt.io/qt-5/qtquick-deployment.html>`_
# page, QML-based applications need the ``qml/`` directory available.
# This is handled by ``hook-PyQt5.QtQuick.py``.
# - Per the `Deploying Qt WebEngine Applications <https://doc.qt.io/qt-5.10/qtwebengine-deploying.html>`_
# page, deployment may include:
#
# - Libraries (handled when PyInstaller following dependencies).
# - QML imports (if Qt Quick integration is used).
# - Qt WebEngine process, which should be located at
# ``QLibraryInfo::location(QLibraryInfo::LibraryExecutablesPath)``
# for Windows and Linux, and in ``.app/Helpers/QtWebEngineProcess``
# for Mac.
# - Resources: the files listed in deployWebEngineCore_.
# - Translations: on macOS: ``.app/Content/Resources``; on Linux and
# Windows: ``qtwebengine_locales`` directory in the directory
# specified by ``QLibraryInfo::location(QLibraryInfo::TranslationsPath)``.
# - Audio and video codecs: Probably covered if Qt5Multimedia is
# referenced?
#
# This is handled by ``hook-PyQt5.QtWebEngineWidgets.py``.
#
# - Since `QAxContainer <http://doc.qt.io/qt-5/activeqt-index.html>`_ is a
# statically-linked library, it doesn't need any special handling.
#
# - Sources for the `Windows Deployment Tool <http://doc.qt.io/qt-5/windows-deployment.html#the-windows-deployment-tool>`_
# show more detail:
#
# - The `PluginModuleMapping struct <https://code.woboq.org/qt5/qttools/src/windeployqt/main.cpp.html#PluginModuleMapping>`_
# and the following ``pluginModuleMappings`` global provide a mapping
# between a plugin directory name and an `enum of Qt plugin names
# <https://code.woboq.org/qt5/qttools/src/windeployqt/main.cpp.html#QtModule>`_.
# - The `QtModuleEntry struct <https://code.woboq.org/qt5/qttools/src/windeployqt/main.cpp.html#QtModuleEntry>`_
# and ``qtModuleEntries`` global connect this enum to the name of the Qt5
# library it represents and to the translation files this library
# requires. (Ignore the ``option`` member -- it's just for command-line
# parsing.)
#
# Manually combining these two provides a mapping of Qt library names to the
# translation and plugin(s) needed by the library. The process is: take the
# key of the dict below from ``QtModuleEntry.libraryName``, but make it
# lowercase (since Windows files will be normalized to lowercase). The
# ``QtModuleEntry.translation`` provides the ``translation_base``. Match the
# ``QtModuleEntry.module`` with ``PluginModuleMapping.module`` to find the
# ``PluginModuleMapping.directoryName`` for the required plugin(s).
#
# - The `deployWebEngineCore <https://code.woboq.org/qt5/qttools/src/windeployqt/main.cpp.html#_ZL19deployWebEngineCoreRK4QMapI7QStringS0_ERK7OptionsbPS0_>`_
# function copies the following files from ``resources/``, and also copies
# the web engine process executable.
#
# - ``icudtl.dat``
# - ``qtwebengine_devtools_resources.pak``
# - ``qtwebengine_resources.pak``
# - ``qtwebengine_resources_100p.pak``
# - ``qtwebengine_resources_200p.pak``
#
# - Sources for the `Mac deployment tool`_ are less helpful. The `deployPlugins
# <https://code.woboq.org/qt5/qttools/src/macdeployqt/shared/shared.cpp.html#_Z13deployPluginsRK21ApplicationBundleInfoRK7QStringS2_14DeploymentInfob>`_
# function seems to:
#
# - Always include ``platforms/libqcocoa.dylib``.
# - Always include ``printsupport/libcocoaprintersupport.dylib``
# - Include ``bearer/`` if ``QtNetwork`` is included (and some other
# condition I didn't look up).
# - Always include ``imageformats/``, except for ``qsvg``.
# - Include ``imageformats/qsvg`` if ``QtSvg`` is included.
# - Always include ``iconengines/``.
# - Include ``sqldrivers/`` if ``QtSql`` is included.
# - Include ``mediaservice/`` and ``audio/`` if ``QtMultimedia`` is
# included.
#
# The always includes will be handled by ``hook-PyQt5.py`` or
# ``hook-PySide2.py``; optional includes are already covered by the dict
# below.
#
_qt_dynamic_dependencies_dict = {
## "lib_name": (.hiddenimports, translations_base, zero or more plugins...)
"qt5bluetooth": (".QtBluetooth", None, ), # noqa: E241,E202
"qt5concurrent": (None, "qtbase", ),
"qt5core": (".QtCore", "qtbase", ),
# This entry generated by hand -- it's not present in the Windows deployment tool sources.
"qtdbus": (".QtDBus", None, ),
"qt5declarative": (None, "qtquick1", "qml1tooling"),
"qt5designer": (".QtDesigner", None, ),
"qt5designercomponents": (None, None, ),
"enginio": (None, None, ),
"qt5gamepad": (None, None, "gamepads"),
# Note: The ``platformthemes`` plugin is for Linux only, and comes from earlier PyInstaller code in ``hook-PyQt5.QtGui.py``. The ``styles`` plugin comes from the suggestion at https://github.com/pyinstaller/pyinstaller/issues/2156.
"qt5gui": (".QtGui", "qtbase", "accessible", "iconengines", "imageformats", "platforms", "platforminputcontexts", "platformthemes", "styles"),
"qt5help": (".QtHelp", "qt_help", ),
# This entry generated by hand -- it's not present in the Windows deployment tool sources.
"qt5macextras": (".QtMacExtras", None, ),
"qt5multimedia": (".QtMultimedia", "qtmultimedia", "audio", "mediaservice", "playlistformats"),
"qt5multimediawidgets": (".QtMultimediaWidgets", "qtmultimedia", ),
"qt5multimediaquick_p": (None, "qtmultimedia", ),
"qt5network": (".QtNetwork", "qtbase", "bearer"),
"qt5nfc": (".QtNfc", None, ),
## These added manually for Linux.
"qt5opengl": (".QtOpenGL", None, "xcbglintegrations", "egldeviceintegrations"),
"qt5positioning": (".QtPositioning", None, "position"),
"qt5printsupport": (".QtPrintSupport", None, "printsupport"),
"qt5qml": (".QtQml", "qtdeclarative", ),
"qmltooling": (None, None, "qmltooling"),
## These added manually for Linux.
"qt5quick": (".QtQuick", "qtdeclarative", "scenegraph", "qmltooling", "xcbglintegrations", "egldeviceintegrations"),
"qt5quickparticles": (None, None, ),
"qt5quickwidgets": (".QtQuickWidgets", None, ),
"qt5script": (None, "qtscript", ),
"qt5scripttools": (None, "qtscript", ),
"qt5sensors": (".QtSensors", None, "sensors", "sensorgestures"),
"qt5serialport": (".QtSerialPort", "qtserialport", ),
"qt5sql": (".QtSql", "qtbase", "sqldrivers"),
"qt5svg": (".QtSvg", None, ),
"qt5test": (".QtTest", "qtbase", ),
"qt5webkit": (None, None, ),
"qt5webkitwidgets": (None, None, ),
"qt5websockets": (".QtWebSockets", None, ),
"qt5widgets": (".QtWidgets", "qtbase", ),
"qt5winextras": (".QtWinExtras", None, ),
"qt5xml": (".QtXml", "qtbase", ),
"qt5xmlpatterns": (".QXmlPatterns", "qtxmlpatterns", ),
## These added manually for Linux.
"qt5webenginecore": (".QtWebEngineCore", None, "qtwebengine", "xcbglintegrations", "egldeviceintegrations"),
"qt5webengine": (".QtWebEngine", "qtwebengine", "qtwebengine"),
"qt5webenginewidgets": (".QtWebEngineWidgets", None, "qtwebengine"),
"qt53dcore": (None, None, ),
"qt53drender": (None, None, "sceneparsers", "renderplugins", "geometryloaders"),
"qt53dquick": (None, None, ),
"qt53dquickRender": (None, None, ),
"qt53dinput": (None, None, ),
"qt5location": (".QtLocation", None, "geoservices"),
"qt5webchannel": (".QtWebChannel", None, ),
"qt5texttospeech": (None, None, "texttospeech"),
"qt5serialbus": (None, None, "canbus"),
}
# add_qt5_dependencies
# --------------------
# Find the Qt dependencies based on the hook name of a PyQt5 hook. Returns
# (hiddenimports, binaries, datas). Typical usage: ``hiddenimports, binaries,
# datas = add_qt5_dependencies(__file__)``.
def add_qt5_dependencies(hook_file):
# Accumulate all dependencies in a set to avoid duplicates.
hiddenimports = set()
translations_base = set()
plugins = set()
# Find the module underlying this Qt hook: change
# ``/path/to/hook-PyQt5.blah.py`` to ``PyQt5.blah``.
hook_name, hook_ext = os.path.splitext(os.path.basename(hook_file))
assert hook_ext.startswith('.py')
assert hook_name.startswith('hook-')
module_name = hook_name[5:]
namespace = module_name.split('.')[0]
if namespace not in ('PyQt5', 'PySide2'):
raise Exception('Invalid namespace: {0}'.format(namespace))
is_PyQt5 = namespace == 'PyQt5'
# Exit if the requested library can't be imported.
if ((is_PyQt5 and not pyqt5_library_info.version) or
(not is_PyQt5 and not pyside2_library_info.version)):
return [], [], []
# Look up the module returned by this import.
module = get_module_file_attribute(module_name)
logger.debug('add_qt5_dependencies: Examining %s, based on hook of %s.',
module, hook_file)
# Walk through all the static dependencies of a dynamically-linked library
# (``.so``/``.dll``/``.dylib``).
imports = set(getImports(module))
while imports:
imp = imports.pop()
# On Windows, find this library; other platforms already provide the
# full path.
if is_win:
imp = getfullnameof(imp,
# First, look for Qt binaries in the local Qt install.
pyqt5_library_info.location['BinariesPath'] if is_PyQt5 else
pyside2_library_info.location['BinariesPath']
)
# Strip off the extension and ``lib`` prefix (Linux/Mac) to give the raw
# name. Lowercase (since Windows always normalized names to lowercase).
lib_name = os.path.splitext(os.path.basename(imp))[0].lower()
# Linux libraries sometimes have a dotted version number --
# ``libfoo.so.3``. It's now ''libfoo.so``, but the ``.so`` must also be
# removed.
if is_linux and os.path.splitext(lib_name)[1] == '.so':
lib_name = os.path.splitext(lib_name)[0]
if lib_name.startswith('lib'):
lib_name = lib_name[3:]
# Mac: rename from ``qt`` to ``qt5`` to match names in Windows/Linux.
if is_darwin and lib_name.startswith('qt'):
lib_name = 'qt5' + lib_name[2:]
logger.debug('add_qt5_dependencies: raw lib %s -> parsed lib %s',
imp, lib_name)
# Follow only Qt dependencies.
if lib_name in _qt_dynamic_dependencies_dict:
# Follow these to find additional dependencies.
logger.debug('add_qt5_dependencies: Import of %s.', imp)
imports.update(getImports(imp))
# Look up which plugins and translations are needed. Avoid Python
# 3-only syntax, since the Python 2.7 parser will raise an
# exception. The original statment was:
## (lib_name_hiddenimports, lib_name_translations_base,
## *lib_name_plugins) = _qt_dynamic_dependencies_dict[lib_name]
dd = _qt_dynamic_dependencies_dict[lib_name]
lib_name_hiddenimports, lib_name_translations_base = dd[:2]
lib_name_plugins = dd[2:]
# Add them in.
if lib_name_hiddenimports:
hiddenimports.update([namespace + lib_name_hiddenimports])
plugins.update(lib_name_plugins)
if lib_name_translations_base:
translations_base.update([lib_name_translations_base])
# Change plugins into binaries.
binaries = []
for plugin in plugins:
more_binaries = qt_plugins_binaries(plugin, namespace=namespace)
binaries.extend(more_binaries)
# Change translation_base to datas.
tp = (
pyqt5_library_info.location['TranslationsPath'] if is_PyQt5
else pyside2_library_info.location['TranslationsPath']
)
datas = []
for tb in translations_base:
src = os.path.join(tp, tb + '_*.qm')
# Not all PyQt5 installations include translations. See
# https://github.com/pyinstaller/pyinstaller/pull/3229#issuecomment-359479893
# and
# https://github.com/pyinstaller/pyinstaller/issues/2857#issuecomment-368744341.
if glob.glob(src):
datas.append((
src, os.path.join(
# The PySide2 Windows wheels place translations in a
# different location.
namespace, '' if not is_PyQt5 and is_win else 'Qt',
'translations'
)
))
else:
logger.warning('Unable to find Qt5 translations %s. These '
'translations were not packaged.', src)
# Change hiddenimports to a list.
hiddenimports = list(hiddenimports)
logger.debug('add_qt5_dependencies: imports from %s:\n'
' hiddenimports = %s\n'
' binaries = %s\n'
' datas = %s',
hook_name, hiddenimports, binaries, datas)
return hiddenimports, binaries, datas
def find_all_or_none(globs_to_include, num_files, qt_library_info):
"""
globs_to_include is a list of file name globs
If the number of found files does not match num_files
then no files will be included.
"""
# This function is required because CI is failing to include libEGL. The
# error in AppVeyor is::
#
# [2312] LOADER: Running pyi_lib_PyQt5-uic.py
# Failed to load libEGL (Access is denied.)
# More info: https://github.com/pyinstaller/pyinstaller/pull/3568
#
# Since old PyQt5 wheels do not include d3dcompiler_4?.dll, libEGL.dll and
# libGLESv2.dll will not be included for PyQt5 builds during CI.
to_include = []
dst_dll_path = '.'
for dll in globs_to_include:
dll_path = os.path.join(qt_library_info.location[
'BinariesPath' if qt_library_info.is_PyQt5 else 'PrefixPath'
], dll)
dll_file_paths = glob.glob(dll_path)
for dll_file_path in dll_file_paths:
to_include.append((dll_file_path, dst_dll_path))
if len(to_include) == num_files:
return to_include
return []
# Gather required Qt binaries, but only if all binaries in a group exist.
def get_qt_binaries(qt_library_info):
binaries = []
angle_files = ['libEGL.dll', 'libGLESv2.dll', 'd3dcompiler_??.dll']
binaries += find_all_or_none(angle_files, 3, qt_library_info)
opengl_software_renderer = ['opengl32sw.dll']
binaries += find_all_or_none(opengl_software_renderer, 1, qt_library_info)
# Include ICU files, if they exist.
# See the "Deployment approach" section in ``PyInstaller/utils/hooks/qt.py``.
icu_files = ['icudt??.dll', 'icuin??.dll', 'icuuc??.dll']
binaries += find_all_or_none(icu_files, 3, qt_library_info)
return binaries
__all__ = ('qt_plugins_dir', 'qt_plugins_binaries', 'qt_menu_nib_dir',
'get_qmake_path')