很多时候,我们的代码需要依赖一些资源文件,比如配置文件、默认数据、图片等,如果用PyInstaller进行打包的话,默认是不会将这些文件打包进去的,那么该如何处理这个问题呢?
示例代码 我会通过一段很简单的代码来说明这个问题,下面的代码会通过configparser
读取config.ini
文件,这个例子也来自官方文档:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import configparserdef read_config (): config = configparser.ConfigParser() config.read('config.ini' ) bitbucket_user = config['bitbucket.org' ]['User' ] print (f'bitucket user: {bitbucket_user} ' ) topsecret_port = config['topsecret.server.com' ]['Port' ] print (f'topsecret port: {topsecret_port} ' ) if __name__ == '__main__' : read_config()
config.ini
的文件内容如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 [DEFAULT] ServerAliveInterval = 45 Compression = yes CompressionLevel = 9 ForwardX11 = yes [bitbucket.org] User = hg[topsecret.server.com] Port = 50022 ForwardX11 = no
现在进行打包:
1 PyInstaller --onefile load_config.py
执行时会发生报错:
1 2 3 4 5 6 7 8 $ cd dist$ ./load_config Traceback (most recent call last): File "load_config.py", line 17, in <module> File "load_config.py", line 10, in read_config File "configparser.py", line 958, in __getitem__ KeyError: 'bitbucket.org' [7073] Failed to execute script load_config
这是因为在load_config
所在的目录下不存在config.ini
文件,如果我们把config.ini
拷贝一份到目录下就可以正常运行:
1 2 3 $ ./load_config bitucket user: hg topsecret port: 50022
现在回到最开始的问题,如果我们并不需要用户知道这种资源文件的存在,想把config.ini
一起打包进去该怎么做?
spec文件 spec
文件实际上是可执行的Python代码,PyInstaller
通过执行spec
文件的内容来构建应用程序。可以将其理解为写C代码时的makefile
文件,都是用于控制编译构建过程。遇到下面几种情况时需要修改spec文件:
需要打包资源文件
需要include一些PyInstaller不知道的run-time库
为可执行文件添加run-time选项
多程序打包
生成spec文件的方式有两种,一种是通过pyi-makespec
命令生成:
1 $ pyi-makespec <options> XXX.py
注意此处的options,如果希望生成一个文件,应该使用--onefile
选项。
在上面进行打包时除了生成build
和dist
两个文件夹外,还有一个load_config.spec
文件,这便是另一种方式啦:
1 $ pyinstaller <options> XXX.py
修改spec文件 先看一下目录结构:
1 2 3 4 5 6 7 $ tree . ├── config.ini ├── load_config.py └── load_config.spec 0 directories, 3 files
打开load_config.spec
文件,按照官方文档进行操作,将我们的资源文件添加进去:
1 2 3 4 5 6 7 8 9 10 11 12 a = Analysis(['load_config.py' ], pathex=['/home/top/CodeWork/Python/ABC/static' ], binaries=[], datas=[('config.ini' , '.' )], hiddenimports=[], hookspath=[], runtime_hooks=[], excludes=[], win_no_prefer_redirects=False , win_private_assemblies=False , cipher=block_cipher, noarchive=False )
除此之前我们还需要对代码稍作修改,因为代码执行的时候是释放到/tmp
文件夹的,所以我们需要告知configparser
配置文件config.ini
的绝对路径:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import osimport sysimport configparserexec_path = os.path.dirname(sys.path[0 ]) def read_config (): file_path = exec_path + '/config.ini' config = configparser.ConfigParser() config.read(file_path) bitbucket_user = config['bitbucket.org' ]['User' ] print (f'bitucket user: {bitbucket_user} ' ) topsecret_port = config['topsecret.server.com' ]['Port' ] print (f'topsecret port: {topsecret_port} ' ) if __name__ == '__main__' : read_config()
现在就可以通过spec
文件进行打包:
1 $ pyinstaller load_config.spec
拷贝到另一台机器上进行测试:
1 2 3 4 $ chmod +x load_config$ ./load_config bitucket user: hg topsecret port: 50022
这样我们就成功的将所需要的资源文件打包进去了。
参考链接 1、https://docs.python.org/zh-cn/3/library/configparser.html 2、https://pythonhosted.org/PyInstaller/spec-files.html#adding-data-files