Personalizar la ruta de búsqueda del módulo (PYTHONPATH) a través de pipenv

Tengo un proyecto de Python que consta de un cuaderno Jupyter, varios scripts en un directorio bin y módulos en un directorio src , con dependencias en un Pipfile :

 myproject ├── myproject.ipynb ├── Pipfile ├── Pipfile.lock ├── bin │  ├── bar.py │  └── foo.py └── src ├── baz.py └── qux.py 

Los scripts foo.py y bar.py usan el shebang estándar

 #!/usr/bin/env python 

y se puede ejecutar con pipenv shell :

 mymachine:myproject myname$ pipenv shell (myproject-U308romt) bash-3.2$ bin/foo.py foo 

Sin embargo, no puedo acceder fácilmente a los módulos en src desde los scripts. Si agrego

 import src.baz as baz 

a foo.py , me sale

 ModuleNotFoundError: No module named 'src' 

Una solución que intenté es agregar un archivo myproject en myproject :

 PYTHONPATH=${PYTHONPATH}:${PWD} 

Esto funciona gracias a la carga automática de .env de .env , pero al registrar el archivo .env en la distribución de git del proyecto colisionaría con el uso tradicional de .env para almacenar secretos como contraseñas, de hecho, mi valor predeterminado es .gitignore para proyectos de Python ya excluye .env solo por esta razón.

 $ git add .env The following paths are ignored by one of your .gitignore files: .env Use -f if you really want to add them. 

Alternativamente, podría mover src debajo de bin , pero luego el portátil Jupyter tendría que hacer referencia a los módulos como bin.src.baz , etc., lo que también es una molestia.

Mi solución actual es simplemente agregar un enlace simbólico:

 myproject ├── Pipfile ├── Pipfile.lock ├── bin │  ├── bar.py │  ├── foo.py │  └── src -> ../src └── src ├── baz.py └── qux.py 

Esto funciona, y supongo que tiene la ventaja de ser transparente, pero parece que debería haber alguna forma de aprovechar el pipenv para resolver el mismo problema.

¿Existe una forma portátil y distribuible de colocar estos módulos en la ruta de búsqueda?

No estoy seguro de que haya una solución perfecta para esto, pero para ser más explícito que implícito ( PEP 20 ), he decidido registrar un archivo que debe obtenerse antes de ejecutar cualquier script. Este es un paso manual adicional, pero puede poner esto en un Makefile por ejemplo.

env.sh

 export PYTHONPATH=${PYTHONPATH}:${PWD} 

Makefile

 bar: source env.sh && pipenv run python scripts/bar.py .PHONY: migrate 

La solución es un poco similar al enfoque que Go toma con su GOPATH .

Creo que las otras soluciones no son tan buenas:

  • pipenv apunta a resolver dependencias, podría estar equivocado pero no encontré nada relacionado con el problema de PYTHONPATH .
  • Las carpetas de enlace no se escalarán muy bien si empiezas a tener otra carpeta de scripts.

(Vine aquí por una respuesta, terminó dando una en su lugar)

Tengo una estructura de carpetas de proyecto similar, así que tuve el mismo problema.
Gracias a su sugerencia, mi solución fue agregar un archivo .env al mismo nivel que el Pipfile con el siguiente contenido:

 $ cat .env PYTHONPATH=${PYTHONPATH}:src 

Ahora, iniciando mi aplicación con algo como

 $ pipenv run python -m package.subpackage.app 

parece funcionar bien desde la carpeta de mi proyecto y también desde sus subcarpetas.

Nota al margen (aunque no es una forma buena / limpia de hacer las cosas):
para su ModuleNotFoundError: No module named 'src' problema … el “problema” es que src (carpeta) no es un paquete, para arreglar que pueda agregar fácilmente un archivo __init__.py (vacío) dentro del src carpeta, por lo que es un “paquete”; que a su vez haría posible la import src.baz .

(Edición posterior)
En realidad, esto agrega un registro /${PYTHONPATH} en sys.path , que es inútil, por lo que el contenido correcto del archivo .env debería ser solo PYTHONPATH=src .