PyInstaller, archivo de especificaciones, ImportError: ningún módulo llamado 'blah'
Estoy intentando crear un script en Python a través de PyInstaller . He utilizado los siguientes comandos para configurar, generar un archivo de especificaciones y compilar:
wget pyinstaller.zip, extracted it, python Configure.py, etc, then:
python pyinstaller/Makespec.py --onefile myscript.py
python pyinstaller/Build.py myscript.spec
Aquí está el archivo de especificaciones que generó:
# -*- 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 )
Esto creó un archivo ejecutable en dist/
el directorio. Al intentar ejecutar este archivo, aparece lo siguiente:
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
Si moví este ejecutable al directorio del código Python real, dio resultados diferentes:
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
En los documentos ... de pyinstaller veo que esa --onefile
es la opción que necesito/quiero, pero por alguna razón no se está compilando todo.
En realidad, el script no incluye nada sofisticado, solo pequeños módulos rápidos que escribí para declaraciones SQL y análisis de ciertos sitios web.
Este error puede ocurrir cuando tienes importaciones dinámicas en tu código. En ese caso, pyinstaller no incluye esos paquetes en el archivo exe. En ese caso puedes:
- Agregue la importación no utilizada de esos paquetes en su código
- Dile a pyinstaller que lo incluya
Una opción de archivo no cambia nada al ejecutar su código. Si crea --onefile exe, todos los archivos creados por pyinstaller se empaquetan en un archivo exe y se descomprimen en la temperatura local cada vez que ejecuta exe.
El problema es que pyinstaller no verá importaciones de segundo nivel . Entonces, si importa el módulo A , pyinstaller ve esto. Pero no se verá ningún módulo adicional que se importe en A.
No es necesario cambiar nada en sus scripts de Python. Puede agregar directamente las importaciones que faltan al archivo de especificaciones . Simplemente agregue lo siguiente en a = Analysis(...)
:
hiddenimports=["mysql"],
Este debería ser el resultado:
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"],)
Después de eso, ejecute pyinstaller con el archivo de especificaciones como argumento.
Solo agregaré mis 2 centavos porque encontré el mismo problema hoy, 6 años después: D
Para ventanas:
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 )
Luego pude ejecutar el exe haciendo doble clic.
Resultó ser bastante fácil. Lo que funcionó para mí fue "--onefile" y agregar mis otros archivos a la carpeta "dist".
El "--windowed" es solo para que la ventana de comando de Python no aparezca cuando inicias el exe.