问题

如何使用 pyinstaller 打包使用了 gettext 本地化的项目,最终只生成一个 exe 文件

起因

最近在用 pyhton 做一个图片处理的小工具,顺便接触了一下 gettext,用来实现本地化化中英文转换。项目主要结构如下:

.
|--src # 源码
| |--package1
| |--package2
| |--locales # 本地化文件
| | |--en # 英文
| | | |--LC_MESSAGES
| | | |--en.mo
| | |--zh # 中文
| | |--LC_MESSAGES
| | |--en.mo
| |--GUI.py # 界面
| |--main.py # 主程序

直接使用 pyinstaller -F src\main.py 命令进行打包,打包后运行在 dist 文件夹中生成的 main.exe 会报错。原因是 gettext 找不到本地化文件。但如果试着将 locales 文件夹复制到 main.exe 的目录下程序能正常运行,说明 pyinstaller 在打包时不会将 locales 文件夹打包进去。

复制 locales 文件夹到可执行文件目录下固然可以运行,但这样用起来会很麻烦。

解决方案

​ 目标是将 locales 目录一起打包进 exe 文件中,查阅 pyinstaller 的官方文档,了解到执行之前的 pyinstaller -F src\\main.py 命令会在目录下生成一个 .spec 文件,pyinstaller 通过该文件的内容来构建应用程序。

the first thing PyInstaller does is to build a spec (specification) file myscript.spec. That file is stored in the --specpath directory, by default the current directory.

The spec file tells PyInstaller how to process your script. It encodes the script names and most of the options you give to the pyinstaller command. The spec file is actually executable Python code. PyInstaller builds the app by executing the contents of the spec file.

使用记事本打开,.spec 文件里面大致长这样(来自官方例子)

block_cipher = None
a = Analysis(['minimal.py'],
pathex=['/Developer/PItests/minimal'],
binaries=None,
datas=None,
hiddenimports=[],
hookspath=None,
runtime_hooks=None,
excludes=None,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,... )
coll = COLLECT(...)

其中,Analysis 里面有个 datas 参数,用于存放非二进制文件,也就是我们想让程序包含的静态文件。我们只要把 locales 目录填到这里面打包就会添加进去。当然不是填一个路径就好了,data 的格式如下:

--add-data <SRC;DEST or SRC:DEST>

SRC 就是未打包前的文件路径,DEST 是打包后文件的路径。以我的项目为例,打包前 locales 在 src/locales,打包后我想讲里面的文件放到临时目录的根目录下就填 ./locales,临时目录是什么后面讲。于是在我的 .spec文件里 datas 处就写成 datas=[("src/locales","./locales")]。如果有多个路径就以这样形式 datas=[(src1, dest1), (src2, dest2), ...]就OK。

这样打包部分的配置就改完了,不要急,还要改下源代码。exe 文件在运行时会生成一个临时目录,我们之前 datas 中的文件也会在该目录下。看看你的源码,如果调用资源用的是相对路径,那读取的是 exe 文件当前的目录,必然是找不到资源的。所以要把源码中相对路径改成临时目录的绝对路径。

sys 中的 _MEIPASS 属性存储了临时目录路径,直接获取即可。如果程序运行环境是打包后的,那么在 sys 中会添加一个 frozen 属性,通过能不能获取 frozen 属性可以判断当前环境是打包前还是打包后,具体详情请查阅 pyinstaller 官方文档(末尾有地址)。打包前就不需要获取临时目录路径了,直接用文件所在目录路径就行。

注意:打包后环境 file 属性不生效

import sys
import os if getattr(sys, 'frozen', None):
dir = sys._MEIPASS
else:
dir = os.path.dirname(__file__)

获取路径 dir,可以使用 os.path.join() 来拼接路径,把源码中调用 datas 中资源地方的路径改成 os.path.join(dir, <打包后相对路径>)

如我的项目中原来的 './locales' 处就变成了 os.path.join(dir, 'locales')

最后一步,打包!不要再输之前的命令了,要使用改过之后的 .spec 文件进行打包,输入 pyinstaller -F 文件名.spec 就完成了。

参考资料

  1. pyinstaller 文档:Using Spec Files
  2. pyinstaller 文档:Run-time Information

