2009-09-08 21 views
26

Tengo un proyecto de Python en el que estoy usando muchos archivos que no son de código. Actualmente estas son todas las imágenes, pero podría usar otros tipos de archivos en el futuro. ¿Cuál sería un buen esquema para almacenar y hacer referencia a estos archivos?Administración de recursos en un proyecto de Python

Consideré simplemente hacer una carpeta de "recursos" en el directorio principal, pero hay un problema; Algunas imágenes se usan desde subpaquetes de mi proyecto. Almacenar estas imágenes de esa manera conduciría al acoplamiento, lo cual es una desventaja.

Además, necesito una forma de acceder a estos archivos que es independiente de lo que es mi directorio actual.

Respuesta

34

Es posible que desee utilizar la biblioteca pkg_resources que viene con setuptools.

Por ejemplo, he hecho un pequeño paquete rápida "proj" para ilustrar el esquema de organización de recursos que haría uso:

proj/setup.py 
proj/proj/__init__.py 
proj/proj/code.py 
proj/proj/resources/__init__.py 
proj/proj/resources/images/__init__.py 
proj/proj/resources/images/pic1.png 
proj/proj/resources/images/pic2.png 

Observe cómo guardo todos los recursos en un sub-paquete separado.

"code.py" muestra cómo pkg_resources se utiliza para referirse a los objetos de recursos:

from pkg_resources import resource_string, resource_listdir 

# Itemize data files under proj/resources/images: 
print resource_listdir('proj.resources.images', '') 
# Get the data file bytes: 
print resource_string('proj.resources.images', 'pic2.png').encode('base64') 

Si lo ejecuta, se obtiene:

['__init__.py', '__init__.pyc', 'pic1.png', 'pic2.png'] 
iVBORw0KGgoAAAANSUhE ... 

Si necesita tratamiento para un recurso como un FileObject, usa resource_stream().

El código de acceso a los recursos puede estar en cualquier lugar dentro de la estructura del subpaquete de su proyecto, solo necesita hacer referencia al subpaquete que contiene las imágenes por nombre completo: proj.resources.images, en este caso.

Aquí es "setup.py":

#!/usr/bin/env python 

from setuptools import setup, find_packages 

setup(name='proj', 
     packages=find_packages(), 
     package_data={'': ['*.png']}) 

Advertencia: Para probar cosas "local", es decir w/o instalar el paquete en primer lugar, usted tiene que invocar los scripts de prueba a partir de directorio que tiene setup.py . Si está en el mismo directorio que code.py, Python no sabrá sobre el paquete proj. Por lo tanto, cosas como proj.resources no se resolverán.

+1

Bueno, las desventajas aquí son demasiado. ¿No hay una forma sensata y simple de empacar recursos con proyectos de Python? –

+0

Conozco solo 2 formas ampliamente compatibles (lamentablemente no son simples): 1) 'distutils'-way (estándar): la documentación deja el acceso a los archivos de recursos como un ejercicio para el lector (probablemente porque piensan en la manipulación de rutas) relativo a '__file__' son todo lo que uno necesita). 2) 'setuptools'-way (superconjunto de' distutils'), descrito anteriormente. –

4

Siempre puede tener una carpeta de "recursos" por separado en cada subpaquete que lo necesite, y utilizar las funciones os.path para obtener estos valores de __file__ de sus subpaquetes. Para ilustrar lo que quiero decir, creé el __init__.py siguiente archivo en tres lugares:

 
c:\temp\topp  (top-level package) 
c:\temp\topp\sub1 (subpackage 1) 
c:\temp\topp\sub2 (subpackage 2) 

Aquí está el archivo __init__.py:

import os.path 
resource_path = os.path.join(os.path.split(__file__)[0], "resources") 
print resource_path 

en C: \ temp \ trabajo, crear una aplicación, topapp. py, como sigue:

import topp 
import topp.sub1 
import topp.sub2 

Este respresents la aplicación con el paquete y subpaquetes topp. Luego lo ejecuto:

 
C:\temp\work>topapp 
Traceback (most recent call last): 
    File "C:\temp\work\topapp.py", line 1, in 
    import topp 
ImportError: No module named topp 

Eso es como se esperaba. Hemos establecido el PYTHONPATH para simular tener nuestro paquete en el camino:

 
C:\temp\work>set PYTHONPATH=c:\temp 

C:\temp\work>topapp 
c:\temp\topp\resources 
c:\temp\topp\sub1\resources 
c:\temp\topp\sub2\resources 

Como se puede ver, las trayectorias de recursos resueltos correctamente a la ubicación de los paquetes reales (sub) en el camino.

Actualización:Here es la documentación correspondiente de py2exe.

+0

¿Pero qué pasa cuando quieres py2exe todo? –

+0

No estaba hablando de cómo empacar los recursos con el código. Estaba hablando del hecho de que '__file__' no funcionará. –

1

@ pycon2009, hubo una presentación sobre distutils y setuptools. Usted puede encontrar todos los videos de

Eggs and Buildout Deployment in Python - Part 1

Eggs and Buildout Deployment in Python - Part 2

Eggs and Buildout Deployment in Python - Part 3

En estos videos, que describen cómo incluir los recursos estáticos en el paquete. Creo que está en la parte 2.

Con herramientas de configuración, puede definir dependencias, esto le permitiría tener 2 paquetes que usan recursos del 3er paquete.

Setuptools también le proporciona una forma estándar de acceder a estos recursos y le permite usar rutas relativas dentro de sus paquetes, lo que elimina la necesidad de preocuparse acerca de dónde están instalados sus paquetes.

Cuestiones relacionadas