python - python应用程序中脚本目录的成语?

标签 python django python-import

我有一个 python 应用程序(基于 Django),我有几个独立的维护脚本与应用程序一起使用,我必须不时调用它们。他们必须导入我的应用程序的一部分(子包)。目前,我只是将它们放在我的顶级目录中:

application/
  djangoproject/
  djangoapp/
  otherpackage/
  tool1.py
  tool2.py

tool1.py 可以做什么

from djangoproject import wsgi
from djangoapp.models import Poll

我已经积累了相当多的这些工具,并且想将它们移动到 scripts 子目录中。然后,我希望能够通过 python scripts/tool1.pycd scripts 调用它们; python tool1.py.

我理解(有时感叹)Python 的导入是如何工作的,我知道我可以向每个脚本添加一些行以将父目录添加到 PYTHONPATH。我想知道是否有一种广泛的模式来处理这样一组各种各样的脚本。也许可以将路径操作放到另一个文件中,并让每个脚本都以 import mainproject 开头?

我正在使用 virtualenv,并使用 pip 安装依赖项。但是应用程序本身目前不使用 setup.py,我认为将脚本移动到通过 pip 安装的单独包中无济于事,因为我在开发过程中对它们进行了很多更改,并且有很多一次性的。

最佳答案

组织源代码的方式因项目而异。根据我多年的经验,最好和最 pythonic 的方法是始终拥有 setup.py

在这种情况下,您可以制作 pip install -e .editable version来自 . 目录将被伪安装到 virtualenv。实际上,并没有真正安装(即复制),而是“链接”:源代码目录将添加到 sys.path.pth 文件,因此您可以编辑 &之后尝试不执行任何特殊的复制/安装步骤。

更多信息,您可以使用 extra dependencies 扩展 setup.py例如开发目的,并通过 pip install -e .[dev] 安装它们。更像是一个奇特的结果。

其余的取决于脚本的性质。


如果脚本是应用程序的一部分,则应通过 entry-points in setup.py 安装它们.

# setup.py:
setup(
    entry_points={
        'console_scripts': [
            'tool1 = mytools.tool1:main',
            'tool2 = mytools.tool2:main',
        ],
    },
)

在那种情况下,在 pip install -e . 之后,它们将在 virtualenv 的 bin 文件夹中,或者在 /usr/local/bin 或类似的,如果使用系统 python。您可以像这样执行它们:

source .venv/bin/activate
tool1 ...

# OR:

~/path/to/venv/bin/tool2

以这种方式安装的脚本完全了解安装它们的 virtualenv,因此不需要激活,也不需要显式的 python 二进制文件。


如果脚本用于代码维护,而不是应用程序的语义部分,那么它们通常被放入 ./scripts/ 目录(或任何其他目录,例如 ./ci/),shebang 位于顶部 (#!/usr/bin/env python)。例如,tool1.py:

#!/usr/bin/env python
def main():
    pass
if __name__ == '__main__':
    main()

由于这个 shebang 在当前 virtualenv 中执行如下:

source .venv/bin/activate
./scripts/tool1.py ...

# OR:

~/path/to/venv/bin/python ./scripts/tool1.py

与通过入口点安装的脚本不同,这些脚本不会以任何方式了解它们自己的 virtualenv,因此应该激活 virtualenv 或明确使用适当的 python。

当脚本不是 python 时也使用这种方式,例如对于 bash 脚本。


在这两种情况下,requirements.txt 文件有时用于固定应用程序和依赖项的版本(使用pip freeze),这样部署就会持久且可预测。但这是另一个故事 — 关于应用程序的部署,而不是关于打包和维护。

requirements.txt 文件会不时重新生成,以满足 setup.py 中新的未固定(即灵活)要求和可用的新包版本。但通常是生成的内容(尽管在 repo 中提交),而不是手动维护的内容。


如果您出于任何原因绝对不想拥有 setup.py,那么可以使用修改后的环境变量执行这些脚本:

PYTHONPATH=. python scripts/tool1.py

或者从内部破解 sys.path:

# tools1.py
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))

这正是 pip install -e . 所做的,只是在每次调用时手动完成,而不是使用 virtualenv 中的 .pth 文件。而且这看起来很古怪。

然而,正如我们所知,无论是 hacky 解决方案还是复制解决方案,尤其是那些复制标准工具包的解决方案,都不会被视为“pythonic”。

关于python - python应用程序中脚本目录的成语?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46715164/

相关文章:

python - 打开CV分水岭无法正确分割椭圆形对象

python - 如何在 matplotlib 中的单个矩形网格中绘制多个图?

javascript - 使用 Ajax 的 Django POST

python - Django 将所有具有不同外键 ID 的值求和,并使用相关表中的字段将它们压缩

python - 为什么 Python 找不到我正在导入的文件?

python - 如何处理像这样的Python导入

python - 浏览器在 django 管理(缓存,python/django)中更改页面内容时出现延迟

python - 使用模型表单中的 Generic_inlineformset_factory 创建表单

python - 为什么表单 "save()"方法的签名应该与 django 中的基 Form 类匹配?

python - 单个文件 - 两个模块