2011-03-18 14 views
18

Siendo bastante nuevo en python, recientemente descubrí la capacidad de ejecutar directamente un archivo .zip al colocar un archivo __main__.py en la parte superior del archivo. Esto funciona muy bien para el código python, pero ¿puedo agrupar otros tipos de archivos y acceder a ellos con mis scripts? ¿Si es así, cómo?python: ¿pueden los archivos zip ejecutables incluir archivos de datos?

Mi objetivo final es agrupar algunos archivos de imagen junto con el código python en un solo archivo .zip, y luego poder usar esas imágenes dentro de la aplicación sin tener que extraerlas en el disco. También me gustaría incluir un aviso de derechos de autor, notas de la versión, etc. para que toda la aplicación y sus archivos de datos estén en un único archivo zip que se puede ejecutar sin tener que extraerlo en otro lugar.

Respuesta

15

Usted podría utilizar pkg_resources funciones 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() 

Dónde archivo zip contiene:

. 
|-- app 
| |-- im.png 
| `-- __init__.py 
|-- README.txt 
`-- __main__.py

Para hacer ejecutable archivo zip, ejecutar:

$ 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 
+1

esto funciona solo con el módulo pkg_resources distribuido con setuptools instalado –

+1

hay un módulo ['zipapp' en Python 3.5] (https://docs.python.org/3/library/zipapp.html) que automatiza la creación del archivo. – jfs

5

Al menos en mi caja de Linux no hay memoria de archivo abierta ni memoria mapeada por el proceso a su propio archivo zip, así que presumiblemente no hay forma de acceder "mágicamente" a él.

Sin embargo, crear su propio acceso no es tan difícil. Crear 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() 

Editar: De alguna manera concisa, que. Para completar:

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

Nunca se me ocurrió volver a abrir el archivo zip se está ejecutando actualmente. Guay. Lamentablemente, cuando ejecuto mi script en OSX '__file__' es' None'. Creo que este es un paso en la dirección correcta. –

+0

@Bryan Oakley: 'sys.argv [0]' contiene la ruta del archivo zip si la primera línea del archivo zip es '#!/Usr/bin/env python' o similar. – jfs

5

simplemente utilizar pkgutil.get_data() como se sugiere en this answer

+0

esto solo funciona si pongo mis archivos en un paquete, lo que significa que no funcionará para un archivo README.txt o COPYRIGHT.txt en la raíz del archivo zip. No es un problema crítico, pero me gustaría poder poner algunos archivos junto con el __main__.py en la parte superior de la jerarquía del archivo zip. –

+0

Normalmente su módulo principal es accesible a través de la importación '__main__' usted puede referirse a él –

+0

Combell: Ojalá fuera cierto. Al menos con mi prueba.archivo zip en OSX y python 2.6, __main__ no está definido. –

0

pkgutil.get_data(package, resource) toma el nombre de un paquete y un recurso. Eso significa que debe 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 

__init__.py El archivo puede estar vacío o simplemente un comentario, pero se necesita uno para hacer zippeddata importables.

Luego, en __main__.py que acaba de llamar:

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