问题出处
代码如下:
# -*- coding: utf-8 -*-
from gooey import Gooey, GooeyParser
def run(keywords):
print(keywords)
@Gooey(
richtext_controls=True, # 打开终端对颜色支持
language='chinese',
header_show_title=False,
program_name="test", # 程序名称
encoding="utf-8", # 设置编码格式,打包的时候遇到问题
progress_regex=r"^progress: (\d+)%$", # 正则,用于模式化运行时进度信息
default_size=(905, 640),
)
def main():
description = "test"
parser = GooeyParser(description=description)
parser.add_argument('keywords', help="关键词")
args = parser.parse_args()
run(args.keywords)
main()
随手键入搜索引擎,发现其他地方也有人在询问或反馈类似问题,估计是个偏门问题,查找了一圈没有发现解决方案,所以献丑将解决方案记录于此,方便有需要的人查阅。
分析过程
python3.8环境,使用了Gooey的gui库(我也是第一次接触这个库),说打包后中文无法显示。
出于谨慎,我先将源码跑了一遍,发现很丝滑,没有丝毫问题。
随即使用pyinstaller将其进行打包,然而令人惊呆的事情出现了,用pyinstaller打包之后一运行输入中文就出错了(此处我是直接打包.py源码文件)。
感谢楼下@fanvalen 的热心回复补充,Gooey打包exe方法跟普通打包方式不一样,需要使用pyinstaller build.spec。详见@fanvalen 回复楼层。
实测使用build.spec方式打包依旧无法正常输出中文,并且该方式打包运行后输入中文不会出现报错信息,程序只会一直卡顿。本篇解决思路同样适用。
报错信息如下:
Exception in thread Thread-1:
Traceback (most recent call last):
File "threading.py", line 932, in _bootstrap_inner
File "threading.py", line 870, in run
File "gooey\gui\processor.py", line 70, in _forward_stdout
File "gooey\gui\processor.py", line 84, in _extract_progress
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc4 in position 0: invalid continuation byte
一看报错就发现是编码问题,所以想着要从编码入手。
解决思路
本着“大胆假设,小心求证”的精神,先将代码gooey的encoding="utf-8"参数改为gbk、gb2312、gb18030,无果,还直接报错。
随即换了个思路,是否是输出的编码有问题。
所以又将print语句的编码为utf-8、gbk再解码为utf-8、gbk,依旧无果。
本来想着就在代码里面改会简单快捷一点,但是无奈,看样子还是得回到报错代码上去了。
一看错误代码gooey/gui/processor.py的70行和84行,找到该库安装路径。
python安装路径下Libsite-packages/gooey/gui/processor.py
一眼就看到self.encoding这个参数很可疑。
通过追踪上下文的运行过程,发现有点儿意思,代码如下:
def _forward_stdout(self, process):
'''
Reads the stdout of `process` and forwards lines and progress
to any interested subscribers
'''
while True:
line = process.stdout.readline() #同样的代码 打包前此处读取为utf-8编码 打包后却成为了gbk编码 所以一打包就无法输出中文 有兴趣的小伙伴可以print到控制台看结果
if not line:
break
_progress = self._extract_progress(line)
pub.send_message(events.PROGRESS_UPDATE, progress=_progress)
if _progress is None or self.hide_progress_msg is False:
pub.send_message(events.CONSOLE_UPDATE,
msg=line.decode("gbk")) #decode默认参数self.encoding 改为gbk打包即可显示中文
pub.send_message(events.EXECUTION_COMPLETE)
def _extract_progress(self, text):
'''
Finds progress information in the text using the
user-supplied regex and calculation instructions
'''
# monad-ish dispatch to avoid the if/else soup
find = partial(re.search, string=text.strip().decode("gbk")) #decode默认参数self.encoding 改为gbk打包即可显示中文
regex = unit(self.progress_regex)
match = bind(regex, find)
result = bind(match, self._calculate_progress)
return result
同样的代码,打包前是utf-8编码,打包后又变成了gbk编码。
初步推测一下,可能是两个库都是老外编写的,某一个对中文的支持不太好。也可能是window下默认编码问题。(手动滑稽,哈哈哈哈)
因为打包后变成了gbk编码,所以解码自然就要解码为gbk。
两处参数一改,搞定,也就不想再继续深究了,本身对Gooey也不太感冒,虽然这是个很棒的作品。
请注意,打包完记得改回原来的参数,避免出现其他意外情况。
总结
这是一个治标不治本的方法,如果想要彻底解决,估计只有将pyinstaller的打包流程和Gooey的代码都深入研究一番,不然估计有点难。
window10环境下打包完之后自己实测跑了几波已经能够输出中文,未见其他异常,完美解决。其他系统请自测。