setuptools: ubicación de la carpeta de datos del paquete

Uso setuptools para distribuir mi paquete de python. Ahora necesito distribuir archivos de datos adicionales.

De lo que he recostackdo de la documentación de setuptools, necesito tener mis archivos de datos dentro del directorio del paquete. Sin embargo, prefiero tener mis archivos de datos dentro de un subdirectorio en el directorio raíz.

Lo que me gustaría evitar:

/ #root |- src/ | |- mypackage/ | | |- data/ | | | |- resource1 | | | |- [...] | | |- __init__.py | | |- [...] |- setup.py 

Lo que me gustaría tener en su lugar:

 / #root |- data/ | |- resource1 | |- [...] |- src/ | |- mypackage/ | | |- __init__.py | | |- [...] |- setup.py 

Simplemente no me siento cómodo teniendo tantos subdirectorios, si no es esencial. No encuentro una razón, por qué tengo / para poner los archivos dentro del directorio del paquete. También es engorroso trabajar con tantos subdirectorios nesteds IMHO. ¿O hay alguna buena razón para justificar esta restricción?

Opción 1: instalar como datos del paquete

La principal ventaja de colocar archivos de datos dentro de la raíz de su paquete de Python es que le permite evitar preocuparse por la ubicación de los archivos en el sistema de un usuario, que puede ser Windows, Mac, Linux, alguna plataforma móvil o dentro de un Egg. Siempre puede encontrar los data del directorio relativos a la raíz de su paquete Python, sin importar dónde o cómo esté instalado.

Por ejemplo, si tengo un diseño de proyecto así:

 project/ foo/ __init__.py data/ resource1/ foo.txt 

Puede agregar una función a __init__.py para ubicar una ruta absoluta a un archivo de datos:

 import os _ROOT = os.path.abspath(os.path.dirname(__file__)) def get_data(path): return os.path.join(_ROOT, 'data', path) print get_data('resource1/foo.txt') 

Salidas:

 /Users/pat/project/foo/data/resource1/foo.txt 

Después de que el proyecto se instale como un Egg, la ruta a los data cambiará, pero el código no necesita cambiar:

 /Users/pat/virtenv/foo/lib/python2.6/site-packages/foo-0.0.0-py2.6.egg/foo/data/resource1/foo.txt 

Opción 2: instalar en una ubicación fija

La alternativa sería colocar sus datos fuera del paquete de Python y luego:

  1. Haga pasar la ubicación de los data a través de un archivo de configuración, argumentos de la línea de comandos o
  2. Incruste la ubicación en su código Python.

Esto es mucho menos deseable si planea distribuir su proyecto. Si realmente desea hacer esto, puede instalar sus data donde quiera en el sistema de destino especificando el destino para cada grupo de archivos al pasar a una lista de tuplas:

 from setuptools import setup setup( ... data_files=[ ('/var/data1', ['data/foo.txt']), ('/var/data2', ['data/bar.txt']) ] ) 

Actualizado : Ejemplo de una función de shell para gursivamente recortar archivos de Python:

 atlas% function grep_py { find . -name '*.py' -exec grep -Hn $* {} \; } atlas% grep_py ": \[" ./setup.py:9: package_data={'foo': ['data/resource1/foo.txt']} 

Creo que encontré un buen compromiso que te permitirá mantener la siguiente estructura:

 / #root |- data/ | |- resource1 | |- [...] |- src/ | |- mypackage/ | | |- __init__.py | | |- [...] |- setup.py 

Debe instalar los datos como package_data, para evitar los problemas descritos en samplebias answer, pero para mantener la estructura de archivos debe agregar a su setup.py:

 try: os.symlink('../../data', 'src/mypackage/data' setup( ... package_data = {'mypackage': ['data/*']} ... ) finally: os.unlink('src/mypackage/data') 

De esta manera, creamos la estructura apropiada “justo a tiempo” y mantenemos nuestro árbol de fonts organizado.

Para acceder a dichos archivos de datos dentro de su código, simplemente ‘usa’:

data = resource_filename(Requirement.parse("main_package"), 'mypackage/data')

Todavía no me gusta tener que especificar ‘mypackage’ en el código, ya que los datos no tienen nada que ver con este módulo, pero creo que es un buen compromiso.

Utilizo setuptools para crear paquetes nativos del sistema operativo como RPM y DEB. El diseño del proyecto que uso es.

 / lib/ -> .../lib/pythonX/site-packages/ bin/ -> .../bin/ etc/ -> /etc/ doc/ man/ -> .../man/man1/ share/ -> .../share/doc// 

Mi archivo setup.py hace la asignación apropiada como se especifica anteriormente. Encuentro este diseño ideal para python. Los paquetes producidos son reubicables, pero por defecto irán bajo /usr/local/ .

Creo que básicamente puedes dar cualquier cosa como argumento * data_files * a setup () .