PyInstaller对工作目录敏感:执行路径引发Unicode解码错误
PyInstaller构建程序因工作目录不同导致运行异常问题
使用PyInstaller构建应用程序时,程序运行行为会随执行时的工作目录变化而产生差异,示例如下:
user:~$ ./project/dist/runmyapp <运行失败> user:~$ /home/user/project/dist/runmyapp <运行失败> user:~$ cd project user:~/project$ ./dist/runmyapp <运行正常> user:~/project$ /home/user/project/dist/runmyapp <运行正常>
运行失败时会抛出奇怪的Unicode错误:
Traceback (most recent call last): File "tokenize.py", line 330, in find_cookie UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa8 in position 128: invalid start byte During handling of the above exception, another exception occurred: Traceback (most recent call last): File "runmyapp", line 3, in <module> File "<frozen importlib._bootstrap>", line 991, in _find_and_load File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 671, in _load_unlocked File "PyInstaller/loader/pyimod02_importers.py", line 385, in exec_module <大量栈追踪信息> File "traceback.py", line 197, in format_stack File "traceback.py", line 211, in extract_stack File "traceback.py", line 366, in extract File "traceback.py", line 288, in line File "linecache.py", line 16, in getline File "linecache.py", line 47, in getlines File "linecache.py", line 136, in updatecache File "tokenize.py", line 394, in open File "tokenize.py", line 371, in detect_encoding File "tokenize.py", line 335, in find_cookie SyntaxError: invalid or missing encoding declaration for '/home/user/project/dist/runmyapp' [7407] Failed to execute script 'runmyapp' due to unhandled exception!
查看PyInstaller生成的可执行文件./dist/runmyapp的字节内容,第128位确实是0xa8:
00000080: a802 0000 0000 0000 a802 4000 0000 0000 ..........@..... ^^
无论在哪个目录运行,这个字节值都不会改变。这是PyInstaller的bootloader可执行文件,Python解释器本不应将其当作脚本文件读取。
推测程序运行时尝试读取相对于当前工作目录的某个文件,而该路径恰好指向了可执行文件本身。但代码中不会引用PyInstaller构建前不存在的可执行文件,且目标路径应随目录变化,却仅在一个目录下能正常运行。
Stack Overflow上有很多PyInstaller相关的UnicodeDecodeError案例,但均与本问题不同。无法从栈追踪中得知程序为何会将runmyapp当作脚本读取,因此陷入困境。
求解答!谢谢!
2023年7月12日更新
以下是最小复现示例,使用Python 3.8.10和PyInstaller 5.13.0。
文件结构
/ /pyitest/ /pyitest/__init__.py /pyitest/__main__.py /runtest /setup.py
__main__.py内容
import traceback def main(): traceback.print_stack() if __name__ == "__main__": main()
runtest内容
#!/usr/bin/env python3 from pyitest.__main__ import main main()
setup.py内容
from setuptools import setup, find_packages package_name = 'pyitest' setup(name=package_name, packages=find_packages(exclude=['tests']), include_package_data=True, setup_requires='wheel', entry_points={ 'console_scripts': [ 'runtest = pyitest.__main__:main' ] } )
构建步骤
$ mktemp -d ./pyibuild.XXXXXX ./pyibuild.3TbKYF $ cp runtest ./pyibuild.3TbKYF/ $ python setup.py build $ pyi-makespec --paths build/lib ./pyibuild.3TbKYF/runtest $ pyinstaller runtest.spec
运行测试
$ ./dist/runtest/runtest (运行正常) $ cd .. $ <project_root>/dist/runtest/runtest Traceback (most recent call last): File "tokenize.py", line 330, in find_cookie UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc0 in position 40: invalid start byte During handling of the above exception, another exception occurred: Traceback (most recent call last): File "runtest", line 6, in <module> File "pyitest/__main__.py", line 5, in main File "traceback.py", line 190, in print_stack File "traceback.py", line 211, in extract_stack File "traceback.py", line 366, in extract File "traceback.py", line 288, in line File "linecache.py", line 16, in getline File "linecache.py", line 47, in getlines File "linecache.py", line 136, in updatecache File "tokenize.py", line 394, in open File "tokenize.py", line 371, in detect_encoding File "tokenize.py", line 335, in find_cookie SyntaxError: invalid or missing encoding declaration for '<project_root>/dist/runtest/runtest' [44713] Failed to execute script 'runtest' due to unhandled exception!
内容的提问来源于stack exchange,提问作者maldata
相关产品推荐
相关产品推荐

