python - cx_Freeze-Previniendo incluyendo paquetes innecesarios
deployment pyqt (1)
La razón por la que no funciona el comando "excluye" fue que olvidé incluir las opciones de compilación en la configuración. Después de agregar la línea respectiva en el código excluyendo trabajos:
from cx_Freeze import setup, Executable
import sys
# exclude unneeded packages. More could be added. Has to be changed for
# other programs.
build_exe_options = {"excludes": ["tkinter", "PyQt4.QtSql", "sqlite3",
"scipy.lib.lapack.flapack",
"PyQt4.QtNetwork",
"PyQt4.QtScript",
"numpy.core._dotblas",
"PyQt5"],
"optimize": 2}
# Information about the program and build command. Has to be adjusted for
# other programs
setup(
name="MyProgram", # Name of the program
version="0.1", # Version number
description="MyDescription", # Description
options = {"build_exe": build_exe_options}, # <-- the missing line
executables=[Executable("MyProgram.py", # Executable python file
base = ("Win32GUI" if sys.platform == "win32"
else None))],
)
Esto disminuyó el tamaño del programa de 230MB a 120MB. Sin embargo, no encontré una buena manera de excluir todos los paquetes innecesarios. Por prueba y error (eliminando los archivos más grandes en la carpeta de compilación en cuanto a las pruebas), descubrí las clases que puedo excluir.
Intenté si los backends matplotlib causan el problema y finalmente descubrí que este no es el caso. No obstante, si alguien necesita un código para excluir todos los módulos de un determinado esquema de nombre en una carpeta particular, excepto algunos especiales, puede ajustar lo siguiente a sus necesidades:
mplBackendsPath = os.path.join(os.path.split(sys.executable)[0],
"Lib/site-packages/matplotlib/backends/backend_*")
fileList = glob.glob(mplBackendsPath)
moduleList = []
for mod in fileList:
modules = os.path.splitext(os.path.basename(mod))[0]
if not module == "backend_qt4agg":
moduleList.append("matplotlib.backends." + modules)
build_exe_options = {"excludes": ["tkinter"] + moduleList, "optimize": 2}
Me alegraría con soluciones más elegantes. Las ideas adicionales son bienvenidas. Sin embargo, considero el problema como resuelto para mí.
He codificado un pequeño programa python usando PyQt4. Ahora, quiero usar cx_Freeze para crear una aplicación independiente. Todo funciona bien: cx_Freeze incluye automáticamente todos los módulos necesarios; el exe resultante funciona.
El único problema es que cx_Freeze incluye muchos módulos innecesarios en la versión independiente. Aunque solo uso QtCore y QtGui, también se incluyen módulos como sqlite3, QtNetwork o QtScript. Sorprendentemente, también encontré las dlls PyQt5 en la carpeta resultante. Me parece que cx_Freeze usa todos los paquetes PyQt que he instalado. El resultado es un programa de 200Mb, aunque solo escribí un pequeño script.
¿Cómo puedo prevenir este comportamiento?
Yo uso el siguiente setup.py:
import sys
from cx_Freeze import setup, Executable
setup(
name="MyProgram",
version="0.1",
description="MyDescription",
executables=[Executable("MyProgram.py", base = "Win32GUI")],
)
Traté de excluir explícitamente algunos paquetes (aunque es bastante complicado excluir todos los módulos Qt no utilizados) agregando este código:
build_exe_options = {"excludes": ["tkinter", "PyQt4.sqlite3",
"PyQt4.QtOpenGL4", "PyQt4.QtSql"]}
pero los módulos superiores todavía se usaban. También intenté
build_exe_options = {"excludes": ["tkinter", "PyQt4.sqlite3",
"QtOpenGL4", "QtSql"]}
con el mismo resultado
Además de los paquetes QT de nedless, también encuentro carpetas innecesarias con nombres como "imageformats", "tcl" y "tk". ¿Cómo puedo incluir solo los archivos necesarios para mantener la carpeta independiente y el instalador lo más pequeños posible?
Busqué en Google este problema por horas, pero solo encontré este hilo que no me ayudó.
Estoy ejecutando python 3.4.2 amd64 en Windows 8.
Estoy contento con cada solución que me da el resultado deseado "independiente" con un tamaño razonable. Intenté también pyqtdeploy pero encontré el error: módulo (s) desconocido (s) en QT (pero esta es una pregunta diferente).
Editar:
Estoy usando dos módulos. Una es la clase de GUI creada por uic, "MyProgramGUIPreset". En este archivo, existen los siguientes comandos de importación:
from PyQt4 import QtCore, QtGui
from matplotlibwidget import MatplotlibWidget
En el módulo principal hago las siguientes importaciones:
import MyProgramGUIPreset
import numpy as np
from PyQt4.QtGui import QApplication, QMainWindow, QMessageBox
import sys
from math import *
Tal vez esto ayude a descubrir dónde está el problema.