From a5f4275e1977ffa61b44d77af2f81e618e67d9de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=88=AA=E5=AE=87?= <3364451258@qq.com> Date: Fri, 8 May 2026 16:15:45 +0800 Subject: [PATCH] =?UTF-8?q?build:=20PyInstaller=E6=89=93=E5=8C=85=E9=85=8D?= =?UTF-8?q?=E7=BD=AE+=E5=90=AF=E5=8A=A8=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build_exe.py | 26 ++++++++++++++++++++++++++ cDNA_Analyzer.spec | 45 +++++++++++++++++++++++++++++++++++++++++++++ web/app.py | 12 +++++++++++- web/launcher.py | 22 ++++++++++++++++++++++ 4 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 build_exe.py create mode 100644 cDNA_Analyzer.spec create mode 100644 web/launcher.py diff --git a/build_exe.py b/build_exe.py new file mode 100644 index 0000000..4abafe4 --- /dev/null +++ b/build_exe.py @@ -0,0 +1,26 @@ +""" +PyInstaller打包脚本 +运行: python build_exe.py +输出: dist/cDNA_Analyzer.exe +""" + +import PyInstaller.__main__ +import os + +BASE = os.path.dirname(os.path.abspath(__file__)) + +PyInstaller.__main__.run([ + 'web/launcher.py', + '--name=cDNA_Analyzer', + '--onefile', + '--windowed', + '--add-data', f'web/templates;templates', + '--add-data', f'web/static;static', + '--hidden-import', 'skimage', + '--hidden-import', 'scipy.ndimage', + '--hidden-import', 'matplotlib.backends.backend_agg', + '--collect-all', 'skimage', + '--noconfirm', + '--clean', +]) +print('\n完成!exe 在 dist/ 目录') diff --git a/cDNA_Analyzer.spec b/cDNA_Analyzer.spec new file mode 100644 index 0000000..665ded2 --- /dev/null +++ b/cDNA_Analyzer.spec @@ -0,0 +1,45 @@ +# -*- mode: python ; coding: utf-8 -*- +from PyInstaller.utils.hooks import collect_all + +datas = [('web/templates', 'templates'), ('web/static', 'static')] +binaries = [] +hiddenimports = ['skimage', 'scipy.ndimage', 'matplotlib.backends.backend_agg'] +tmp_ret = collect_all('skimage') +datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2] + + +a = Analysis( + ['web\\launcher.py'], + pathex=[], + binaries=binaries, + datas=datas, + hiddenimports=hiddenimports, + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + noarchive=False, + optimize=0, +) +pyz = PYZ(a.pure) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.datas, + [], + name='cDNA_Analyzer', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=False, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) diff --git a/web/app.py b/web/app.py index d6c14fc..95e8909 100644 --- a/web/app.py +++ b/web/app.py @@ -2,6 +2,7 @@ cDNA微阵列图像处理 - Web UI (Flask) ===================================== 启动:python web/app.py +打包:python build_exe.py 打开:http://localhost:5000 """ @@ -19,7 +20,16 @@ from scipy import ndimage BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, os.path.join(BASE_DIR, 'src')) -app = Flask(__name__) +# PyInstaller 打包后资源路径 +if getattr(sys, 'frozen', False): + bundle_dir = sys._MEIPASS + template_dir = os.path.join(bundle_dir, 'templates') + static_dir = os.path.join(bundle_dir, 'static') +else: + template_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates') + static_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static') + +app = Flask(__name__, template_folder=template_dir, static_folder=static_dir) app.config['MAX_CONTENT_LENGTH'] = 50 * 1024 * 1024 # 50MB UPLOAD_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'uploads') os.makedirs(UPLOAD_DIR, exist_ok=True) diff --git a/web/launcher.py b/web/launcher.py new file mode 100644 index 0000000..9263ea6 --- /dev/null +++ b/web/launcher.py @@ -0,0 +1,22 @@ +"""cDNA Analyzer 启动器 — 供 PyInstaller 打包""" +import os, sys, threading + +# PyInstaller 打包后资源路径 +if getattr(sys, 'frozen', False): + base = sys._MEIPASS +else: + base = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +# 设置模板和静态文件目录 +os.environ['TEMPLATE_DIR'] = os.path.join(base, 'templates') +os.environ['STATIC_DIR'] = os.path.join(base, 'static') + +# 导入 Flask app +from app import app + +def open_browser(): + os.startfile('http://localhost:5000') + +if __name__ == '__main__': + threading.Timer(1.5, open_browser).start() + app.run(debug=False, port=5000)