Настроить путь поиска модуля (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 используют стандартный шебанг

#!/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 под myproject:

PYTHONPATH=${PYTHONPATH}:${PWD}

Это работает благодаря автоматической загрузке .env, но проверка файла .env в дистрибутиве git проекта столкнулась бы с традиционным использованием .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 и т. д., что также является проблемой.

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

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

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

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


person David Moles    schedule 06.04.2018    source источник
comment
У меня та же .env идея, что и у вас. Но тогда значение моего пути буквально ${PYTHONPATH}:${PWD}. Почему это сработало для вас?   -  person Pranasas    schedule 02.08.2018
comment
@Pranasas Я не знаю, извини. Попробуйте задать новый вопрос.   -  person David Moles    schedule 02.08.2018


Ответы (3)


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

env.sh

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

Создать файл

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

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

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

  • pipenv направлен на решение зависимостей, я могу ошибаться, но я не нашел ничего, связанного с проблемой PYTHONPATH.
  • Связывание папок не будет хорошо масштабироваться, если у вас появится другая папка со скриптами.
person charlax    schedule 12.04.2018
comment
pipenv также автоматически загружает файлы .env - person Zeragamba; 22.05.2019
comment
Вместо того, чтобы создавать bash-скрипт, вы можете просто установить env vars перед командой для запуска pipenv. Используя ту же строку, что и в вашем Makefile: PYTHONPATH=${PYTHONPATH}:${PWD} pipenv run python scripts/bar.py - person jpenna; 10.08.2019
comment
Не придираться, но как это решение (или любое подобное решение в этом отношении) проще и явнее, чем просто запуск export PYTHONPATH=.? Вы делаете отдельный скрипт и создаете Makefile, чтобы сохранить одну строку кода? Это выглядит крайне непитоново :) - person gented; 15.11.2019

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

У меня похожая структура папок проекта, поэтому у меня была та же проблема.
Благодаря вашему совету я решил добавить файл .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.

(Позднее редактирование)
На самом деле это добавляет запись <project_folder>/${PYTHONPATH} в sys.path, что бесполезно, поэтому правильное содержимое файла .env должно быть только PYTHONPATH=src.

person Lohmar ASHAR    schedule 07.01.2019
comment
Это самый удобный ответ без обходного пути. Файл .env (env vars), на мой взгляд, лучшее решение. - person msarafzadeh; 03.10.2019
comment
Через 3 часа я нашел твой ответ, спасибо, братан, так просто :) - person Lincoln; 13.10.2019

Вероятно, вы можете использовать два отдельных файла .env. Один для ваших паролей и один для pipenv где-то еще. Вы можете использовать собственный путь для вашего .env-файла pipenv, установив переменную PIPENV_DOTENV_LOCATION в среде. Это спорно, если вы считаете это переносимым, если вам нужно сначала установить переменную.

В любом случае, по опыту, вы не должны слишком полагаться на автозагрузку .env. Если вы используете удаленные/ssh интерпретаторы или имеете несколько параллельных сред для целей тестирования, самым чистым способом было бы просто добавить путь к вашему проекту в файл *.pth в папке site-packages вашей среды Python. В conda для этого есть явная команда разработки, но в pipenv вам все равно придется делать это вручную. Тем не менее, это так, потому что вы создаете свою среду Python явно для своего проекта в произвольной настройке, а затем вы также должны жестко привязать местоположение проекта к этой настройке.

person CheradenineZK    schedule 26.07.2021