J'écris un package python avec des modules qui doivent ouvrir des fichiers de données dans un ./data/
sous - répertoire. À l'heure actuelle, j'ai les chemins d'accès aux fichiers codés en dur dans mes classes et mes fonctions. Je voudrais écrire un code plus robuste qui puisse accéder au sous-répertoire quel que soit l'endroit où il est installé sur le système de l'utilisateur.
J'ai essayé diverses méthodes, mais jusqu'à présent, je n'ai pas eu de chance. Il semble que la plupart des commandes "répertoire courant" renvoient 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 des .py
fichiers, je ne peux donc pas utiliser les fonctions d'importation et autres.
Aucune suggestion?
À l'heure actuelle, mon répertoire de paquets ressemble à:
/
__init__.py
module1.py
module2.py
data/
data.txt
J'essaye d'accéder à data.txt
partir de module*.py
!
Réponses:
Vous pouvez utiliser
__file__
pour obtenir le chemin d'accès au package, comme ceci:la source
__file__
ne fonctionne pas avec py2exe, car la valeur sera le chemin du fichier zip.La manière standard de le faire est d'utiliser les packages setuptools et pkg_resources.
Vous pouvez mettre en page votre package selon la hiérarchie suivante et configurer le fichier de configuration du package pour qu'il pointe 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 en utilisant pkg_resources, selon ce lien:
http://peak.telecommunity.com/DevCenter/PkgResources#basic-resource-access
la source
python-setuptools
uniquement pour cela? Jusqu'à présent, cela__file__
fonctionne bien pour moi.from pkg_resources import resource_filename open(resource_filename('data', 'data.txt'), 'rb')
importlib.resources
remplacepkg_resources
dans ce but (en raison de problèmes de performances).Fournir une solution qui fonctionne aujourd'hui. Utilisez définitivement cette API pour ne pas réinventer toutes ces roues.
Un vrai nom de fichier de système de fichiers est nécessaire. Les œufs zippés seront extraits dans un répertoire de cache:
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 contenus dans la ressource seront lus tels quels.
Découverte de package et accès aux ressources à l'aide de pkg_resources
la source
Il est souvent inutile de faire une réponse qui détaille un code qui ne fonctionne pas tel quel , mais je pense que c'est une exception. Ajout de Python 3.7
importlib.resources
qui est censé remplacerpkg_resources
. Cela fonctionnerait pour accéder aux fichiers dans des packages qui n'ont pas de barres obliques dans leurs noms, c'est-à-direc'est à dire que vous pouvez accéder à l'
data2.txt
intérieur du packagefoo
avec par exemplemais cela échouerait avec une exception pour
Cela ne peut pas être fixé , sauf en plaçant
__init__.py
dansdata
, puis l' utiliser comme un paquet:La raison de ce comportement est "c'est par conception" ; mais le design pourrait changer ...
la source
"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?"
Vous avez besoin d'un nom pour tout votre module, l'arborescence de répertoires qui vous est donnée ne répertorie pas ce détail, pour moi cela a fonctionné:
Notamment, setuptools ne semble pas résoudre les fichiers en fonction d'une correspondance de nom avec des fichiers de données compressés, vous devez donc inclure le
data/
préfixe à peu près quoi qu'il arrive . Vous pouvez utiliseros.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.la source
Je pense que j'ai cherché une réponse.
Je crée un module data_path.py, que j'importe dans mes autres modules contenant:
Et puis j'ouvre tous mes fichiers avec
la source
pkg_resources.resource_string('pkg_name', 'data/file.txt')
__file__
quelque part. Dans mon cas, j'utilise une bibliothèque qui veut vraiment des chemins et non des flux. Bien sûr, je pourrais écrire les fichiers temporairement sur le disque, mais étant paresseux, j'utilise simplement la fonctionnalité de setuptools.