PYTHONPATH contre sys.path

92

Un autre développeur et moi ne sommes pas d'accord sur le fait que PYTHONPATH ou sys.path devraient être utilisés pour permettre à Python de trouver un package Python dans un répertoire utilisateur (par exemple, développement).

Nous avons un projet Python avec une structure de répertoires typique:

Project
    setup.py
    package
        __init__.py
        lib.py
        script.py

Dans script.py, nous devons le faire import package.lib. Lorsque le package est installé dans site-packages, script.py peut trouver package.lib.

Cependant, lorsque vous travaillez à partir d'un répertoire utilisateur, quelque chose d'autre doit être fait. Ma solution est de configurer mon PYTHONPATH pour inclure "~ / Project". Un autre développeur souhaite mettre cette ligne de code au début de script.py:

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

Pour que Python puisse trouver la copie locale de package.lib.

Je pense que c'est une mauvaise idée, car cette ligne n'est utile que pour les développeurs ou les personnes exécutant une copie locale, mais je ne peux pas donner une bonne raison pour laquelle c'est une mauvaise idée.

Devrions-nous utiliser PYTOHNPATH, sys.path, ou est-ce bien?

gaefan
la source
4
Il semble que les votes et les réponses soient répartis de manière assez égale avec une très légère tendance à utiliser PYTHON_PATH bien que cela puisse être un bruit d'échantillonnage ou un biais involontaire de la question.
AJP

Réponses:

42

Si la seule raison de modifier le chemin est pour les développeurs travaillant à partir de leur arbre de travail, vous devez utiliser un outil d'installation pour configurer votre environnement pour vous. virtualenv est très populaire, et si vous utilisez setuptools, vous pouvez simplement exécuter setup.py developpour semi-installer l'arborescence de travail dans votre installation Python actuelle.

Ned Batchelder
la source
10
Pouvez-vous offrir un peu plus de précisions à ce sujet? Même si vous installez un environnement conda / virtualenv, comment cela placerait-il le répertoire de niveau supérieur sur votre chemin python?
compguy24
38

Je déteste PYTHONPATH. Je trouve qu'il est fragile et ennuyeux de définir par utilisateur (en particulier pour les utilisateurs de démons) et de suivre l'évolution des dossiers de projet. Je préfère de loin définir sys.pathdans les scripts d'invocation pour les projets autonomes.

Cependant, ce sys.path.appendn'est pas la façon de le faire. Vous pouvez facilement obtenir des doublons et cela ne trie pas les .pthfichiers. Mieux (et plus lisible): site.addsitedir.

Et script.pyce ne serait normalement pas l'endroit le plus approprié pour le faire, car il se trouve à l' intérieur du package que vous souhaitez rendre disponible sur le chemin. Les modules de la bibliothèque ne devraient certainement pas se toucher sys.path. Au lieu de cela, vous auriez normalement un script hashbanged en dehors du package que vous utilisez pour instancier et exécuter l'application, et c'est dans ce script wrapper trivial que vous mettez des détails de déploiement comme sys.path-frobbing.

bobince
la source
16
Le problème avec site.addsitedirest qu'il fait un appendon sys.path, ce qui signifie qu'un paquet installé aura la priorité sur le paquet local dans le développement (et il peut en résulter un tirage de cheveux). sys.path.insert(0...est nécessaire pour surmonter cela.
Eli Bendersky
5
@EliBendersky: devrait être sys.path.insert(1. stackoverflow.com/q/10095037/125507
endolith
12

En général, je considérerais la mise en place d'une variable d'environnement (comme PYTHONPATH) comme une mauvaise pratique. Bien que cela puisse convenir pour un débogage ponctuel, l'utiliser comme
une pratique régulière peut ne pas être une bonne idée.

L'utilisation de la variable d'environnement conduit à des situations comme «ça marche pour moi» quand quelqu'un d'
autre signale des problèmes dans la base de code. On peut également appliquer la même pratique avec l'environnement de test, conduisant à des situations telles que les tests s'exécutant correctement pour un développeur particulier, mais échouant probablement lorsque quelqu'un lance les tests.

satin
la source
5

Je pense que dans ce cas, utiliser PYTHONPATH est une meilleure chose, principalement parce qu'il n'introduit pas de code inutile (discutable).

Après tout, si vous y pensez, votre utilisateur n'a pas besoin de cette sys.pathchose, car votre package sera installé dans les packages de site, car vous utiliserez un système de packaging.

Si l'utilisateur choisit de s'exécuter à partir d'une "copie locale", comme vous l'appelez, alors j'ai observé que la pratique habituelle est de déclarer que le package doit être ajouté manuellement à PYTHONPATH, s'il est utilisé en dehors des packages du site .

timide
la source
5

Outre les nombreuses autres raisons déjà mentionnées, vous pouvez également souligner que le codage en dur

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

est fragile car il suppose l'emplacement de script.py - cela ne fonctionnera que si script.py se trouve dans Project / package. Il se cassera si un utilisateur décide de déplacer / copier / symlink script.py (presque) n'importe où ailleurs.

unutbu
la source
2

Ni le piratage PYTHONPATHni sys.pathn'est une bonne idée pour les raisons mentionnées précédemment. Et pour lier le projet actuel dans le dossier site-packages, il existe en fait un meilleur moyen que python setup.py develop, comme expliqué ici :

pip install --editable path/to/project

Si vous n'avez pas encore de setup.py dans le dossier racine de votre projet, celui-ci est assez bon pour commencer:

from setuptools import setup
setup('project')
Peter
la source