2026-04-16 16:51:05 +08:00
|
|
|
|
# -*- mode: python ; coding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
|
|
SPEC_DIR = (
|
|
|
|
|
|
os.path.abspath(os.path.dirname(__file__))
|
|
|
|
|
|
if "__file__" in globals()
|
|
|
|
|
|
else os.getcwd()
|
|
|
|
|
|
)
|
|
|
|
|
|
if SPEC_DIR not in sys.path:
|
|
|
|
|
|
sys.path.insert(0, SPEC_DIR)
|
|
|
|
|
|
|
|
|
|
|
|
from app_version import APP_NAME, APP_VERSION
|
|
|
|
|
|
from PyInstaller.utils.win32.versioninfo import (
|
|
|
|
|
|
VSVersionInfo,
|
|
|
|
|
|
FixedFileInfo,
|
|
|
|
|
|
StringFileInfo,
|
|
|
|
|
|
StringTable,
|
|
|
|
|
|
StringStruct,
|
|
|
|
|
|
VarFileInfo,
|
|
|
|
|
|
VarStruct,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def build_windows_version(version_text):
|
|
|
|
|
|
parts = [int(part) for part in version_text.split('.') if part.strip()]
|
|
|
|
|
|
parts = (parts + [0, 0, 0, 0])[:4]
|
|
|
|
|
|
return tuple(parts)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
windows_version = build_windows_version(APP_VERSION)
|
|
|
|
|
|
windows_version_text = '.'.join(str(part) for part in windows_version)
|
|
|
|
|
|
|
|
|
|
|
|
version_info = VSVersionInfo(
|
|
|
|
|
|
ffi=FixedFileInfo(
|
|
|
|
|
|
filevers=windows_version,
|
|
|
|
|
|
prodvers=windows_version,
|
|
|
|
|
|
mask=0x3F,
|
|
|
|
|
|
flags=0x0,
|
|
|
|
|
|
OS=0x40004,
|
|
|
|
|
|
fileType=0x1,
|
|
|
|
|
|
subtype=0x0,
|
|
|
|
|
|
date=(0, 0),
|
|
|
|
|
|
),
|
|
|
|
|
|
kids=[
|
|
|
|
|
|
StringFileInfo(
|
|
|
|
|
|
[
|
|
|
|
|
|
StringTable(
|
|
|
|
|
|
'080404B0',
|
|
|
|
|
|
[
|
|
|
|
|
|
StringStruct('CompanyName', 'Moka'),
|
|
|
|
|
|
StringStruct('FileDescription', APP_NAME),
|
|
|
|
|
|
StringStruct('FileVersion', windows_version_text),
|
|
|
|
|
|
StringStruct('InternalName', 'pqAutomationApp'),
|
|
|
|
|
|
StringStruct('OriginalFilename', 'pqAutomationApp.exe'),
|
|
|
|
|
|
StringStruct('ProductName', APP_NAME),
|
|
|
|
|
|
StringStruct('ProductVersion', windows_version_text),
|
|
|
|
|
|
],
|
|
|
|
|
|
)
|
|
|
|
|
|
]
|
|
|
|
|
|
),
|
|
|
|
|
|
VarFileInfo([VarStruct('Translation', [2052, 1200])]),
|
|
|
|
|
|
],
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
a = Analysis(
|
|
|
|
|
|
['pqAutomationApp.py'],
|
|
|
|
|
|
pathex=[],
|
|
|
|
|
|
binaries=[],
|
|
|
|
|
|
datas=[('assets', 'assets'), ('UniTAP', 'UniTAP')],
|
2026-04-20 15:34:45 +08:00
|
|
|
|
hiddenimports=[
|
|
|
|
|
|
# app 包的子模块在主文件里是静态 import 的,但惰性调用 / 属性绑定
|
|
|
|
|
|
# 场景较多,显式列出可避免 PyInstaller 漏打包。
|
|
|
|
|
|
'app',
|
|
|
|
|
|
'app.config_io',
|
|
|
|
|
|
'app.data_range_converter',
|
|
|
|
|
|
'app.resources',
|
|
|
|
|
|
'app.device',
|
|
|
|
|
|
'app.device.connection',
|
|
|
|
|
|
'app.pq',
|
|
|
|
|
|
'app.pq.pq_config',
|
|
|
|
|
|
'app.pq.pq_result',
|
|
|
|
|
|
'app.plots',
|
|
|
|
|
|
'app.plots.plot_accuracy',
|
|
|
|
|
|
'app.plots.plot_cct',
|
|
|
|
|
|
'app.plots.plot_contrast',
|
|
|
|
|
|
'app.plots.plot_eotf',
|
|
|
|
|
|
'app.plots.plot_gamma',
|
|
|
|
|
|
'app.plots.plot_gamut',
|
|
|
|
|
|
'app.runner',
|
|
|
|
|
|
'app.runner.test_runner',
|
|
|
|
|
|
'app.tests',
|
|
|
|
|
|
'app.tests.color_accuracy',
|
|
|
|
|
|
'app.tests.eotf',
|
|
|
|
|
|
'app.tests.gamma',
|
|
|
|
|
|
'app.tests.gamut',
|
|
|
|
|
|
'app.tests.local_dimming',
|
|
|
|
|
|
'app.views',
|
|
|
|
|
|
'app.views.chart_frame',
|
|
|
|
|
|
'app.views.collapsing_frame',
|
|
|
|
|
|
'app.views.panel_manager',
|
|
|
|
|
|
'app.views.pq_debug_panel',
|
|
|
|
|
|
'app.views.pq_log_gui',
|
|
|
|
|
|
'app.views.panels',
|
|
|
|
|
|
'app.views.panels.cct_panel',
|
|
|
|
|
|
'app.views.panels.custom_template_panel',
|
|
|
|
|
|
'app.views.panels.main_layout',
|
|
|
|
|
|
'app.views.panels.side_panels',
|
|
|
|
|
|
'drivers',
|
|
|
|
|
|
'drivers.baseSerail',
|
|
|
|
|
|
'drivers.caSerail',
|
|
|
|
|
|
'drivers.tvSerail',
|
|
|
|
|
|
'drivers.UCD323_Enum',
|
|
|
|
|
|
'drivers.UCD323_Function',
|
|
|
|
|
|
'drivers.ucd_helpers',
|
|
|
|
|
|
],
|
2026-04-16 16:51:05 +08:00
|
|
|
|
hookspath=[],
|
|
|
|
|
|
hooksconfig={},
|
|
|
|
|
|
runtime_hooks=[],
|
2026-04-17 11:15:39 +08:00
|
|
|
|
excludes=[
|
|
|
|
|
|
'PyQt5',
|
|
|
|
|
|
'PyQt6',
|
|
|
|
|
|
'PySide2',
|
|
|
|
|
|
'PySide6',
|
|
|
|
|
|
'cv2',
|
|
|
|
|
|
'imageio',
|
|
|
|
|
|
'imageio_ffmpeg',
|
|
|
|
|
|
'IPython',
|
|
|
|
|
|
'jedi',
|
|
|
|
|
|
],
|
2026-04-16 16:51:05 +08:00
|
|
|
|
noarchive=False,
|
2026-04-17 11:15:39 +08:00
|
|
|
|
# numpy 在运行时依赖部分 docstring,optimize=2 会移除 docstring 导致启动报错。
|
2026-04-16 16:51:05 +08:00
|
|
|
|
optimize=0,
|
|
|
|
|
|
)
|
|
|
|
|
|
pyz = PYZ(a.pure)
|
|
|
|
|
|
|
|
|
|
|
|
exe = EXE(
|
|
|
|
|
|
pyz,
|
|
|
|
|
|
a.scripts,
|
|
|
|
|
|
[],
|
|
|
|
|
|
exclude_binaries=True,
|
|
|
|
|
|
name='pqAutomationApp',
|
|
|
|
|
|
debug=False,
|
|
|
|
|
|
bootloader_ignore_signals=False,
|
|
|
|
|
|
strip=False,
|
2026-04-17 11:15:39 +08:00
|
|
|
|
# 关闭 UPX:通常可减少启动时解压与杀软扫描开销,提升冷启动体感。
|
|
|
|
|
|
upx=False,
|
2026-04-16 16:51:05 +08:00
|
|
|
|
console=False,
|
|
|
|
|
|
disable_windowed_traceback=False,
|
|
|
|
|
|
argv_emulation=False,
|
|
|
|
|
|
target_arch=None,
|
|
|
|
|
|
codesign_identity=None,
|
|
|
|
|
|
entitlements_file=None,
|
|
|
|
|
|
contents_directory='internal',
|
|
|
|
|
|
version=version_info,
|
|
|
|
|
|
icon=os.path.join(SPEC_DIR, 'assets', 'pq.ico'),
|
|
|
|
|
|
)
|
|
|
|
|
|
coll = COLLECT(
|
|
|
|
|
|
exe,
|
|
|
|
|
|
a.binaries,
|
|
|
|
|
|
a.datas,
|
|
|
|
|
|
strip=False,
|
2026-04-17 11:15:39 +08:00
|
|
|
|
upx=False,
|
2026-04-16 16:51:05 +08:00
|
|
|
|
upx_exclude=[],
|
|
|
|
|
|
name='pqAutomationApp',
|
|
|
|
|
|
)
|