web-dev-qa-db-fra.com

Personnaliser le chemin de recherche du module (PYTHONPATH) via pipenv

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 pipenvchargement 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?

17
David Moles

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.
  • La liaison de dossiers ne sera pas vraiment mise à l'échelle si vous commencez à avoir d'autres dossiers de scripts.
12
charlax

(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.

1
Lohmar ASHAR