我有一个 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.py
或 cd 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/