Gestión de recursos en un proyecto Python


Tengo un proyecto 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?

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

También, necesito un forma de acceder a estos archivos que es independiente de lo que mi directorio actual es.

Author: JJ Geewax, 2009-09-08

3 answers

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

Por ejemplo, he creado un pequeño paquete rápido "proj" para ilustrar el esquema de organización de recursos que usaría:

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 mantengo todos los recursos en un subpaquete separado.

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

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 ejecutas, obtienes: {[17]]}

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

Si necesita tratar un recurso como un objeto de archivo, utilice resource_stream().

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

Aquí está "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 "localmente", es decir sin instalar el paquete primero, tendrá que invocar sus scripts de prueba desde el directorio que tiene setup.py. Si estás en el mismo directorio que code.py, Python no sabrá sobre el paquete proj. Así que cosas como proj.resources no se resolverá.

 42
Author: Pavel Repin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-08 22:22:05

Siempre puede tener una carpeta separada de "recursos" en cada subpaquete que lo necesite, y usar las funciones os.path para acceder a ellas desde los valores __file__ de sus subpaquetes. Para ilustrar lo que quiero decir, creé el siguiente archivo __init__.py en tres ubicaciones:

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\work, Creo una aplicación, topapp.py, según se indica:

import topp
import topp.sub1
import topp.sub2

Esto representa la aplicación usando el paquete y subpaquetes topp. Entonces corro it:

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 lo esperado. Configuramos el PYTHONPATH para simular tener nuestro paquete en la ruta:

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 puede ver, las rutas de recurso se resolvieron correctamente a la ubicación de los (sub)paquetes reales en la ruta.

Actualizar: Aquí está la documentación correspondiente de py2exe.

 4
Author: Vinay Sajip,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-08 20:56:19

@ pycon2009, hubo una presentación sobre distutils y setuptools. Puedes encontrar todos los videos aquí

Despliegue de Eggs y Buildout en Python-Parte 1

Despliegue de Eggs y Buildout en Python-Parte 2

Despliegue de Eggs y Buildout en Python-Parte 3

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

Con setuptools, puede definir dependencias, esto le permitiría tener 2 paquetes que usan recursos de 3rd package.

Setuptools también le da 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 por dónde están instalados sus paquetes.

 1
Author: Taras Mankovski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-24 16:16:28