Ya ha pasado algún tiempo desde que escribí cómo empaquetar un archivo de Python en un ejecutable. No pensé que tuviera el impacto que tuvo, pero me da gusto al final de todo.
En fin, ahora aquí está la parte 2 en donde muestro cómo agregar assets a nuestro paquete. Por ejemplo, a veces es necesario agregar imágenes, canciones o cualquier archivo extra al empaquetar con pyinstaller.
Cabe mencionar que no fue nada fácil, ya que casi no encontré documentación sobre eso excepto en el sitio oficial.
Será simple. Aprovechando que acabamos de ver cómo leer un archivo de texto, haremos que ese archivo de texto sea empaquetado junto con el ejecutable. Que sea simple no significa que no funcione, ya que con el ejemplo que pondré se verá cómo agregar más assets de todo tipo.
Recuerda mirar el tutorial anterior, estás forzado a ello. Aparte de eso, aquí puedes ver más tutoriales de Python.
Cuando ya tengas listo tu código, empaquétalo normalmente como quieras. En mi caso tengo el archivo main.py
con el siguiente código:
Hola, soy un archivo de texto para demostrar algunos tutoriales de parzibyte.me. Puedo contener cualquier tipo de contenido, por ejemplo, saltos,
tabulaciones
y cualquier
otra
cosa.
"""
Ejemplo simple de cómo leer un archivo
línea por línea en Python 3
@author parzibyte
"""
nombre_archivo = "archivo.txt"
with open(nombre_archivo, "r") as archivo:
for linea in archivo:
print("Aquí hay una línea: ", linea)
Así que para empaquetarlo en un .exe ejecuto lo siguiente:
pyinstaller --onefile main.py
Luego de esperar un momento, se creará lo necesario. Voy a omitir las cosas básicas porque ya las puse en el tutorial anterior. Ahora, lo importante es un archivo con extensión .spec
que se ha creado. Su nombre debe ser el mismo que nuestro script principal, así que en mi caso se llama main.spec
.
Ahora vamos a agregar código (porque es código de Python) de manera que se añadan datos al valor datas
de a
. Así:
a.datas += [("ruta_absoluta_al_archivo", "ruta_al_archivo_que_usamos_en_el_código", "DATA")]
Dentro del arreglo []
podemos agregar las tuplas necesarias, con 3 elementos en cada una de ellas… una tupla por cada archivo.
De manera que solamente cambian las dos primeras cosas, ya que DATA
se queda intacto. En mi caso agregaré el archivo archivo.txt
así que mi spec queda así:
a.datas += [("./archivo.txt", "archivo.txt", "DATA")]
Si fuera necesario, agregaría más tuplas separadas por coma; siempre dentro del arreglo. Para que quede más claro, ahora mi archivo spec se ve así:
Ahora sí ya estamos listos. Por cierto, ya no ejecutes pyinstaller con el script, porque va a sobrescribir el archivo spec. Déjalo intacto, sólo si haces cambios entonces genera de nuevo y modifica.
Lo que sigue es crear una función que resuelva las rutas dependiendo del entorno. Si estamos en desarrollo normalmente, resolverá la ruta normal. Pero si ya está empaquetado, resolverá la ruta en donde se desempaquetan los assets.
import os, sys
def resolver_ruta(ruta_relativa):
if hasattr(sys, '_MEIPASS'):
return os.path.join(sys._MEIPASS, ruta_relativa)
return os.path.join(os.path.abspath('.'), ruta_relativa)
Gracias a _MEIPASS
sabremos si ya estamos “empaquetados” o todavía no. Esta ruta de _MEIPASS
es en donde PyInstaller coloca los assets que le indicamos.
En caso de que no estén empaquetados, la ruta se resuelve normalmente. Por cierto, la función necesita que exista os
y sys
, por eso es que se importan al inicio.
En cada lugar en donde se invoque a un archivo, vamos a cambiarlo para que ahora su ruta sea lo que devuelve resolver_ruta
. Por ejemplo, el código para leer el archivo indica así la ruta:
nombre_archivo = "archivo.txt"
Pero ahora lo cambiaré para que sea lo siguiente:
nombre_archivo = resolver_ruta("archivo.txt")
En tu caso cámbialo por cada imagen, canción o lo que sea. Antes de empaquetar todo, prueba tu código normalmente para ver si realmente se resuelven las rutas.
Como mi script es sencillo, puse la función que resuelve rutas dentro del mismo. Por cierto, agregué un mensaje de “presiona Enter para salir” (usando input) al final para que al ejecutarlo no se cierre inmediatamente. Todo el código queda así:
Hola, soy un archivo de texto para demostrar algunos tutoriales de parzibyte.me. Puedo contener cualquier tipo de contenido, por ejemplo, saltos,
tabulaciones
y cualquier
otra
cosa.
"""
Agregar assets con PyInstaller. Ejemplo de
cómo empaquetar un archivo de texto junto
con el código fuente. El script lee un archivo
línea a línea
@author parzibyte
"""
import os, sys
def resolver_ruta(ruta_relativa):
if hasattr(sys, '_MEIPASS'):
return os.path.join(sys._MEIPASS, ruta_relativa)
return os.path.join(os.path.abspath('.'), ruta_relativa)
nombre_archivo = resolver_ruta("archivo.txt")
with open(nombre_archivo, "r") as archivo:
for linea in archivo:
print("Aquí hay una línea: ", linea)
input("Presiona Enter para salir")
# -*- mode: python -*-
block_cipher = None
a = Analysis(['main.py'],
pathex=['D:\\desarrollo\\ejercicios'],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
a.datas += [("./archivo.txt", "archivo.txt", "DATA")]
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='main',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
runtime_tmpdir=None,
console=True )
También agregué mi main.spec
para que quede de referencia.
Este paso es el más importante. Ahora no haremos esto:
pyinstaller --onefile main.py
Sino que vamos a pasar el nombre del spec, así:
pyinstaller --onefile main.spec
Si no lo haces así, se va a sobescribir el main.spec
.
Después de eso podemos ir a la carpeta dist
en donde ejecutamos el comando, y estará un ejecutable con el nombre de nuestro script, en mi caso main.exe
.
¿No crees que funcione? te invito a descargar el ejecutable. Si se lee el archivo, significa que sí pude empaquetar el asset.
Aquí hay un vídeo con todos los pasos que se explican en el post:
PyInstaller y el archivo spec permiten hacer más cosas. En este caso vimos cómo agregar archivos al ejecutable, pero se pueden hacer más cosas.
Hoy te voy a presentar un creador de credenciales que acabo de programar y que…
Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…
En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…
En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…
Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…
En este artículo te voy a enseñar cómo usar un "top level await" esperando a…
Esta web usa cookies.
Ver comentarios
pyinstaller --onefile --icon=./nombre_archivo.ico maestro_descarga4.py
para crear un archivo ico pone en googl e busca "crear ico online" y sube una imagen (la que deseas) y la conviertes y bajaras esa pero ahora .ico
Saludos M.R.
Gracias por su comentario :)
Saludos. He probado tu tutorial en Linux tal cual pero no me funciono pero di con la solución a partir de tu trabajo.
Partimos del punto de que tenemos el archivo.txt y el main.py tal cual como lo publicas aqui. Lo que hay que hacer es decirle en la terminal:
pyinstaller --onefile main.py --add- data archivo.txt:/
Si el asset que quieres agregar esta dentro de una carpeta entonces le dices el nombre de la carpeta
pyinstaller --onefile main.py --add-data nombrecarpeta/archivo.txt/nombrecarpeta
como puedo agregar una imagen al ejecutable?