web-dev-qa-db-fra.com

Python Accéder aux données dans le sous-répertoire du package

J'écris un package python avec des modules qui doivent ouvrir des fichiers de données dans un ./data/ sous-répertoire. En ce moment, j'ai les chemins d'accès aux fichiers codés en dur dans mes classes et fonctions. Je voudrais écrire un code plus robuste qui peut accéder au sous-répertoire indépendamment de l'endroit où il est installé sur le système de l'utilisateur.

J'ai essayé différentes méthodes, mais jusqu'à présent, je n'ai pas eu de chance. Il semble que la plupart des commandes du "répertoire courant" retournent le répertoire de l'interpréteur python du système, et non le répertoire du module.

Cela semble être un problème banal et courant. Pourtant, je n'arrive pas à comprendre. Une partie du problème est que mes fichiers de données ne sont pas .py fichiers, donc je ne peux pas utiliser les fonctions d'importation et autres.

Aucune suggestion?

En ce moment, mon répertoire de packages ressemble à:

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

J'essaie d'accéder à data.txt de module*.py

Merci!

107
Jacob Lyles

Vous pouvez utiliser __file__ pour obtenir le chemin d'accès au package, comme ceci:

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
RichieHindle

La façon standard de le faire est d'utiliser les packages setuptools et pkg_resources.

Vous pouvez disposer votre package selon la hiérarchie suivante et configurer le fichier de configuration du package pour pointer vers vos ressources de données, selon ce lien:

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

Vous pouvez ensuite retrouver et utiliser ces fichiers à l'aide de pkg_resources, selon ce lien:

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')
144
elliot42

Pour fournir une solution qui fonctionne aujourd'hui. Utilisez certainement cette API pour ne pas réinventer toutes ces roues.

Un vrai nom de fichier du système de fichiers est nécessaire. Les œufs zippés seront extraits dans un répertoire cache:

from pkg_resources import resource_filename, Requirement

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

Renvoie un objet de type fichier lisible pour la ressource spécifiée; il peut s'agir d'un fichier réel, d'un StringIO ou d'un objet similaire. Le flux est en "mode binaire", en ce sens que tous les octets de la ressource seront lus tels quels.

from pkg_resources import resource_stream, Requirement

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

Découverte de packages et accès aux ressources à l'aide de pkg_resources

13
Sascha Gottfried

Je pense que j'ai traqué une réponse.

Je crée un module data_path.py, que j'importe dans mes autres modules contenant:

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

Et puis j'ouvre tous mes fichiers avec

open(os.path.join(data_path,'filename'), <param>)
8
Jacob Lyles

Vous avez besoin d'un nom pour l'ensemble de votre module, on vous donne une arborescence de répertoires qui ne répertorie pas ce détail, pour moi, cela a fonctionné:

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

Setuptools ne semble pas résoudre les fichiers basés sur une correspondance de nom avec des fichiers de données compressés, alors vous êtes obligé d'inclure le préfixe data/ À peu près quoi qu'il arrive. Vous pouvez utiliser os.path.join('data', 'data.txt) si vous avez besoin de séparateurs de répertoires alternatifs. En général, je ne trouve aucun problème de compatibilité avec les séparateurs de répertoires de style Unix codés en dur.

7
ThorSummoner