2009-04-22 15 views
65

Estoy escribiendo un paquete python con módulos que necesitan abrir archivos de datos en un subdirectorio ./data/. En este momento tengo las rutas a los archivos codificados en mis clases y funciones. Me gustaría escribir un código más robusto que pueda acceder al subdirectorio independientemente de dónde esté instalado en el sistema del usuario.Datos de acceso Python en el subdirectorio de paquete

He intentado una variedad de métodos, pero hasta ahora no he tenido suerte. Parece que la mayoría de los comandos del "directorio actual" devuelven el directorio del intérprete python del sistema, y ​​no el directorio del módulo.

Parece que debería ser un problema común y trivial. Sin embargo, parece que no puedo resolverlo. Parte del problema es que mis archivos de datos no son archivos .py, por lo que no puedo usar funciones de importación y similares.

¿Alguna sugerencia?

Ahora mismo mi directorio del paquete se parece a:

/ 
__init__.py 
module1.py 
module2.py 
data/ 
    data.txt 

Estoy tratando de acceder data.txt de module*.py

Gracias!

Respuesta

24

Puede usar guión bajo-underscore- archivo-guión-guión bajo (__file__) para obtener la ruta al paquete, así:

import os 
this_dir, this_filename = os.path.split(__file__) 
DATA_PATH = os.path.join(this_dir, "data", "data.txt") 
print open(DATA_PATH).read() 
+24

Esto no funcionará si los archivos están en una distribución (es decir, huevo). Use pkg_resources para obtener el archivo de datos. – Chris

+0

De hecho, esto está roto. – Federico

6

Creo que he buscado una respuesta.

mía es data_path.py módulo, que importo en mis otros módulos que contienen:

data_path = os.path.join(os.path.dirname(__file__),'data') 

Y entonces abro todos mis archivos con

open(os.path.join(data_path,'filename'), <param>) 
+0

Esto no funcionará cuando el recurso se encuentre en una distribución de archivo (como un huevo comprimido). Prefiera algo así: 'pkg_resources.resource_string ('pkg_name', 'data/file.txt')' – ankostis

+0

@ankostis setuptools es lo suficientemente inteligente como para extraer el archivo si detecta que utilizó '__file__' en alguna parte. En mi caso, uso una biblioteca que realmente quiere rutas y no transmisiones. Por supuesto, podría escribir los archivos temporalmente en el disco, pero como soy flojo, solo uso la función setuptools. – letmaik

95

La forma estándar de hacerlo es con los paquetes setuptools y pkg_resources.

Usted puede diseñar su paquete de acuerdo con la siguiente jerarquía, y configurar el archivo de instalación del paquete de señalar que los recursos de datos, de acuerdo con este enlace:

http://docs.python.org/distutils/setupscript.html#installing-package-data

A continuación, puede volver a encontrar y utilizar esos archivos utilizando pkg_resources, según este enlace:

http://peak.telecommunity.com/DevCenter/PkgResources#basic-resource-access

import pkg_resources 

DATA_PATH = pkg_resources.resource_filename('<package name>', 'data/') 
DB_FILE = pkg_resources.resource_filename('<package name>', 'data/sqlite.db') 
+0

Creo que esta es la forma preferida, no estoy del todo seguro de la razón, pero los proyectos muestran advertencias cuando se refiere al paquete/módulo con '__file__'. – lukecampbell

+1

¿No * pkg_resources * crea una dependencia en tiempo de ejecución * setuptools *? Por ejemplo, redistribuyo un paquete Debian entonces ¿por qué iba a depender de 'python-setuptools' solo para eso? Hasta ahora '__file__' funciona bien para mí. – mlt

+3

Por qué esto es mejor: la clase ResourceManager proporciona acceso uniforme a los recursos del paquete, ya sea que esos recursos existan como archivos y directorios o que estén comprimidos en un archivo de algún tipo – vrdhn

11

Para proporcionar una solución de trabajo hoy. Definitivamente use esta API para no reinventar todas esas ruedas.

Se necesita un verdadero nombre de archivo del sistema de archivos. Los huevos comprimidos se extraerán en un directorio de caché:

from pkg_resources import resource_filename, Requirement 

path_to_vik_logo = resource_filename(Requirement.parse("enb.portals"), "enb/portals/reports/VIK_logo.png") 

Devuelve un objeto similar a un archivo legible para el recurso especificado; puede ser un archivo real, un StringIO u otro objeto similar. La secuencia está en "modo binario", en el sentido de que los bytes que se encuentran en el recurso se leerán tal cual.árbol de directorios

from pkg_resources import resource_stream, Requirement 

vik_logo_as_stream = resource_stream(Requirement.parse("enb.portals"), "enb/portals/reports/VIK_logo.png") 

Paquete Descubrimiento y acceso al recurso utilizando pkg_resources

3

Es necesario un nombre para todo el módulo, que está dado no lo hace la lista ese detalle, para mí esto funcionó:

import pkg_resources 
print( 
    pkg_resources.resource_filename(__name__, 'data/data.txt') 
) 

Parece que las herramientas de configuración no resuelven los archivos basados ​​en una coincidencia de nombre con los archivos de datos empaquetados, por lo que tiene que incluir el prefijo data/ prácticamente sin importar nada. Puede usar os.path.join('data', 'data.txt) si necesita separadores de directorio alternativos. Sin embargo, en general no encuentro problemas de compatibilidad con los separadores de directorios de estilo Unix codificados.

Cuestiones relacionadas