Usando la excelente respuesta de Max y esta publicación sobre agregar archivos de datos adicionales como imágenes o sonido y mi propia investigación / prueba, descubrí lo que creo que es la forma más fácil de agregar dichos archivos.
Si desea ver un ejemplo en vivo, mi repositorio está aquí en GitHub.
Nota: esto es para compilar usando el comando --onefile
o -F
con pyinstaller.
Mi entorno es el siguiente.
Resolviendo el problema en 2 pasos
Para resolver el problema, necesitamos decirle específicamente a Pyinstaller que tenemos archivos adicionales que necesitan ser "empaquetados" con la aplicación.
También necesitamos usar una ruta 'relativa' , para que la aplicación pueda ejecutarse correctamente cuando se ejecuta como un script de Python o un EXE congelado.
Dicho esto, necesitamos una función que nos permita tener rutas relativas. Usando la función que Max Posted podemos resolver fácilmente la ruta relativa.
def img_resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
Usaríamos la función anterior de esta manera para que el ícono de la aplicación aparezca cuando la aplicación se esté ejecutando como Script O Frozen EXE.
icon_path = img_resource_path("app/img/app_icon.ico")
root.wm_iconbitmap(icon_path)
El siguiente paso es que necesitamos indicarle a Pyinstaller dónde encontrar los archivos adicionales cuando se está compilando para que cuando se ejecute la aplicación, se creen en el directorio temporal.
Podemos resolver este problema de dos maneras, como se muestra en la documentación , pero personalmente prefiero administrar mi propio archivo .spec, así es como lo haremos.
Primero, ya debe tener un archivo .spec. En mi caso, pude crear lo que necesitaba ejecutando pyinstaller
con argumentos adicionales, puede encontrar argumentos adicionales aquí . Debido a esto, mi archivo de especificaciones puede verse un poco diferente al suyo, pero lo publicaré como referencia después de explicar los puntos importantes.
added_files es esencialmente una lista que contiene tuplas, en mi caso solo quiero agregar una imagen ÚNICA, pero puede agregar múltiples ico, png o jpg usando('app/img/*.ico', 'app/img')
También puede crear otra tupla comoadded_files = [ (), (), ()]
para tener múltiples importaciones
La primera parte de la tupla define qué archivo o qué tipo de archivo le gustaría agregar, así como dónde encontrarlos. Piense en esto como CTRL + C
La segunda parte de la tupla le dice a Pyinstaller que haga la ruta 'app / img /' y coloque los archivos en ese directorio RELATIVOS a cualquier directorio temporal que se cree cuando ejecuta el .exe. Piense en esto como CTRL + V
Debajoa = Analysis([main...
, configurédatas=added_files
, originalmente solía ser,datas=[]
pero queremos que la lista de importaciones sea, bueno, importada, así que pasamos nuestras importaciones personalizadas.
No necesita hacer esto a menos que desee un ícono específico para el EXE, en la parte inferior del archivo de especificaciones le digo a Pyinstaller que configure el ícono de mi aplicación para el exe con la opción icon='app\\img\\app_icon.ico'
.
added_files = [
('app/img/app_icon.ico','app/img/')
]
a = Analysis(['main.py'],
pathex=['D:\\Github Repos\\Processes-Killer\\Process Killer'],
binaries=[],
datas=added_files,
hiddenimports=[],
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,
a.binaries,
a.zipfiles,
a.datas,
[],
name='Process Killer',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True , uac_admin=True, icon='app\\img\\app_icon.ico')
Compilar a EXE
Soy muy flojo; No me gusta escribir cosas más de lo necesario. He creado un archivo .bat en el que puedo hacer clic. No tiene que hacer esto, este código se ejecutará en un shell del símbolo del sistema perfectamente sin él.
Dado que el archivo .spec contiene todas nuestras configuraciones y argumentos de compilación (también conocidos como opciones), solo tenemos que darle ese archivo .spec a Pyinstaller.
pyinstaller.exe "Process Killer.spec"
a.datas += ...
) realmente me ayudó en este momento. la documentación de pyinstaller habla sobre el uso,COLLECT
pero eso no logra poner archivos en el binario cuando se usa--onefile