Pyinstaller 打包发布经验总结

在使用Pyinstaller打包Python项目遇到大量的坑,本片文章总结实践得到的Pyinstaller打包经验,记录并防止以后忘记。本文的例子为Python3.7代码,Pyinstaller4.25,在Centos 7.0下打包。

本文

Pyinstaller基本使用方法

        Pyinstaller可以通过简单的命令进行python代码的打包工作,其基本的命令为:

pyinstaller -option xxx.py

这边只介绍用到的option:

                   -D生成一个文件目录包含可执行文件和相关动态链接库和资源文件等;

                   -F仅生成一个可执行文件

对于打包结果较大的项目,选用-d生成目录相比单可执行文件的打包方式,执行速度更快,但包含更加多的文件。本文的例子选中-D方式打包。

Python项目的打包方法

以一个多文件和目录的Python项目为例,项目文件包含:1.Python源代码文件;2.图标资源文件;3.其它资源文件

以图中项目为例,Python源代码文件在多个目录下:bin, lib\app, lib\models, lib\views;图标资源文件在lib\icon目录下;其它资源文件在data目录下,包括文本文件,视频文件等等。

        

1.spec文件生成

为了进行自定义配置的打包,首先需要编写打包的配置文件.spec文件。当使用pyinstaller -d xxx.py时候会生成默认的xxx.spec文件进行默认的打包配置。通过配置spec脚本,并执行pyinstaller -d xxx.spec完成自定义的打包。

通过生成spec文件的命令,针对代码的主程序文件生成打包对应的spec文件

 pyi-makespec -w xxx.py

打开生成的spec文件,修改其默认脚本,完成自定义打包需要的配置。spec文件是一个python脚本,其默认的结构如下例所示

# -*- mode: python -*-
 
block_cipher = None
 
 
a = Analysis(['fastplot.py'],
             pathex=['D:\\install_test\\DAGUI-0.1\\bin'],
             binaries=[],
             datas=[],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          exclude_binaries=True,
          name='fastplot',
          debug=False,
          strip=False,
          upx=True,
          console=False )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               name='fastplot')

spec文件中主要包含4个class: Analysis, PYZ, EXE和COLLECT.

        Analysis以py文件为输入,它会分析py文件的依赖模块,并生成相应的信息

        PYZ是一个.pyz的压缩包,包含程序运行需要的所有依赖

        EXE根据上面两项生成

        COLLECT生成其他部分的输出文件夹,COLLECT也可以没有

2.spec文件配置

首先给出举例python项目的spec文件配置

# -*- mode: python -*-
import sys
import os.path as osp
sys.setrecursionlimit(5000)
 
block_cipher = None
 
 
SETUP_DIR = 'D:\\install_test\\FASTPLOT\\'
 
a = Analysis(['fastplot.py',
              'frozen_dir.py',
              'D:\\install_test\\FASTPLOT\\lib\\app\\start.py',
             'D:\\install_test\\FASTPLOT\\lib\\models\\analysis_model.py',
             'D:\\install_test\\FASTPLOT\\lib\\models\\datafile_model.py',
             'D:\\install_test\\FASTPLOT\\lib\\models\\data_model.py',
             'D:\\install_test\\FASTPLOT\\lib\\models\\figure_model.py',
             'D:\\install_test\\FASTPLOT\\lib\\models\\time_model.py',
             'D:\\install_test\\FASTPLOT\\lib\\models\\mathematics_model.py',
             'D:\\install_test\\FASTPLOT\\lib\\views\\constant.py',
             'D:\\install_test\\FASTPLOT\\lib\\views\\custom_dialog.py',
             'D:\\install_test\\FASTPLOT\\lib\\views\\data_dict_window.py',
             'D:\\install_test\\FASTPLOT\\lib\\views\\data_process_window.py',
             'D:\\install_test\\FASTPLOT\\lib\\views\\data_sift_window.py',
             'D:\\install_test\\FASTPLOT\\lib\\views\\mathematics_window.py',
             'D:\\install_test\\FASTPLOT\\lib\\views\\para_temp_window.py',
             'D:\\install_test\\FASTPLOT\\lib\\views\\mainwindow.py',
             'D:\\install_test\\FASTPLOT\\lib\\views\\paralist_window.py',
             'D:\\install_test\\FASTPLOT\\lib\\views\\plot_window.py'],
             pathex=['D:\\install_test\\FASTPLOT'],
             binaries=[],
             datas=[(SETUP_DIR+'lib\\icon','lib\\icon'),(SETUP_DIR+'data','data')],
             hiddenimports=['pandas','pandas._libs','pandas._libs.tslibs.np_datetime','pandas._libs.tslibs.timedeltas',
             'pandas._libs.tslibs.nattype', 'pandas._libs.skiplist','scipy._lib','scipy._lib.messagestream'],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
                                     
            
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          exclude_binaries=True,
          name='fastplot',
          debug=False,
          strip=False,
          upx=True,
          console=True)
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               name='fastplot')

