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

时间:2017-10-12 17:01:04

标签: 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安装的单独软件包是没有用的,因为我在开发过程中经常更改它们,有很多一次性的。

1 个答案:

答案 0 :(得分:1)

组织源代码的方式因项目而异。从我多年的经验来看,最好和最抒情的方式是始终拥有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 .之后,如果使用系统python,它们将位于virtualenv的bin文件夹中,或者位于/usr/local/bin或类似文件夹中。您可以像这样执行它们:

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文件有时用于 pin 应用程序的&依赖项的版本(带pip freeze),这样部署就可以持久化了。可预测的。但这是另一个故事 - 关于应用程序的部署,而不是关于包装和安装;维护。

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

如果您因任何原因严格不希望setup.py,那么请使用修改后的env var执行这些脚本:

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”。