145 votes

Élargir le chemin de recherche de Python à d'autres sources

Je viens de rejoindre un projet avec une base de code existante assez importante. Nous développons sous linux et n'utilisons pas d'IDE. Nous utilisons la ligne de commande. J'essaie de comprendre comment faire en sorte que Python recherche le bon chemin lorsque je lance des modules de projet. Par exemple, quand je lance quelque chose comme :

python someprojectfile.py

J'obtiens

ImportError: no module named core.'somemodule'

J'obtiens ce résultat pour toutes mes importations et je suppose qu'il s'agit d'un problème avec le chemin d'accès.

Comment faire pour que Python recherche ~/codez/project/ et tous les fichiers et dossiers pour *.py lors des déclarations d'importation ?

237voto

David Z Points 49476

Il y a plusieurs façons de procéder :

  • Définir la variable d'environnement PYTHONPATH à une liste de répertoires séparés par des deux-points dans lesquels rechercher les modules importés.
  • Dans votre programme, utilisez sys.path.append('/path/to/search') pour ajouter les noms des répertoires dans lesquels vous souhaitez que Python recherche les modules importés. sys.path est simplement la liste des répertoires que Python recherche à chaque fois qu'on lui demande d'importer un module, et vous pouvez la modifier selon vos besoins (bien que je ne recommande pas de supprimer les répertoires standard !) Tous les répertoires que vous mettez dans la variable d'environnement PYTHONPATH sera inséré dans sys.path au démarrage de Python.
  • Utilice site.addsitedir pour ajouter un répertoire à sys.path . La différence entre cette méthode et l'apposition simple est que lorsque vous utilisez addsitedir il recherche également .pth à l'intérieur de ce répertoire et les utilise pour ajouter éventuellement des répertoires supplémentaires aux sys.path sur la base du contenu des fichiers. Voir la documentation pour plus de détails.

Le choix de l'un ou l'autre dépend de votre situation. N'oubliez pas que lorsque vous distribuez votre projet à d'autres utilisateurs, ceux-ci l'installent généralement de manière à ce que les fichiers de code Python soient automatiquement détectés par l'importateur de Python (c'est-à-dire que les paquets sont généralement installés dans le répertoire site-packages ), de sorte que si vous modifiez le répertoire sys.path dans votre code, cela peut être inutile et peut même avoir des effets négatifs lorsque ce code s'exécute sur un autre ordinateur. En ce qui concerne le développement, j'oserais dire que le fait de paramétrer PYTHONPATH est généralement la meilleure solution.

Cependant, lorsque vous utilisez quelque chose qui ne fonctionne que sur votre propre ordinateur (ou lorsque vous avez des configurations non standard, par exemple parfois dans les frameworks d'applications web), il n'est pas totalement rare de faire quelque chose comme

import sys
from os.path import dirname
sys.path.append(dirname(__file__))

17voto

Andrew B. Points 561

Vous pouvez également vous renseigner sur les paquets python ici : http://docs.python.org/tutorial/modules.html .

D'après votre exemple, je suppose que vous avez vraiment un paquet à ~/codez/project . Le fichier __init__.py dans un répertoire python fait correspondre un répertoire à un espace de noms. Si vos sous-répertoires ont tous un espace de noms __init__.py il vous suffit d'ajouter le répertoire de base à votre fichier PYTHONPATH . Par exemple :

PYTHONPATH=$PYTHONPATH:$HOME/adaifotis/projet

En plus de tester votre variable d'environnement PYTHONPATH, comme l'explique David, vous pouvez la tester en python comme suit :

$ python
>>> import project                      # should work if PYTHONPATH set
>>> import sys
>>> for line in sys.path: print line    # print current python path

...

8voto

Tom Gordon Points 101

Je sais que ce fil de discussion est un peu ancien, mais il m'a fallu un certain temps pour arriver au cœur du problème, et je voulais donc le partager.

Dans mon projet, j'avais le script principal dans un répertoire parent, et, pour différencier les modules, j'ai mis tous les modules de support dans un sous-dossier appelé "modules". Dans mon script principal, j'importe ces modules comme suit (pour un module appelé report.py) :

from modules.report import report, reportError

Si j'appelle mon script, cela fonctionne. CEPENDANT, j'ai voulu tester chaque module en incluant un fichier main() dans chacun d'entre eux, et en les appelant directement, comme suit :

python modules/report.py

Maintenant, Python se plaint qu'il ne peut pas trouver "un module appelé modules". La clé ici est que, par défaut, Python inclut le dossier du script dans son chemin de recherche, MAIS PAS LE CWD. Cette erreur dit donc, en réalité, "Je ne trouve pas de sous-dossier modules". C'est parce qu'il n'y a pas de sous-répertoire "modules" dans le répertoire où réside le module report.py.

Je trouve que la meilleure solution consiste à ajouter le CWD dans le chemin de recherche Python en l'incluant en haut de la page :

import sys

sys.path.append(".")

Maintenant, Python cherche dans le CWD (répertoire courant), trouve le sous-dossier "modules", et tout va bien.

4voto

KieranPC Points 2400

La méthode la plus simple consiste à créer un fichier any_name.pth et placez-le dans votre dossier \Lib\site-packages . Vous devriez trouver ce dossier partout où python est installé.

Dans ce fichier, mettez une liste de répertoires dans lesquels vous souhaitez conserver les modules à importer. Par exemple, faites une ligne dans ce fichier comme ceci :

C:\Users\example\...\example

Vous pourrez vous rendre compte que cela fonctionne en lançant ce programme en python :

import sys
for line in sys.path:
    print line

Vous verrez votre répertoire imprimé, parmi d'autres, d'où vous pourrez également importer. Vous pouvez maintenant importer un mymodule.py qui se trouve dans ce répertoire aussi facilement que :

import mymodule

Cela n'importera pas les sous-dossiers. Pour cela, vous pourriez imaginer de créer un script en python pour créer un .pth fichier contenant tous les sous-dossiers d'un dossier que vous définissez. Il peut être exécuté au démarrage.

3voto

Droogans Points 2098

J'ai lu cette question en cherchant une réponse, et je n'ai aimé aucune d'entre elles.

J'ai donc rédigé une solution rapide et pratique. Il suffit de mettre ceci quelque part dans votre sys.path, et cela ajoutera n'importe quel répertoire sous folder (à partir du répertoire de travail actuel), ou sous abspath :

#using.py

import sys, os.path

def all_from(folder='', abspath=None):
    """add all dirs under `folder` to sys.path if any .py files are found.
    Use an abspath if you'd rather do it that way.

    Uses the current working directory as the location of using.py. 
    Keep in mind that os.walk goes *all the way* down the directory tree.
    With that, try not to use this on something too close to '/'

    """
    add = set(sys.path)
    if abspath is None:
        cwd = os.path.abspath(os.path.curdir)
        abspath = os.path.join(cwd, folder)
    for root, dirs, files in os.walk(abspath):
        for f in files:
            if f[-3:] in '.py':
                add.add(root)
                break
    for i in add: sys.path.append(i)

>>> import using, sys, pprint
>>> using.all_from('py') #if in ~, /home/user/py/
>>> pprint.pprint(sys.path)
[
#that was easy
]

Et j'aime ça parce que je peux avoir un dossier pour des outils aléatoires sans qu'ils fassent partie de paquets ou quoi que ce soit d'autre, tout en ayant accès à certains d'entre eux (ou à tous) en quelques lignes de code.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X