J'ai un projet Python composé d'un bloc-notes Jupyter, de plusieurs scripts dans un répertoire bin
et de modules dans un répertoire src
, avec des dépendances dans un Pipfile
:
myproject
├── myproject.ipynb
├── Pipfile
├── Pipfile.lock
├── bin
│ ├── bar.py
│ └── foo.py
└── src
├── baz.py
└── qux.py
Les scripts foo.py
et bar.py
utiliser le Shebang standard
#!/usr/bin/env python
et peut être exécuté avec pipenv Shell
:
mymachine:myproject myname$ pipenv Shell
(myproject-U308romt) bash-3.2$ bin/foo.py
foo
Cependant, je ne peux pas accéder facilement aux modules dans src
à partir des scripts. Si j'ajoute
import src.baz as baz
à foo.py
, Je reçois:
ModuleNotFoundError: No module named 'src'
Une solution que j'ai essayée est d'ajouter un .env
fichier sous myproject
:
PYTHONPATH=${PYTHONPATH}:${PWD}
Cela fonctionne grâce aux pipenv
chargement automatique de .env
, mais en vérifiant le .env
dans la distribution git du projet entrerait en collision avec l'utilisation traditionnelle de .env
pour stocker des secrets tels que les mots de passe - en fait, ma valeur par défaut .gitignore
pour Python excluent déjà .env
juste pour cette raison.
$ git add .env
The following paths are ignored by one of your .gitignore files:
.env
Use -f if you really want to add them.
Alternativement, je pourrais déplacer src
sous bin
, mais le bloc-notes Jupyter devrait référencer les modules comme bin.src.baz
etc., ce qui est également un problème.
Ma solution de contournement actuelle consiste simplement à ajouter un lien symbolique:
myproject
├── Pipfile
├── Pipfile.lock
├── bin
│ ├── bar.py
│ ├── foo.py
│ └── src -> ../src
└── src
├── baz.py
└── qux.py
Cela fonctionne, et je suppose qu'il a l'avantage d'être transparent, mais il semble qu'il devrait y avoir un moyen de tirer parti de pipenv
pour résoudre le même problème.
Existe-t-il un moyen portable et distribuable de placer ces modules sur le chemin de recherche?
Je ne suis pas sûr qu'il existe une solution parfaite pour cela, mais dans l'intérêt d'être explicite plutôt qu'implicite ( PEP 2 ), j'ai décidé de m'enregistrer un fichier qui doit être obtenu avant d'exécuter un script. C'est une étape manuelle supplémentaire mais vous pouvez la mettre dans un Makefile par exemple.
env.sh
export PYTHONPATH=${PYTHONPATH}:${PWD}
Makefile
bar:
source env.sh && pipenv run python scripts/bar.py
.PHONY: migrate
La solution est un peu similaire à l'approche de Go avec son GOPATH
.
Je pense que les autres solutions ne sont pas aussi bonnes:
pipenv
vise à résoudre les dépendances, je peux me tromper mais je n'ai rien trouvé de lié au problème du PYTHONPATH
.(Je suis venu ici pour une réponse, j'ai fini par en donner une à la place)
J'ai une structure de dossiers de projet similaire, j'ai donc eu le même problème.
Grâce à votre conseil, ma solution a été d'ajouter un fichier .env
au même niveau que le Pipfile
avec le contenu suivant:
$ cat .env
PYTHONPATH=${PYTHONPATH}:src
Maintenant, lancer mon application avec quelque chose comme
$ pipenv run python -m package.subpackage.app
semble fonctionner correctement depuis le dossier de mon projet et aussi depuis ses sous-dossiers.
Note latérale (bien que ce ne soit pas une bonne façon de faire les choses):
pour votre ModuleNotFoundError: No module named 'src'
problème ... le "problème" est que le src
(dossier) n'est pas un package, afin de corriger que vous pourriez facilement ajouter un (vide) __init__.py
fichier dans le dossier src
, des milliers en faisant un "package"; ce qui à son tour ferait import src.baz
possible.
(Édition ultérieure)
En fait, cela ajoute un enregistrement <project_folder>/${PYTHONPATH}
dans sys.path
, ce qui est inutile, donc le contenu correct du .env
le fichier ne doit être que PYTHONPATH=src
.