Python: ¿pueden los archivos zip ejecutables incluir archivos de datos?

Al ser bastante nuevo en Python, recientemente descubrí la capacidad de ejecutar directamente un archivo .zip colocando un archivo __main__.py en la parte superior del archivo. Esto funciona muy bien para el código de Python, pero ¿puedo agrupar otros tipos de archivos y acceder a ellos con mis scripts? ¿Si es así, cómo?

Mi objective final sería agrupar algunos archivos de imagen junto con el código de Python en un solo archivo .zip, para luego poder usar esas imágenes dentro de la aplicación sin tener que extraerlas en el disco. También me gustaría agrupar un aviso de copyright, notas de la versión, etc. para que la aplicación completa y sus archivos de datos estén en un solo archivo zip que se pueda ejecutar sin tener que extraerlo en alguna parte.

Podría usar pkg_resources funciones pkg_resources para acceder a los archivos:

 # __main__.py import pkg_resources from PIL import Image print pkg_resources.resource_string(__name__, 'README.txt') im = Image.open(pkg_resources.resource_stream('app', 'im.png')) im.rotate(45).show() 

Donde zipfile contiene:

  .
 | - aplicación
 |  | - im.png
 |  `- __init__.py
 | - README.txt
 `- __main__.py 

Para hacer ejecutable el archivo zip, ejecute:

 $ echo '#!/usr/bin/env python' | cat - zipfile > program-name $ chmod +x program-name 

Para probarlo:

 $ cp program-name /another-dir/ $ cd /another-dir && ./program-name 

simplemente use pkgutil.get_data () como se sugiere en esta respuesta

Al menos en mi caja de Linux no hay un identificador de archivo abierto o una memoria asignada por el proceso a su propio archivo zip, por lo que presumiblemente no hay manera de acceder “mágicamente” a él.

Sin embargo, crear tu propio acceso no es tan difícil. Crea un __main__.py así:

 import os, zipfile me = zipfile.ZipFile(os.path.dirname(__file__), 'r') f = me.open('other.txt') print f.read() f.close() me.close() 

Edit: Algo conciso, eso. Por completitud:

 $ echo "Hello ZIP" > other.txt $ zip testo.zip __main__.py other.txt $ python testo.zip Hello ZIP 

pkgutil.get_data(package, resource) toma el nombre de un paquete y un recurso. Eso significa que tiene que colocar sus archivos de datos dentro de un paquete dentro del archivo zip.

Así, por ejemplo, un archivo zip que contiene:

 __main__.py zippeddata/__init__.py zippeddata/data.txt 

El archivo __init__.py puede estar vacío o solo un comentario, pero necesita uno para hacer que los datos zippeddata sean zippeddata .

Luego, en __main__.py usted acaba de llamar:

 data = pkgutil.get_data('zippeddata', 'data.txt')