PyInstaller,spec文件,导入错误:没有名为'blah'的模块
我正在尝试通过PyInstaller来构建一个Python脚本。我使用了以下命令来配置、生成一个规格文件,并进行构建:
wget pyinstaller.zip, extracted it, python Configure.py, etc, then:
python pyinstaller/Makespec.py --onefile myscript.py
python pyinstaller/Build.py myscript.spec
这是它生成的规格文件:
# -*- mode: python -*-
a = Analysis([os.path.join(HOMEPATH,'support/_mountzlib.py'), os.path.join(HOMEPATH,'support/useUnicode.py'), 'icinga.py'],
pathex=['/home/user/projects/icinga_python/releases/v2.1'])
pyz = PYZ(a.pure)
exe = EXE( pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
name=os.path.join('dist', 'myscript'),
debug=False,
strip=False,
upx=True,
console=1 )
这在dist/
目录下生成了一个可执行文件。当我尝试运行这个文件时,出现了以下问题:
Traceback (most recent call last):
File "<string>", line 12, in <module>
File "/home/user/projects/myscript/releases/v2.1/pyinstaller/iu.py", line 455, in importHook
raise ImportError, "No module named %s" % fqname
ImportError: No module named mysql
如果我把这个可执行文件移动到实际Python代码所在的目录,它给出的结果就不一样了:
Traceback (most recent call last):
File "<string>", line 12, in <module>
File "/home/user/projects/myscript/releases/v2.1/pyinstaller/iu.py", line 436, in importHook
mod = _self_doimport(nm, ctx, fqname)
File "/home/user/projects/myscript/releases/v2.1/pyinstaller/iu.py", line 521, in doimport
exec co in mod.__dict__
File "CLUSTER/mysql/icingasql.py", line 13, in <module>
import urllib2
File "/home/user/projects/myscript/releases/v2.1/pyinstaller/iu.py", line 455, in importHook
raise ImportError, "No module named %s" % fqname
ImportError: No module named urllib2
在... pyinstaller文档中,我看到--onefile
是我需要的选项,但不知为何并不是所有内容都被编译进去了。
这个脚本其实没有包含什么复杂的东西,只是我为SQL语句和解析某些网站写的一些小模块。
3 个回答
我也来分享一下我的经验,因为我今天遇到了同样的问题,时隔6年了 :D
对于Windows系统:
1) cmd => rightclick => with admin rights
2) Enter in cmd: "pip install pyinstaller"
3) navigate in cmd to the folder of "yourMain.py"
4) Enter in cmd: "pyinstaller --onefile --windowed yourMain.py"
5) If you import other scripts / data in "yourMain.py":
Manually enter the folder "dist" (gets created - where "yourMain.exe" should be by now),
and copy your scripts or folder structure there
(e.g. /assets/sounds; /assets/graphics; /scripts; anotherscript.py )
然后我就可以通过双击来运行这个exe文件了。
其实这件事挺简单的。对我来说,关键是使用了“--onefile”这个选项,并把其他文件放到“dist”文件夹里。
至于“--windowed”,这个选项的作用是让你启动exe时,不会弹出Python命令窗口。
问题在于,pyinstaller 不能识别二级导入。也就是说,如果你导入了模块A,pyinstaller 能看到这个模块。但是,如果A里面又导入了其他模块,pyinstaller 就看不到了。
你不需要修改你的 Python 脚本。你可以直接把缺失的导入添加到spec 文件中。只需在a = Analysis(...)
中添加以下内容:
hiddenimports=["mysql"],
这样就可以了:
a = Analysis([os.path.join(HOMEPATH,'support/_mountzlib.py'), os.path.join(HOMEPATH,'support/useUnicode.py'), 'icinga.py'],
pathex=['/home/user/projects/icinga_python/releases/v2.1'], hiddenimports=["mysql"],)
之后,使用 spec 文件作为参数运行 pyinstaller。
这个错误可能发生在你的代码中使用了动态导入的时候。在这种情况下,pyinstaller不会把那些包包含进exe文件里。你可以这样做:
- 在你的代码中添加那些包的未使用导入
- 告诉pyinstaller把它包含进去
使用单文件选项并不会改变你运行代码的方式。如果你创建了一个--onefile的exe,pyinstaller生成的所有文件都会打包到这个exe文件里,每次你运行exe时,它们会被解压到本地临时文件夹。