mit neuen venv und exe-Files
This commit is contained in:
438
venv3_12/Lib/site-packages/cx_Freeze/hooks/_qthooks.py
Normal file
438
venv3_12/Lib/site-packages/cx_Freeze/hooks/_qthooks.py
Normal file
@@ -0,0 +1,438 @@
|
||||
"""A collection of functions which are the base to hooks for PyQt5, PyQt6,
|
||||
PySide2 and PySide6.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from contextlib import suppress
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from cx_Freeze._compat import IS_CONDA, IS_MACOS, IS_MINGW, IS_WINDOWS
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from cx_Freeze.finder import ModuleFinder
|
||||
from cx_Freeze.module import Module
|
||||
|
||||
|
||||
def _qt_implementation(module: Module) -> str:
|
||||
"""Helper function to get the name of the Qt implementation."""
|
||||
return module.name.split(".")[0]
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def _qt_libraryinfo_paths(name: str) -> dict[str, tuple[Path, Path]]:
|
||||
"""Cache the QtCore library paths."""
|
||||
try:
|
||||
qtcore = __import__(name, fromlist=["QtCore"]).QtCore
|
||||
except RuntimeError:
|
||||
print("WARNING: Tried to load multiple incompatible Qt ", end="")
|
||||
print("wrappers. Some incorrect files may be copied.")
|
||||
return {}
|
||||
|
||||
# get paths from QLibraryInfo
|
||||
source_paths: dict[str, Path] = {}
|
||||
lib = qtcore.QLibraryInfo
|
||||
major_version = lib.version().majorVersion()
|
||||
if major_version == 6:
|
||||
if hasattr(lib.LibraryPath, "__members__"):
|
||||
for key, value in lib.LibraryPath.__members__.items():
|
||||
source_paths[key] = Path(lib.path(value))
|
||||
else:
|
||||
for key, value in lib.__dict__.items():
|
||||
if isinstance(value, lib.LibraryPath):
|
||||
source_paths[key] = Path(lib.path(value))
|
||||
else:
|
||||
for key, value in lib.__dict__.items():
|
||||
if isinstance(value, (lib.LibraryLocation, int)):
|
||||
source_paths[key] = Path(lib.location(value))
|
||||
qt_root_dir = Path(qtcore.__file__).parent
|
||||
|
||||
# if QLibraryInfo has incomplete information
|
||||
if not source_paths.get("PluginsPath"):
|
||||
# Qt Plugins can be in a plugins directory next to the Qt libraries
|
||||
plugins_path = qt_root_dir / "plugins"
|
||||
if not plugins_path.exists():
|
||||
plugins_path = qt_root_dir / "Qt5" / "plugins" # PyQt5 5.15.4
|
||||
# or in a special location in conda-forge
|
||||
if not plugins_path.exists():
|
||||
plugins_path = Path(sys.base_prefix, "Library", "plugins")
|
||||
# default location
|
||||
if not plugins_path.exists():
|
||||
plugins_path = qt_root_dir / "Qt" / "plugins"
|
||||
source_paths["PluginsPath"] = plugins_path
|
||||
source_paths.setdefault("PrefixPath", source_paths["PluginsPath"].parent)
|
||||
prefix_path = source_paths["PrefixPath"]
|
||||
source_paths.setdefault("DataPath", prefix_path)
|
||||
source_paths.setdefault("LibrariesPath", prefix_path / "lib")
|
||||
source_paths.setdefault("SettingsPath", ".")
|
||||
if name in ("PySide2", "PySide6") and IS_WINDOWS and not IS_CONDA:
|
||||
source_paths["BinariesPath"] = prefix_path
|
||||
source_paths["LibraryExecutablesPath"] = prefix_path
|
||||
|
||||
# set the target paths
|
||||
data: dict[str, tuple[Path, Path]] = {}
|
||||
target_base = Path("lib", name)
|
||||
with suppress(ValueError):
|
||||
target_base = target_base / prefix_path.relative_to(qt_root_dir)
|
||||
if name == "PyQt5" and prefix_path.name != "Qt5":
|
||||
# conda pyqt
|
||||
target_base = target_base / "Qt5"
|
||||
|
||||
# set some defaults or use relative path
|
||||
for key, source in source_paths.items():
|
||||
if key == "SettingsPath": # Check for SettingsPath first
|
||||
target = Path("Contents/Resources" if IS_MACOS else ".")
|
||||
elif name in ("PySide2", "PySide6") and IS_WINDOWS and not IS_CONDA:
|
||||
target = target_base / source.relative_to(prefix_path)
|
||||
elif key in ("ArchDataPath", "DataPath", "PrefixPath"):
|
||||
target = target_base
|
||||
elif key == "BinariesPath":
|
||||
target = target_base / "bin"
|
||||
elif key == "LibrariesPath":
|
||||
target = target_base / "lib"
|
||||
elif key == "LibraryExecutablesPath":
|
||||
target = target_base / (
|
||||
"bin" if IS_WINDOWS or IS_MINGW else "libexec"
|
||||
)
|
||||
elif key == "PluginsPath":
|
||||
target = target_base / "plugins"
|
||||
elif key == "TranslationsPath":
|
||||
target = target_base / "translations"
|
||||
elif source == Path("."):
|
||||
target = target_base
|
||||
else:
|
||||
target = target_base / source.relative_to(prefix_path)
|
||||
data[key] = source.resolve(), target
|
||||
|
||||
# debug
|
||||
if os.environ.get("QT_DEBUG"):
|
||||
print("QLibraryInfo:")
|
||||
for key, (source, target) in sorted(data.items()):
|
||||
print(" ", key, source, "->", target)
|
||||
return data
|
||||
|
||||
|
||||
def get_qt_paths(name: str, variable: str) -> tuple[Path, Path]:
|
||||
"""Helper function to get the source and target path of Qt variable."""
|
||||
libraryinfo_paths = _qt_libraryinfo_paths(name)
|
||||
source_path, target_path = libraryinfo_paths[variable]
|
||||
return (source_path, target_path)
|
||||
|
||||
|
||||
def _get_qt_files(
|
||||
name: str, variable: str, arg: str
|
||||
) -> list[tuple[Path, Path]]:
|
||||
"""Helper function to get Qt plugins, resources, translations, etc."""
|
||||
source_path, target_path = get_qt_paths(name, variable)
|
||||
if source_path.joinpath(arg).is_dir():
|
||||
source_path = source_path / arg
|
||||
target_path = target_path / arg
|
||||
pattern = "*"
|
||||
else:
|
||||
pattern = arg
|
||||
return [
|
||||
(source, target_path / source.name)
|
||||
for source in source_path.glob(pattern)
|
||||
]
|
||||
|
||||
|
||||
def get_qt_plugins_paths(name: str, plugins: str) -> list[tuple[Path, Path]]:
|
||||
"""Helper function to get a list of source and target paths of Qt plugins,
|
||||
indicated to be used in include_files.
|
||||
"""
|
||||
return _get_qt_files(name, "PluginsPath", plugins)
|
||||
|
||||
|
||||
def copy_qt_files(
|
||||
finder: ModuleFinder, name: str, variable: str, arg: str
|
||||
) -> None:
|
||||
"""Helper function to copy Qt plugins, resources, translations, etc."""
|
||||
for source_path, target_path in _get_qt_files(name, variable, arg):
|
||||
finder.include_files(source_path, target_path)
|
||||
|
||||
|
||||
def load_qt_phonon(finder: ModuleFinder, module: Module) -> None:
|
||||
"""In Windows, phonon5.dll requires an additional dll phonon_ds94.dll to
|
||||
be present in the build directory inside a folder phonon_backend.
|
||||
"""
|
||||
if IS_WINDOWS or IS_MINGW:
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "PluginsPath", "phonon_backend")
|
||||
|
||||
|
||||
def load_qt_qt3dinput(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "PluginsPath", "3dinputdevices")
|
||||
|
||||
|
||||
def load_qt_qt3drender(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "PluginsPath", "sceneparsers")
|
||||
copy_qt_files(finder, name, "PluginsPath", "geometryloaders")
|
||||
copy_qt_files(finder, name, "PluginsPath", "renderplugins")
|
||||
copy_qt_files(finder, name, "PluginsPath", "renderers")
|
||||
|
||||
|
||||
def load_qt_qtbluetooth(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include translations for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "TranslationsPath", "qtconnectivity_*.qm")
|
||||
|
||||
|
||||
def load_qt_qtcore(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
variable = "BinariesPath" if IS_WINDOWS else "LibrariesPath"
|
||||
for source, target in _get_qt_files(name, variable, "*"):
|
||||
finder.lib_files[source] = target
|
||||
|
||||
|
||||
def load_qt_qtdesigner(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "PluginsPath", "designer")
|
||||
copy_qt_files(finder, name, "TranslationsPath", "designer_*.qm")
|
||||
|
||||
|
||||
def load_qt_qtgui(finder: ModuleFinder, module: Module) -> None:
|
||||
"""There is a chance that QtGui will use some image formats, then, add the
|
||||
image format plugins.
|
||||
"""
|
||||
name = _qt_implementation(module)
|
||||
for plugin_name in (
|
||||
"accessiblebridge",
|
||||
"platforms",
|
||||
"platforms/darwin",
|
||||
"xcbglintegrations",
|
||||
"platformthemes",
|
||||
"platforminputcontexts",
|
||||
"generic",
|
||||
"iconengines",
|
||||
"imageformats",
|
||||
"egldeviceintegrations",
|
||||
"wayland-graphics-integration-client",
|
||||
"wayland-inputdevice-integration",
|
||||
"wayland-decoration-client",
|
||||
"wayland-shell-integration",
|
||||
"wayland-graphics-integration-server",
|
||||
"wayland-hardware-layer-integration",
|
||||
):
|
||||
copy_qt_files(finder, name, "PluginsPath", plugin_name)
|
||||
copy_qt_files(finder, name, "TranslationsPath", "qt_??.qm")
|
||||
copy_qt_files(finder, name, "TranslationsPath", "qt_??_??.qm")
|
||||
copy_qt_files(finder, name, "TranslationsPath", "qtbase_*.qm")
|
||||
# old names?
|
||||
copy_qt_files(finder, name, "PluginsPath", "accessible")
|
||||
copy_qt_files(finder, name, "PluginsPath", "pictureformats")
|
||||
|
||||
|
||||
def load_qt_qtlocation(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "PluginsPath", "geoservices")
|
||||
copy_qt_files(finder, name, "TranslationsPath", "qtlocation_*.qm")
|
||||
|
||||
|
||||
def load_qt_qtmultimedia(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "PluginsPath", "multimedia")
|
||||
copy_qt_files(finder, name, "TranslationsPath", "qtmultimedia_*.qm")
|
||||
# ?
|
||||
copy_qt_files(finder, name, "PluginsPath", "audio")
|
||||
copy_qt_files(finder, name, "PluginsPath", "mediaservice")
|
||||
copy_qt_files(finder, name, "PluginsPath", "playlistformats")
|
||||
copy_qt_files(finder, name, "PluginsPath", "resourcepolicy")
|
||||
copy_qt_files(finder, name, "PluginsPath", "video")
|
||||
|
||||
|
||||
def load_qt_qtnetwork(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "PluginsPath", "networkaccess")
|
||||
copy_qt_files(finder, name, "PluginsPath", "networkinformation")
|
||||
copy_qt_files(finder, name, "PluginsPath", "tls")
|
||||
copy_qt_files(finder, name, "PluginsPath", "bearer") # ?
|
||||
|
||||
|
||||
def load_qt_qtpositioning(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "PluginsPath", "position")
|
||||
|
||||
|
||||
def load_qt_qtprintsupport(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "PluginsPath", "printsupport")
|
||||
if IS_WINDOWS:
|
||||
copy_qt_files(finder, name, "PrefixPath", "Qt?Pdf*.dll")
|
||||
|
||||
|
||||
def load_qt_qtqml(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "PluginsPath", "qmllint") # pyqt6
|
||||
copy_qt_files(finder, name, "PluginsPath", "qmltooling")
|
||||
copy_qt_files(finder, name, "QmlImportsPath", "*")
|
||||
finder.include_module(f"{name}.QtQuick")
|
||||
|
||||
|
||||
def load_qt_qtquick(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "PluginsPath", "scenegraph")
|
||||
|
||||
|
||||
def load_qt_qtquick3d(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "PluginsPath", "assetimporters")
|
||||
|
||||
|
||||
def load_qt_qtscript(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "PluginsPath", "script")
|
||||
|
||||
|
||||
def load_qt_qtscxml(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "PluginsPath", "scxmldatamodel")
|
||||
|
||||
|
||||
def load_qt_qtsensors(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "PluginsPath", "sensors")
|
||||
copy_qt_files(finder, name, "PluginsPath", "sensorgestures") # pyqt6
|
||||
|
||||
|
||||
def load_qt_qtserialbus(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "PluginsPath", "canbus")
|
||||
|
||||
|
||||
def load_qt_qtserialport(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include translations for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "TranslationsPath", "qtserialport_*.qm")
|
||||
|
||||
|
||||
def load_qt_qtsql(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "PluginsPath", "sqldrivers")
|
||||
|
||||
|
||||
def load_qt_qttexttospeech(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "PluginsPath", "texttospeech")
|
||||
|
||||
|
||||
def load_qt_qtvirtualkeyboard(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "PluginsPath", "virtualkeyboard")
|
||||
|
||||
|
||||
def load_qt_qtwebenginecore(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include module dependency and QtWebEngineProcess files."""
|
||||
name = _qt_implementation(module)
|
||||
distribution = module.parent.distribution
|
||||
environment = (distribution and distribution.installer) or "pip"
|
||||
|
||||
if IS_WINDOWS:
|
||||
for filename in (
|
||||
"QtWebEngineProcess.exe",
|
||||
"d3dcompiler_47.dll",
|
||||
"libEGL.dll",
|
||||
"libGLESv2.dll",
|
||||
"opengl32sw.dll",
|
||||
):
|
||||
# pyside2 - only QtWebEngineProcess is in LibraryExecutablesPath
|
||||
# pyside6 - like pyside2, but the two lib*.dll are missing
|
||||
copy_qt_files(finder, name, "ArchDataPath", filename)
|
||||
# pyqt5 - all files listed in LibraryExecutablesPath
|
||||
copy_qt_files(finder, name, "LibraryExecutablesPath", filename)
|
||||
elif IS_MACOS and environment == "pip": # pip wheels for macOS
|
||||
source_path, _ = get_qt_paths(name, "LibrariesPath")
|
||||
source_framework = source_path / "QtWebEngineCore.framework"
|
||||
# QtWebEngineProcess
|
||||
finder.include_files(source_framework / "Helpers", "share")
|
||||
# QtWebEngineCore resources
|
||||
source_resources = source_framework / "Resources"
|
||||
if source_resources.exists():
|
||||
target_datapath = get_qt_paths(name, "DataPath")[1]
|
||||
for resource in source_resources.iterdir():
|
||||
if resource.name == "Info.plist":
|
||||
continue
|
||||
if resource.name == "qtwebengine_locales":
|
||||
target = get_qt_paths(name, "TranslationsPath")[1]
|
||||
else:
|
||||
target = target_datapath / "resources"
|
||||
finder.include_files(
|
||||
resource,
|
||||
target / resource.name,
|
||||
copy_dependent_files=False,
|
||||
)
|
||||
else:
|
||||
# wheels for Linux or conda-forge Linux and macOS
|
||||
copy_qt_files(
|
||||
finder, name, "LibraryExecutablesPath", "QtWebEngineProcess"
|
||||
)
|
||||
if environment == "conda": # conda-forge Linux and macOS
|
||||
prefix = Path(sys.prefix)
|
||||
conda_meta = prefix / "conda-meta"
|
||||
pkg = next(conda_meta.glob("nss-*.json"))
|
||||
files = json.loads(pkg.read_text(encoding="utf_8"))["files"]
|
||||
for file in files:
|
||||
source = prefix / file
|
||||
if source.match("lib*.so") or source.match("lib*.dylib"):
|
||||
finder.include_files(source, f"lib/{source.name}")
|
||||
else:
|
||||
copy_qt_files(finder, name, "LibraryExecutablesPath", "libnss*.*")
|
||||
|
||||
copy_qt_files(finder, name, "DataPath", "resources")
|
||||
copy_qt_files(finder, name, "TranslationsPath", "qtwebengine_*.qm")
|
||||
copy_qt_files(finder, name, "TranslationsPath", "qtwebengine_locales")
|
||||
|
||||
|
||||
def load_qt_qtwebenginewidgets(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include data and plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "LibrariesPath", "*WebEngineWidgets.*")
|
||||
copy_qt_files(finder, name, "PluginsPath", "webview")
|
||||
|
||||
|
||||
def load_qt_qtwebsockets(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include translations for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "TranslationsPath", "qtwebsockets_*.qm")
|
||||
|
||||
|
||||
def load_qt_qtwidgets(finder: ModuleFinder, module: Module) -> None:
|
||||
"""Include plugins for the module."""
|
||||
name = _qt_implementation(module)
|
||||
copy_qt_files(finder, name, "PluginsPath", "styles")
|
||||
|
||||
|
||||
def load_qt_uic(finder: ModuleFinder, module: Module) -> None:
|
||||
"""The uic module makes use of "plugins" that need to be read directly and
|
||||
cannot be frozen; the PyQt5.QtWebKit and PyQt5.QtNetwork modules are
|
||||
also implicity loaded.
|
||||
"""
|
||||
name = _qt_implementation(module)
|
||||
source_dir = module.path[0] / "widget-plugins"
|
||||
if source_dir.exists():
|
||||
finder.include_files(source_dir, f"{name}.uic.widget-plugins")
|
||||
Reference in New Issue
Block a user