Estoy escribiendo un paquete de Python con módulos que necesitan abrir archivos de datos en un ./data/
subdirectorio. 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.
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 de Python del sistema, y no el directorio del módulo.
Parece que debería ser un problema trivial y común. Sin embargo, parece que no puedo entenderlo. Parte del problema es que mis archivos de datos no son .py
archivos, por lo que no puedo usar las funciones de importación y similares.
¿Alguna sugerencia?
En este momento mi directorio de paquetes se ve así:
/
__init__.py
module1.py
module2.py
data/
data.txt
Estoy tratando de acceder data.txt
desde module*.py
!
Respuestas:
Puede usar
__file__
para obtener la ruta al paquete, de esta manera:fuente
__file__
no funciona con py2exe, ya que el valor será la ruta al archivo zip.La forma estándar de hacerlo es con paquetes setuptools y pkg_resources.
Puede diseñar su paquete de acuerdo con la siguiente jerarquía y configurar el archivo de configuración del paquete para que señale sus recursos de datos, según este enlace:
http://docs.python.org/distutils/setupscript.html#installing-package-data
Luego puede volver a buscar y usar esos archivos usando pkg_resources, según este enlace:
http://peak.telecommunity.com/DevCenter/PkgResources#basic-resource-access
fuente
python-setuptools
solo para eso? Hasta ahora__file__
funciona bien para mí.from pkg_resources import resource_filename open(resource_filename('data', 'data.txt'), 'rb')
importlib.resources
reemplazapkg_resources
para este propósito (debido a problemas de rendimiento).Para proporcionar una solución que funcione 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 a un directorio de caché:
Devuelve un objeto similar a un archivo legible para el recurso especificado; Puede ser un archivo real, un StringIO o algún objeto similar. La secuencia está en "modo binario", en el sentido de que los bytes que estén en el recurso se leerán tal cual.
Descubrimiento de paquetes y acceso a recursos utilizando pkg_resources
fuente
A menudo no tiene sentido hacer una respuesta que detalle el código que no funciona como es, pero creo que esto es una excepción. Python 3.7 agregó
importlib.resources
que se supone que debe reemplazarpkg_resources
. Funcionaría para acceder a archivos dentro de paquetes que no tienen barras en sus nombres, es decires decir, puede acceder al
data2.txt
paquete internofoo
con, por ejemplo,pero fallaría con una excepción para
Esto no se puede fijar excepto mediante la colocación
__init__.py
endata
y después de usarlo como un paquete:La razón de este comportamiento es "es por diseño" ; pero el diseño puede cambiar ...
fuente
"This was a deliberate choice, but I think you have a valid use case. @brettcannon what do you think? And if we allow this, should we make sure it gets into Python 3.7?"
Necesita un nombre para todo el módulo, se le da que el árbol de directorios no incluye ese detalle, para mí esto funcionó:
No parece que setuptools resuelva los archivos basándose en una coincidencia de nombre con los archivos de datos empaquetados, por lo que tendrá que incluir el
data/
prefijo prácticamente sin importar qué. Puede usarloos.path.join('data', 'data.txt)
si necesita separadores de directorio alternativos. Sin embargo, generalmente no encuentro problemas de compatibilidad con los separadores de directorio de estilo Unix codificados.fuente
Creo que busqué una respuesta.
Hago un módulo data_path.py, que importo en mis otros módulos que contienen:
Y luego abro todos mis archivos con
fuente
pkg_resources.resource_string('pkg_name', 'data/file.txt')
__file__
alguna parte. En mi caso, uso una biblioteca que realmente quiere rutas y no secuencias. Por supuesto, podría escribir los archivos temporalmente en el disco, pero siendo flojo, solo uso la función setuptools.