通过pipenv自定义模块搜索路径(PYTHONPATH)

问题描述 投票:0回答:4

我有一个 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
下添加一个
myproject
文件:

PYTHONPATH=${PYTHONPATH}:${PWD}

这要归功于

pipenv
自动加载
.env
,但是将
.env
文件签入项目的git发行版会与
.env
存储密码等秘密的传统用法发生冲突 - - 事实上,出于这个原因,我对 Python 项目的默认
.gitignore
已经排除了
.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
来解决同样的问题。

是否有一种可移植、可分发的方式将这些模块放在搜索路径上?

python python-3.x pythonpath pipenv
4个回答
20
投票

我不确定是否有一个完美的解决方案,但为了显式而不是隐式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
    问题相关的任何内容。
  • 如果您开始拥有其他脚本文件夹,链接文件夹将无法很好地扩展。

13
投票

(来这里寻求答案,最后却给出了答案)

我有类似的项目文件夹结构,所以我遇到了同样的问题。
感谢您的提示,我的解决方案是在与

.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


0
投票

您可能可以使用两个单独的 .env 文件。一个用于您的密码,另一个用于其他地方的 pipelinev。您可以通过在环境中设置 PIPENV_DOTENV_LOCATION 变量来为 pipelinenv .env 文件使用自定义路径。 如果你认为这是可移植的,如果你必须先设置变量,这是有争议的。

无论如何,根据经验,你不应该太依赖 .env 的自动加载。如果您使用远程/ssh 互斥器或出于测试目的并行使用多个环境,最简洁的方法是将项目路径添加到 Python 环境的 site-packages 文件夹中的 *.pth 文件中。在 conda 中,有一个明确的“开发”命令,但在 pipelinev 中,您仍然必须手动执行此操作。不过,这就是方法,因为您可以在任意设置中为项目显式创建 Python 环境,然后您还应该将项目位置硬连接到此设置中。


0
投票

在项目根目录下,我:

  • 创建了一个最小的
    setup.py
  • pipenv install -e .

然后我可以在项目目录中的任何位置运行

pipenv run python file/path.py
并且像
import src.baz as baz
这样的导入似乎可以工作。

© www.soinside.com 2019 - 2024. All rights reserved.