搞事情还是非常累的,那么这里的话就简单更新一下使用实用一点的文章。这也是在实际过程当中遇到了很多问题,最终才解决之后的一篇经验文吧。
打包准备
这里我使用到的打包软件还是Pyinstaller ,通过这个来对其进行打包,软件本体大概是长这个样子:
这是一个视频编辑器,页面是使用streamlit来进行编写的(当然也后悔了,早知道直接使用qt或者vue来写的)那么众所周知,streamlit写出来的界面本身是需要这个玩意来独立启动的。因此打包的时候有很多细节。
载入streamlit
这里我们需要单独指定一下streamlit。这里我们需要编写一下hook,让pyinstaller来处理。
from PyInstaller.utils.hooks import copy_metadata datas = copy_metadata("streamlit")
创建启动脚本
这里我们的程序入口虽然是main.py 但是,由于我们需要
streamlit run main.py
才能启动,所以的话我们只能写一个运行脚本。之后对这个脚本进行打包,得到执行文件。 之后打包之后,需要将这个文件放到打包好 的执行文件的同级目录下
。
""" @FileName:run_app.py.py @Author:Huterox @Description:Go For It @Time:2024/6/11 11:42 @Copyright:©2018-2024 awesome! """ from main import * def resolve_path(path): resolved_path = os.path.abspath(os.path.join(os.getcwd(), path)) return resolved_path if __name__ == "__main__": sys.argv = [ "streamlit", "run", resolve_path("main.py"), "--global.developmentMode=false", ] sys.exit(stcli.main())
创建指令
之后的话,我们需要来创建我们的指令: 这里我展示一下我的指令:
pyinstaller --add-data ".streamlit:.streamlit" --add-data "resource:resource" --add-data "doc:doc" --add-data "assert:assert" --additional-hooks-dir=./hooks --icon=tubiao.ico run_app.py
当然实际上,我们之所以使用这个指令的目的还是为了生成spec文件,你当然可以直接创建这个文件。下面是我的参考文件。
# -*- mode: python ; coding: utf-8 -*- from PyInstaller.utils.hooks import collect_data_files from PyInstaller.utils.hooks import copy_metadata datas = [("C:/Anaconda3/envs/MixedVideo/Lib/site-packages/streamlit/runtime","./streamlit/runtime"),('.streamlit', '.streamlit'), ('resource', 'resource'), ('doc', 'doc'), ('assert', 'assert')] datas += collect_data_files("streamlit") datas += copy_metadata("streamlit") block_cipher = None a = Analysis( ['run_app.py'], pathex=[], binaries=[], datas=datas, hiddenimports=[], hookspath=['./hooks'], hooksconfig={}, runtime_hooks=[], excludes=[], noarchive=False, optimize=0, ) pyz = PYZ(a.pure) exe = EXE( pyz, a.scripts, [], exclude_binaries=True, name='run_app', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, console=True, disable_windowed_traceback=False, argv_emulation=False, target_arch=None, codesign_identity=None, entitlements_file=None, icon=['tubiao.ico'], ) coll = COLLECT( exe, a.binaries, a.datas, strip=False, upx=True, upx_exclude=[], name='run_app', )
你可以直接按照这个来进行修改。之后
pyinstaller your_spec.spec --clean
这样一来就可以完成打包了,但是这里有几个点需要特别注意:
Q&A
虽然通过上面的方法我们可以打包好我们的程序,但是这里还是有很多问题。这里我遇到的,包括我查找相关资料的时候看到的最多的问题就是,关于依赖的问题。
依赖未找到
这里原因其实就只有一个,那就是Pyinstaller打包的时候,没有找到依赖,我们来看到这个代码。
from main import * def resolve_path(path): resolved_path = os.path.abspath(os.path.join(os.getcwd(), path)) return resolved_path if __name__ == "__main__": sys.argv = [ "streamlit", "run", resolve_path("main.py"), "--global.developmentMode=false", ] sys.exit(stcli.main())
我在这里特意:
from main import *
其目的就是为了,让Pyinstaller知道,我导入了先前程序的main文件,之后去解析里面的依赖然后自动打包。这样就解决了依赖问题,注意哪怕是你自己写的包,他也会自动解析的。如果没有,只有两个问题:
- 你的Python包没有
__init__.py
- 缺少某些dll,依赖模型(因为我这个是深度学习项目,有一些特殊格式的文件是不会被自动打包进去的)
那么解决办法很简单:
- 加入初始化文件
- 填写模块名字(第三方或自己的包名)
- 缺少某些媒体,资源文件,那就直接找打对应文件copy过去就好了。以我的程序为例,有3G的模型文件不会自动打包进去的,只能自己手动导入。