web-dev-qa-db-fra.com

Comment faire référence à des chemins relatifs de ressources lorsque vous travaillez avec un référentiel de code dans Python

Nous travaillons avec un référentiel de code déployé à la fois sous Windows et Linux - parfois sur des répertoires différents. Comment l'un des modules du projet doit-il se référer à l'une des ressources non Python du projet (fichiers CSV, etc.)?

Si nous faisons quelque chose comme:

thefile=open('test.csv')

ou:

thefile=open('../somedirectory/test.csv')

Cela fonctionnera uniquement lorsque le script sera exécuté à partir d'un répertoire spécifique ou d'un sous-ensemble des répertoires.

Ce que j'aimerais faire est quelque chose comme:

path=getBasePathOfProject()+'/somedirectory/test.csv'
thefile=open(path)

Est-ce la bonne façon? C'est possible?

171
olamundo

Essayez d’utiliser un nom de fichier relatif au chemin des fichiers actuels. Exemple pour './my_file':

fn = os.path.join(os.path.dirname(__file__), 'my_file')

Dans Python 3.4+, vous pouvez également utiliser pathlib :

fn = pathlib.Path(__file__).parent / 'my_file'
229
c089

Si vous utilisez des outils d'installation ou si vous distribuez (une installation setup.py), la "bonne" façon d'accéder à ces ressources empaquetées semble utiliser package_resources.

Dans votre cas, l'exemple serait

import pkg_resources
my_data = pkg_resources.resource_string(__name__, "foo.dat")

Ce qui bien sûr lit la ressource et les données binaires lues seraient la valeur de my_data

Si vous avez juste besoin du nom de fichier, vous pouvez aussi utiliser

resource_filename(package_or_requirement, resource_name)

Exemple:

resource_filename("MyPackage","foo.dat")

L'avantage est que son fonctionnement est garanti même s'il s'agit d'une distribution d'archives comme un Egg.

Voir http://packages.python.org/distribute/pkg_resources.html#resourcemanager-api

37
Sharoon Thomas

En Python, les chemins sont relatifs au répertoire de travail actuel , qui est dans la plupart des cas le répertoire à partir duquel vous exécutez votre programme. . Le répertoire de travail actuel est très probablement différent du répertoire de votre fichier de module. Il est donc toujours mauvais d'utiliser un chemin relatif à votre fichier de module actuel. choix.

Utiliser le chemin absolu devrait être la meilleure solution:

import os
package_dir = os.path.dirname(os.path.abspath(__file__))
thefile = os.path.join(package_dir,'test.cvs')
14
skyfree

J'utilise souvent quelque chose de similaire à ceci:

import os
DATA_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), 'datadir'))

# if you have more paths to set, you might want to shorten this as
here = lambda x: os.path.abspath(os.path.join(os.path.dirname(__file__), x))
DATA_DIR = here('datadir') 

pathjoin = os.path.join
# ...
# later in script
for fn in os.listdir(DATA_DIR):
    f = open(pathjoin(DATA_DIR, fn))
    # ...

La variable

__file__

contient le nom de fichier du script dans lequel vous écrivez ce code, vous pouvez donc créer des chemins relatifs au script, mais toujours écrits avec des chemins absolus. Cela fonctionne assez bien pour plusieurs raisons:

  • chemin est absolu, mais toujours relatif
  • le projet peut toujours être déployé dans un conteneur relatif

Mais vous devez surveiller la compatibilité de la plate-forme - os.pathsep de Windows est différent d’UNIX.

12
user137673
import os
cwd = os.getcwd()
path = os.path.join(cwd, "my_file")
f = open(path)

Vous essayez également de normaliser votre cwd en utilisant os.path.abspath(os.getcwd()). Plus d'infos ici .

5
gavoja

Vous pouvez utiliser la variable de construction __file__. Il contient le chemin du fichier actuel. J'implémenterais getBaseOfProject dans un module à la racine de votre projet. Là, j'obtiendrais la partie chemin de __file__ et je le renverrais. Cette méthode peut ensuite être utilisée partout dans votre projet.

2
Achim

Je suis un peu coincé ici. Voulait empaqueter des fichiers de ressources dans un fichier wheel et y accéder. L'emballage a-t-il utilisé le fichier manifeste, mais pip install ne l'installait pas sauf s'il s'agissait d'un sous-répertoire. En espérant que ces plans vous aideront

├── cnn_client
│   ├── image_preprocessor.py
│   ├── __init__.py
│   ├── resources
│   │   ├── mscoco_complete_label_map.pbtxt
│   │   ├── retinanet_complete_label_map.pbtxt
│   │   └── retinanet_label_map.py
│   ├── tf_client.py

MANIFEST.in

recursive-include cnn_client/resources *

Créé un weel en utilisant setup.py standard. pip a installé le fichier de roue. Après l'installation, vérifiez si les ressources sont installées. Elles sont

ls /usr/local/lib/python2.7/dist-packages/cnn_client/resources

mscoco_complete_label_map.pbtxt
retinanet_complete_label_map.pbtxt 
 retinanet_label_map.py  

Dans tfclient.py pour accéder à ces fichiers. de

templates_dir = os.path.join(os.path.dirname(__file__), 'resources')
 file_path = os.path.join(templates_dir, \
            'mscoco_complete_label_map.pbtxt')
        s = open(file_path, 'r').read()

Et il fonctionne.

0
Alex Punnen