a) py文件打包配置

针对多目录多文件的python项目,打包时候需要将所有相关的py文件输入到Analysis类里。Analysis类中的pathex定义了打包的主目录,对于在此目录下的py文件可以只写文件名不写路径。如上的spec脚本,将所有项目中的py文件路径以列表形式写入Analysis,这里为了说明混合使用了绝对路径和相对路径。

b) 资源文件打包配置

资源文件包括打包的python项目使用的相关文件,如图标文件,文本文件等。对于此类资源文件的打包需要设置Analysis的datas,如例子所示datas接收元组:datas=[(SETUP_DIR+'lib\\icon','lib\\icon'),(SETUP_DIR+'data','data')]。元组的组成为(原项目中资源文件路径,打包后路径),例子中的(SETUP_DIR+'lib\\icon','lib\\icon')表示从D:\\install_test\\FASTPLOT\\lib\\icon下的图标文件打包后放入打包结果路径下的lib\\icon目录。

c)Hidden import配置

pyinstaller在进行打包时,会解析打包的python文件,自动寻找py源文件的依赖模块。但是pyinstaller解析模块时可能会遗漏某些模块(not visible to the analysis phase),造成打包后执行程序时出现类似No Module named xxx。这时我们就需要在Analysis下hiddenimports中加入遗漏的模块,如例子中所示。

d)递归深度设置

在打包导入某些模块时,常会出现"RecursionError: maximum recursion depth exceeded"的错误,这可能是打包时出现了大量的递归超出了python预设的递归深度。因此需要在spec文件上添加递归深度的设置,设置一个足够大的值来保证打包的进行,即
 

import sys
sys.setrecursionlimit(5000)

e)去除不必要的模块import

有时需要让pyinstaller不打包某些用不到的模块,可通过在excludes=[]中添加此模块实现,如

excludes=['zmq']

3.使用spec执行打包命令

pyinstaller -D xxx.spec

打包生成两个文件目录build和dist,build为临时文件目录完成打包后可以删除;dist中存放打包的结果,可执行文件和其它程序运行的关联文件都在这个目录下。

Python模块的打包问题

说一下我自己打包的问题,我是用-F生成一个可执行的文件。

1.生成的可执行文件的权限问题,赋予该文件可执行的权限

        chmod +x main

2.打包后的文件太大

        可使用pipenv来创建一个虚拟环境进行打包

        也可在代码中尽量减少不必要的import,如from xxx import*

3.打包后运行可执行文件main在某些地方卡主,一通寻找问题之后,发现有一些包未被打包进来

        我这里是缺少torchvision里面的包,所以我将torchvision下面所有的包都加进来。

        刚开始我使用一下目录发现不行

pathex=['D:\\install_test\\FASTPLOT',
'/home/cv/anaconda3/lib/python3.7/site-packages/torchvision'],

 需要将该目录下的所有文件都加进来,就可以了。

pathex=['D:\\install_test\\FASTPLOT',
'/home/cv/anaconda3/lib/python3.7/site-packages/torchvision/transforms',
  '/home/cv/anaconda3/lib/python3.7/site-packages/torchvision/datasets'],

最后附上参考的博客,这篇博客对Pyinstaller 打包讲解的非常详细,很有帮助。

https://blog.csdn.net/weixin_42052836/article/details/82315118

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值