Настроить путь поиска модуля (PYTHONPATH) через pipenv

У меня есть проект Python, состоящий из ноутбука Jupyter, нескольких сценариев в каталоге bin и модулей в каталоге src с зависимостями в Pipfile:

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

Скрипты foo.py и bar.py используют стандартный shebang

#!/usr/bin/env python

и может работать с pipenv shell:

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

Однако я не могу легко получить доступ к модулям в src из сценариев. Если я добавлю

import src.baz as baz

к foo.py, я получаю:

ModuleNotFoundError: No module named 'src'

Одно из .env - добавить файл .env в myproject:

PYTHONPATH=${PYTHONPATH}:${PWD}

Это работает благодаря pipenv автоматической загрузки .env, но проверка .env файл в распределение мерзавца проекта будет сталкиваться с традиционным использованием .env хранить секреты, такие как пароли - на самом деле, мое по умолчанию .gitignore для Python проекты уже исключают .env именно по этой причине.

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

В качестве альтернативы, я мог бы перемещать src под bin, но тогда ноутбук Jupyter должен будет ссылаться на модули как bin.src.baz и т.д., bin.src.baz также является проблемой.

Мое текущее решение - просто добавить символическую ссылку:

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

Это работает, и я полагаю, что имеет преимущество быть прозрачным, но кажется, что должен быть какой-то способ использовать pipenv для решения одной и той же проблемы.

Есть ли переносимый, распространяемый способ поместить эти модули в путь поиска?

Ответ 1

Я не уверен, что для этого есть идеальное решение, но в интересах быть явным, а не подразумеваемым (PEP 20), я решил проверить файл, который должен быть отправлен до запуска любого скрипта. Это один дополнительный ручной шаг, но вы можете поместить его в Makefile, например.

env.sh

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

Makefile

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

Решение немного похоже на подход Go принимает с его GOPATH.

Я думаю, что другие решения не так хороши:

  • pipenv направлен на решение зависимостей, я мог ошибаться, но я не нашел ничего, связанного с проблемой PYTHONPATH.
  • Связывание папок не будет очень хорошо масштабироваться, если вы начнете использовать другую папку сценариев.

Ответ 2

(Пришел сюда за ответом, в итоге дал один вместо)

У меня похожая структура папок проекта, поэтому у меня была такая же проблема.
Благодаря вашему .env добавить файл .env на том же уровне, что и Pipfile со следующим содержимым:

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

Теперь запускаю мое приложение с чем-то вроде

$ pipenv run python -m package.subpackage.app

кажется, работает нормально из моей папки проекта, а также из его подпапок.

Примечание (хотя это не хороший/чистый способ сделать что-то):
для вашего ModuleNotFoundError: No module named 'src' проблема... "проблема" в том, что src (папка) не является пакетом, чтобы исправить это, вы можете легко добавить (пустой) файл __init__.py внутри src папка, что делает ее "упаковкой"; что в свою очередь сделает возможным import src.baz.