|
| 1 | +# -*- mode: python ; coding: utf-8 -*- |
| 2 | +""" |
| 3 | +TestPilot AI 引擎打包配置 |
| 4 | +用法: poetry run pyinstaller testpilot_engine.spec |
| 5 | +""" |
| 6 | + |
| 7 | +import os |
| 8 | +import sys |
| 9 | +from pathlib import Path |
| 10 | + |
| 11 | +# ── 基本路径 ────────────────────────────────────────────────── |
| 12 | +project_dir = Path(SPECPATH) |
| 13 | +venv_site_packages = project_dir / '.venv' / 'lib' / 'site-packages' |
| 14 | + |
| 15 | +# ── 需要随二进制一起携带的数据目录 ──────────────────────────── |
| 16 | +datas = [ |
| 17 | + # playwright driver(含 node.exe 和 package/) |
| 18 | + (str(venv_site_packages / 'playwright' / 'driver'), 'playwright/driver'), |
| 19 | + # alembic 迁移脚本(数据库升级用) |
| 20 | + (str(project_dir / 'alembic'), 'alembic'), |
| 21 | + # alembic.ini |
| 22 | + (str(project_dir / 'alembic.ini'), '.'), |
| 23 | + # 小程序 JS 脚本(BUNDLE_DIR/controller/ 下可找到) |
| 24 | + (str(project_dir / 'src' / 'controller' / 'miniprogram_runner.js'), 'controller'), |
| 25 | + (str(project_dir / 'src' / 'controller' / 'miniprogram_bridge_server.js'), 'controller'), |
| 26 | +] |
| 27 | + |
| 28 | +# ── 隐式导入(动态加载的模块,分析器找不到)──────────────────── |
| 29 | +hiddenimports = [ |
| 30 | + # FastAPI / Starlette |
| 31 | + 'uvicorn.logging', |
| 32 | + 'uvicorn.loops', |
| 33 | + 'uvicorn.loops.auto', |
| 34 | + 'uvicorn.loops.asyncio', |
| 35 | + 'uvicorn.loops.uvloop', |
| 36 | + 'uvicorn.protocols', |
| 37 | + 'uvicorn.protocols.http', |
| 38 | + 'uvicorn.protocols.http.auto', |
| 39 | + 'uvicorn.protocols.http.h11_impl', |
| 40 | + 'uvicorn.protocols.http.httptools_impl', |
| 41 | + 'uvicorn.protocols.websockets', |
| 42 | + 'uvicorn.protocols.websockets.auto', |
| 43 | + 'uvicorn.protocols.websockets.websockets_impl', |
| 44 | + 'uvicorn.protocols.websockets.wsproto_impl', |
| 45 | + 'uvicorn.lifespan', |
| 46 | + 'uvicorn.lifespan.on', |
| 47 | + 'uvicorn.lifespan.off', |
| 48 | + 'starlette.routing', |
| 49 | + 'starlette.middleware', |
| 50 | + 'starlette.middleware.cors', |
| 51 | + # Playwright |
| 52 | + 'playwright', |
| 53 | + 'playwright.sync_api', |
| 54 | + 'playwright.async_api', |
| 55 | + # SQLAlchemy |
| 56 | + 'sqlalchemy.dialects.sqlite', |
| 57 | + # jose |
| 58 | + 'jose', |
| 59 | + 'jose.jwt', |
| 60 | + # multipart |
| 61 | + 'multipart', |
| 62 | + # email_validator (fastapi opt-dep) |
| 63 | + 'email_validator', |
| 64 | + # passlib |
| 65 | + 'passlib.handlers.bcrypt', |
| 66 | + 'passlib.handlers.sha2_crypt', |
| 67 | + # websockets |
| 68 | + 'websockets', |
| 69 | + 'websockets.legacy', |
| 70 | + 'websockets.legacy.server', |
| 71 | +] |
| 72 | + |
| 73 | +a = Analysis( |
| 74 | + ['main.py'], |
| 75 | + pathex=[str(project_dir)], |
| 76 | + binaries=[], |
| 77 | + datas=datas, |
| 78 | + hiddenimports=hiddenimports, |
| 79 | + hookspath=[], |
| 80 | + hooksconfig={}, |
| 81 | + runtime_hooks=[], |
| 82 | + excludes=[ |
| 83 | + # 排除用不到的大型包,减小体积 |
| 84 | + 'tkinter', |
| 85 | + 'matplotlib', |
| 86 | + 'numpy', |
| 87 | + 'pandas', |
| 88 | + 'scipy', |
| 89 | + 'PIL', |
| 90 | + 'IPython', |
| 91 | + 'notebook', |
| 92 | + 'pytest', |
| 93 | + 'sphinx', |
| 94 | + ], |
| 95 | + noarchive=False, |
| 96 | + optimize=0, |
| 97 | +) |
| 98 | + |
| 99 | +pyz = PYZ(a.pure) |
| 100 | + |
| 101 | +exe = EXE( |
| 102 | + pyz, |
| 103 | + a.scripts, |
| 104 | + a.binaries, |
| 105 | + a.datas, |
| 106 | + [], |
| 107 | + name='testpilot-engine', |
| 108 | + debug=False, |
| 109 | + bootloader_ignore_signals=False, |
| 110 | + strip=False, |
| 111 | + upx=False, # UPX 压缩在某些杀毒软件中会误报,关闭 |
| 112 | + upx_exclude=[], |
| 113 | + runtime_tmpdir=None, |
| 114 | + console=True, # 保留控制台,方便用户看启动日志 |
| 115 | + disable_windowed_traceback=False, |
| 116 | + argv_emulation=False, |
| 117 | + target_arch=None, |
| 118 | + codesign_identity=None, |
| 119 | + entitlements_file=None, |
| 120 | + # 图标(可选,后续替换为实际 .ico 文件) |
| 121 | + # icon='resources/icon.ico', |
| 122 | +) |
0 commit comments