web-dev-qa-db-fra.com

Développer Python Chemin de recherche vers une autre source

Je viens de rejoindre un projet avec une base de code existante assez grande. Nous développons sous Linux et n'utilisons pas et IDE. Nous parcourons la ligne de commande. J'essaie de comprendre comment obtenir python pour rechercher le bon chemin lorsque j'exécute des modules de projet. Par exemple, lorsque j'exécute quelque chose comme:

python someprojectfile.py

Je reçois

ImportError: no module named core.'somemodule'

Je reçois ceci pour toutes mes importations, je suppose que c'est un problème avec le chemin.

TLDR:

Comment obtenir Python pour rechercher ~/codez/project/ et tous les fichiers et dossiers pour les fichiers * .py au cours des instructions d'importation.

81
themaestro

Il y a plusieurs façons possibles de le faire:

  • Définissez la variable d’environnement PYTHONPATH sur une liste de répertoires séparés par des deux-points pour la recherche de modules importés.
  • Dans votre programme, utilisez sys.path.append('/path/to/search') pour ajouter les noms des répertoires souhaités Python pour rechercher les modules importés. sys.path n’est que la liste des répertoires Python cherche à chaque fois qu’on lui demande d’importer un module, et vous pouvez le modifier à votre guise (bien que je ne recommande pas de supprimer les répertoires standard!). Tous les répertoires que vous avez mis dans la variable d’environnement PYTHONPATH seront insérés dans sys.path quand Python démarre.
  • Utilisation site.addsitedir pour ajouter un répertoire à sys.path. La différence entre cela et simplement l'ajout est que lorsque vous utilisez addsitedir, il recherche également .pth fichiers dans ce répertoire et les utilise pour ajouter éventuellement des répertoires supplémentaires à sys.path basé sur le contenu des fichiers. Voir la documentation pour plus de détails.

Lequel de ceux-ci que vous souhaitez utiliser dépend de votre situation. N'oubliez pas que lorsque vous distribuez votre projet à d'autres utilisateurs, ils 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.-à-d. Que les packages sont installés dans le fichier site-packages répertoire), donc si vous vous trompez avec sys.path dans votre code, cela peut être inutile et peut même avoir des effets indésirables lorsque ce code est exécuté sur un autre ordinateur. Pour le développement, je suppose que définir PYTHONPATH est généralement la meilleure solution.

Toutefois, lorsque vous utilisez quelque chose qui ne tourne que sur votre propre ordinateur (ou lorsque vous avez des configurations non standard, par exemple dans des frameworks d'applications Web), il n'est pas tout à fait inhabituel de faire quelque chose comme:

import sys
from os.path import dirname
sys.path.append(dirname(__file__))
143
David Z

Vous devriez également lire à propos de python ici: http://docs.python.org/tutorial/modules.html .

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

PYTHONPATH = $ PYTHONPATH: $ HOME/adaifotis/project

En plus de tester votre variable d'environnement PYTHONPATH, comme l'explique David, vous pouvez le tester dans python comme ceci:

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

...

11
Andrew B.

Je sais que ce fil est un peu vieux, mais il m'a fallu un certain temps pour en arriver au cœur de la question, alors je voulais partager.

Dans mon projet, le script principal se trouvait dans un répertoire parent et, pour différencier les modules, je plaçais tous les modules de support dans un sous-dossier appelé "modules". Dans mon script principal, j'importe ces modules comme ceci (pour un module appelé report.py):

from modules.report import report, reportError

Si j'appelle mon script principal, cela fonctionne. CEPENDANT, je voulais tester chaque module en incluant un main() dans chacun et en appelant chacun directement, en tant que:

python modules/report.py

Maintenant Python se plaint de ne 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. Donc, cette erreur dit vraiment: "Je ne trouve pas de sous-dossier de modules", car 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 solution la plus simple est d’ajouter le CWD dans Python en l’ajoutant en haut:

import sys

sys.path.append(".")

Now Python effectue une recherche dans le CWD (répertoire actuel), trouve le sous-dossier "modules" et tout va bien.

4
Tom Gordon

Le moyen le plus simple que je trouve est de créer un fichier "any_name.pth" et de le placer dans votre dossier "\ Lib\site-packages". Vous devriez trouver ce dossier où python est installé.

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

C:\Utilisateurs\exemple ...\exemple

Vous pourrez dire que cela fonctionne en exécutant ceci en python:

import sys
for line in sys: print line

Vous verrez votre répertoire imprimé, entre autres, à partir duquel vous pouvez également importer. Maintenant, vous pouvez importer un fichier "mymodule.py" qui se trouve dans ce répertoire aussi facilement que:

import mymodule

Cela n'importera pas de sous-dossiers. Pour cela, vous pouvez imaginer créer un script python) pour créer un fichier .pth contenant tous les sous-dossiers d’un dossier que vous définissez. Faites-le éventuellement au démarrage.

3
KieranPC

J'ai lu cette question à la recherche d'une réponse et je n'ai aimé aucune d'entre elles.

J'ai donc écrit une solution rapide et sale. Il suffit de mettre ceci quelque part sur votre chemin 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 certains outils aléatoires sans que ceux-ci fassent partie de paquetages ou quoi que ce soit, tout en ayant accès à certains (ou à tous) d'entre eux dans quelques lignes de code.

2
Droogans

Nouvelle option pour l'ancienne question.
Installation de fail2ban package sur Debian, on dirait qu’il est difficile à installer sur /usr/lib/python3/dist-packages/fail2ban un chemin non sur python3 sys.path.


> python3
Python 3.7.3 (v3.7.3:ef4ec6ed12, Jun 25 2019, 18:51:50)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/usr/lib/python37.Zip', '/usr/lib/python3.7', '/usr/lib/python3.7/lib-dynload', '/usr/lib/python3.7/site-packages']
>>>

ainsi, au lieu de simplement copier, j'ai (bash) lié la bibliothèque à des versions plus récentes.
Les futures mises à jour de l'application d'origine seront également appliquées automatiquement aux versions liées.

 if [ -d /usr/lib/python3/dist-packages/fail2ban ]
   then
      for d in /usr/lib/python3.*
      do
         [ -d ${d}/fail2ban ] || \
            ln -vs /usr/lib/python3/dist-packages/fail2ban ${d}/
      done
   fi
0
fcm