Python:使用pyinstaller打包含有gettext locales语言环境的项目的更多相关文章

  1. python用pyinstaller打包成exe文件

    版本为Python2.7 一.安装Pyinstaller 1.安装pywin32 下载安装文件:查找到跟自己适用的python版本及window系统版本匹配的pywin32,下载后安装  使用pip命 ...

  2. 【Python】pyinstaller打包运行报错failed to execute script main

    前言 最近用pyinstaller打包的时候一直报"failed to execute script main". 最终使用"pyinstaller --hidden-i ...

  3. python 使用pyinstaller打包程序

    使用pyinstaller 打包.py脚本,在其他计算机可以直接运行,不需要python环境 安装pyinstaller库 pip install pystaller 打包程序 pyinstaller ...

  4. Python | 用Pyinstaller打包发布exe应用

    参考:https://jingyan.baidu.com/article/a378c960b47034b3282830bb.html https://ask.csdn.net/questions/72 ...

  5. python使用Pyinstaller打包

    一.前言 python文件打包,将.py文件转化成.exe文件(windows平台),可以使用Pyinstaller来打包 Pyinstaller可以在全平台下使用,但是请注意打包生成的文件不能在全平 ...

  6. python pyinstaller 打包exe报错

    今天用python 使用pyinstaller打包exe出现错误 环境pyqt5 + python3.6 在导入pyqt5包之前加上如下代码 import sysimport osif hasattr ...

  7. 利用PyInstaller打包exe文件

    前言 平常我们通过Python写完一些小脚本之后,如果使用不频繁的话,一般会选择在DOS界面直接跑脚本,或者在IDE中运行.但当我们需要频繁使用某些脚本,或者在没有Python环境的机器上也能顺利运行 ...

  8. pyinstaller打包python文件成exe(原理.安装.问题)

    py文件打包成exe文件的方式一共有三种:py2exe.PyInstaller和cx_Freeze 本文分四个步骤来详讲如何用PyInstaller将py文件打包成exe文件 1. PyInstall ...

  9. 用PyInstaller打包用PyQt5编写的python程序

    0.背景 本弱初学PyQt5,写了一个GUI小程序,但在用PyInstaller打包时出现了不少问题,现将几个比较大的问题记录如下,希望以后能记住. 1. 资源打包 首先是资源打包的问题,我写的程序引 ...

随机推荐

  1. 【LeetCode】555. Split Concatenated Strings 解题报告(C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 遍历 日期 题目地址:https://leetcode ...

  2. 1108 - Instant View of Big Bang

    1108 - Instant View of Big Bang   PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limi ...

  3. Gumbel distribution

    目录 概 主要内容 定义 Gumbel-Max trick Gumbel trick 用于归一化 代码 概 感觉这个分布的含义很有用啊, 能预测'最大', 也就是自然灾害, 太牛了. 主要内容 定义 ...

  4. Geometric GAN

    目录 概 主要内容 McGAN 结合SVM 训练 训练 理论分析 证明 Jae Hyun Lim, Jong Chul Ye, Geometric GAN. 概 很有趣, GAN的训练过程可以分成 寻 ...

  5. LDAP客户端安装

    安装环境: 10.43.159.7 客户端 使用ldap客户端验证登陆: 用户为10.43.159.9服务端上面创建的ldap:zdh1234 1.安装LDAP client认证需要的pam包 yum ...

  6. js_给元素增加或移除style属性

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. Selenium_使用execute_script执行JavaScript(11)

    selenium的包含的方法已能完全满足UI自动化,但是有些时候又不得不用到执行JS的情况,比如在一个富文本框中输入1W个字,使用send_keys方法将经历漫长的输入过程,如果换成使用JS的inne ...

  8. minio + kkFileView 实现在线预览

    minio上传的pdf之类文件不支持预览,地址在浏览器访问时会直接下载,现在搭配kkFileView文件预览 1.minio查看之前的安装方式 2.kkFileView安装 docker方式 1.拉取 ...

  9. Linux如何对文件内容中的关键字进行查找

    如果是用vi打开文件后,在命令行下输入"/关键字"如果是在没有打开文件的前提就用"cat 文件名 | grep "关键字"

  10. linux VI命令快捷键

    ctrl+f  下一页 ctrl+b 上一页 ctrl+u 上半页 ctrl+d 下半页 数字+空格键 根据当前光标移动多少个字母 0键 光标移动到第一个字母,是当前行的 $键 光标移动到最后一个字母 ...