上週五好不容易用Python內建的Tkinter將操作介面拉好且測試OK,沒想到在打包成執行檔(.exe)這邊花了一個上午,所以紀錄一下自己的碰壁流程。
工作環境:
-Windows 10, Windows Server 2019
-Anaconda 2020.02
-Python 3.6.10
問題描述:
pip install pyinstaller
cd C:\Users\*\Documents\GUI-20200323
pyinstaller main.py
File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 253, in visit
return visitor(node)
File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 263, in generic_visit
self.visit(value)
File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 253, in visit
return visitor(node)
File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 263, in generic_visit
self.visit(value)
File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 253, in visit
return visitor(node)
File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 263, in generic_visit
self.visit(value)
File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 253, in visit
return visitor(node)
File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 257, in generic_visit
for field, value in iter_fields(node):
RecursionError: maximum recursion depth exceeded
突然蹦出這些有的沒的,解決方法很簡單,看一下.py檔存放路徑是不是出現了main.spec這個由PyInstaller自動產生的配置文件,用筆記本打開後新增下面兩行代碼後儲存離開,然後保險起見將build和dist兩個資料夾刪除:
原因在於超過遞迴限制,我也看不懂這什麼意思。[8]
# -*- mode: python ; coding: utf-8 -*-
import sys #我是新增的
sys.setrecursionlimit(9000000) #我是新增的,這邊數字越大越好
block_cipher = None
a = Analysis(['main.py'],
pathex=['C:\\Users\\*\\Documents\\GUI-20200323'],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyinstaller main.spec
等了一會兒後終於跑完了:
113390 INFO: checking EXE
113390 INFO: Building EXE because EXE-00.toc is non existent
113391 INFO: Building EXE from EXE-00.toc
113391 INFO: Appending archive to EXE C:\Users\*\Documents\GUI-20200323\build\main\main.exe
113486 INFO: Building EXE from EXE-00.toc completed successfully.
113501 INFO: checking COLLECT
113502 INFO: Building COLLECT because COLLECT-00.toc is non existent
113502 INFO: Building COLLECT COLLECT-00.toc
184733 INFO: Building COLLECT COLLECT-00.toc completed successfully.
我們來看看main.exe是不是可以正常地打開吧,main.exe的位置在:
C:\Users\*\Documents\GUI-20200323\dist\main\main.exe
但是等等,為什麼會閃退!!!原來打包成功並不等於.exe可以順利執行呀。既然這樣那我們改用終端機來開啟.exe,這樣就能知道程是閃退的原因了[1]:
(keras4) C:\Users\*\Documents\GUI-20200323>cd C:\Users\*\Documents\GUI-20200323\dist\main #切換路徑到main.exe的位置
(keras4) C:\Users\*\Documents\GUI-20200323\dist\main>main.exe #執行
Traceback (most recent call last):
File "site-packages\PyInstaller\loader\rthooks\pyi_rth_pkgres.py", line 13, in <module>
File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 623, in exec_module
exec(bytecode, module.__dict__)
File "site-packages\pkg_resources\__init__.py", line 86, in <module>
ModuleNotFoundError: No module named 'pkg_resources.py2_warn'# 這個是問題來源
[15208] Failed to execute script pyi_rth_pkgres
(keras4) C:\Users\*\Documents\GUI-20200323\dist\main>
原來是因為PyInstaller再打包過程中漏掉pkg_resources.py2_warn導致產生的.exe無法順利執行。這時我們再次開啟配置文件.spec,手動添加pkg_resources.py2_warn吧,記得再次執行main.spec前要先刪掉build、dist兩個資料夾[2][3][4]:
# -*- mode: python ; coding: utf-8 -*-
import sys
sys.setrecursionlimit(9000000)
block_cipher = None
a = Analysis(['main.py'],
pathex=['C:\\Users\\*\\Documents\\GUI-20200323'],
binaries=[],
datas=[],
hiddenimports=['pkg_resources.py2_warn'], #我是新增的
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyinstaller main.spec
現在我們再次執行.exe,結果又閃退了...,沒關係我們用上面講的方法,透過終端機來執行.exe檔就能知道問題了:
(keras4) C:\Users\*\Documents\GUI-20200323>cd C:\Users\*\Documents\GUI-20200323\dist\main #切換路徑到main.exe的位置
(keras4) C:\Users\*\Documents\GUI-20200323\dist\main>main.exe # 執行
Traceback (most recent call last):
File "main.py", line 3, in <module>
File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 623, in exec_module
exec(bytecode, module.__dict__)
File "mylib.py", line 10, in <module>
File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 623, in exec_module
exec(bytecode, module.__dict__)
File "site-packages\sklearn\linear_model\__init__.py", line 12, in <module>
File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 623, in exec_module
exec(bytecode, module.__dict__)
File "site-packages\sklearn\linear_model\_least_angle.py", line 22, in <module>
File "sklearn\utils\arrayfuncs.pyx", line 1, in init sklearn.utils.arrayfuncs
ModuleNotFoundError: No module named 'sklearn.utils._cython_blas'# 這個是問題來源
[11656] Failed to execute script main
(keras4) C:\Users\*\Documents\GUI-20200323\dist\main>
這次是打包過程中漏掉sklearn.utils._cython_blas,PyInstaller你這個小淘氣~:
# -*- mode: python ; coding: utf-8 -*-
import sys
sys.setrecursionlimit(9000000)
block_cipher = None
a = Analysis(['main.py'],
pathex=['C:\\Users\\*\\Documents\\GUI-20200323'],
binaries=[],
datas=[],
hiddenimports=['pkg_resources.py2_warn', 'sklearn.utils._cython_blas'], # 再加1個
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
a = Analysis(['main.py'],
pathex=['C:\\Users\\*\\Documents\\GUI-20200323'],
binaries=[],
datas=[],
hiddenimports=['pkg_resources.py2_warn', 'sklearn.utils._cython_blas'],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='main',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False # console要從True改成False)
結論:
# -*- mode: python ; coding: utf-8 -*-
import sys # 這邊要注意
sys.setrecursionlimit(9000000) # 這邊要注意
block_cipher = None
a = Analysis(['main.py'],
pathex=['C:\\Users\\e10832\\Documents\\GUI-20200323'],
binaries=[],
datas=[],
hiddenimports=['pkg_resources.py2_warn', 'sklearn.utils._cython_blas'], # 這邊要注意
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='main',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True )# 命令視窗開啟(True)
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='main')
參考資料:
[1]https://blog.csdn.net/weixin_41417982/article/details/82216363
[2]https://blog.csdn.net/qq_40587575/article/details/86500445
[3]https://blog.csdn.net/j754379117/article/details/77281354
[4]https://medium.com/@peaceful0907/%E5%B0%87%E4%BD%A0%E7%9A%84python-code-%E6%89%93%E5%8C%85-pyinstaller-6777d0e06f58
[5]https://zhuanlan.zhihu.com/p/58199926
[6]https://zhuanlan.zhihu.com/p/40716095
[7]https://zhuanlan.zhihu.com/p/76974787
[8]https://xken831.pixnet.net/blog/post/463075799-%5Bpython%5D-%E8%A7%A3%E6%B1%BA-recursionerror%3A-maximum-recursion-depth-exce