在 Python 中处理项目脚本中的路径/可执行文件的最佳实践(例如 Django 的 Manage.py 或 Fabric 之类的东西)

发布于 2025-01-04 03:50:11 字数 569 浏览 1 评论 0原文

我在一个相当标准化的目录结构中在不同的项目上做了很多工作(我是一名科学家)。例如:

project
   /analyses/
   /lib
   /doc
   /results
   /bin

我将所有各种实用程序脚本放在 /bin/ 中,因为清洁仅次于敬虔。但是,我必须对路径进行硬编码(例如 ../../x/y/z),然后我必须在 ./bin/ 中运行内容,否则它们就会中断。

我使用过 Django,它有 /manage.py ,它运行各种 django-things 并自动处理路径。我还使用 Fabric 来运行各种用户定义的函数。

问题:我该如何做类似的事情?最好的方法是什么?我可以轻松地在 /manage.py 中编写一些内容,将根目录注入 sys.path 等,但随后我希望能够执行“./manage.py foo”,它将运行 /bin/foo.py。或者是否可以让 Fabric 从某个目录调用可执行文件?

基本上 - 我想要一些简单且维护成本低的东西。我希望能够将可执行脚本/文件/任何内容放入 ./bin/ 中,而不必处理路径问题或导入问题。

最好的方法是什么?

I do a lot of work on different projects (I'm a scientist) in a fairly standardised directory structure. e.g.:

project
   /analyses/
   /lib
   /doc
   /results
   /bin

I put all my various utility scripts in /bin/ because cleanliness is next to godliness. However, I have to hard code paths (e.g. ../../x/y/z) and then I have to run things within ./bin/ or they break.

I've used Django and that has /manage.py which runs various django-things and automatically handles the path. I've also used fabric to run various user defined functions.

Question: How do I do something similar? and what's the best way? I can easily write something in /manage.py to inject the root dir into sys.path etc, but then I'd like to be able to do "./manage.py foo" which would run /bin/foo.py. Or is it possible to get fabric to call executables from a certain directory?

Basically - I want something easy and low maintenance. I want to be able to drop an executable script/file/whatever into ./bin/ and not have to deal with path issues or import issues.

What is the best way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

将执行保持在 TLD

通常,尝试将运行时保持在顶级。这将极大地理顺你的进口。

如果您必须使用相对导入进行大量导入寻址,则可能有一个
更好的方法。

修改路径

其他发帖者提到了PYTHONPATH。这是在 shell 中永久执行此操作的好方法。

如果您不想/无法直接操作 PYTHONPATH 项目路径,您可以使用 sys.path 来摆脱相对导入地狱。

使用 sys.path.append

sys.path 只是内部的一个列表。您可以附加到它以将内容添加到您的路径中。

假设我在 /bin 中,并且 lib/ 中有一个库 markdown。您可以使用 sys.path 附加相对路径来导入您想要的内容。

import sys
sys.path.append('../lib')
import markdown


print markdown.markdown("""

Hello world!
------------

""")

忠告:不要对 sys.path 添加过于疯狂。保持你的模式简单,以避免你自己陷入很多混乱。

过于急切的导入有时会导致 python 模块需要导入自身,此时执行将停止!

使用包和 __init__.py

另一个很棒的技巧是通过添加 __init__.py 文件来创建 python 包。 __init__.py 在目录中的任何其他模块之前加载,因此这是在整个目录中添加导入的好方法。这使得它成为添加 sys.path 黑客的理想场所。

您甚至不需要向文件中添加任何内容。只需在控制台上执行 touch __init__.py 即可将目录设为包。

请参阅此帖子以获取更具体的示例。

Keep Execution at TLD

In general, try to keep your runtime at top-level. This will straighten out your imports tremendously.

If you have to do a lot of import addressing with relative imports, there's probably a
better way.

Modifying The Path

Other poster's have mentioned the PYTHONPATH. That's a great way to do it permanently in your shell.

If you don't want to/aren't able to manipulate the PYTHONPATH project path directly you can use sys.path to get yourself out of relative import hell.

Using sys.path.append

sys.path is just a list internally. You can append to it to add stuff to into your path.

Say I'm in /bin and there's a library markdown in lib/. You can append a relative paths with sys.path to import what you want.

import sys
sys.path.append('../lib')
import markdown


print markdown.markdown("""

Hello world!
------------

""")

Word to the wise: Don't get too crazy with your sys.path additions. Keep your schema simple to avoid yourself a lot confusion.

Overly eager imports can sometimes lead to cases where a python module needs to import itself, at which point execution will halt!

Using Packages and __init__.py

Another great trick is creating python packages by adding __init__.py files. __init__.py gets loaded before any other modules in the directory, so it's a great way to add imports across the entire directory. This makes it an ideal spot to add sys.path hackery.

You don't even need to necessarily add anything to the file. It's sufficient to just do touch __init__.py at the console to make a directory a package.

See this SO post for a more concrete example.

无戏配角 2025-01-11 03:50:11

在当前 shell 中获取(而不是运行)的 shell 脚本中,设置以下环境变量:

PATH=$PATH:$PROJECTDIR/bin
PYTHONPATH=$PROJECTDIR/lib

然后将 Python 模块和包树放入项目的 ./lib 目录中。 Python 自动将 PYTHONPATH 环境变量添加到 sys.path 中。

然后,您可以从 shell 运行任何顶级脚本,而无需指定路径,并且会在 lib 目录中查找来自库模块的任何导入。

我推荐非常简单的顶级脚本,例如:

#!/usr/bin/python

import sys
import mytool

mytool.main(sys.argv)

那么您就不必更改它,只需编辑模块代码,并且还可以从字节码缓存中受益。

In a shell script that you source (not run) in your current shell you set the following environment variables:

PATH=$PATH:$PROJECTDIR/bin
PYTHONPATH=$PROJECTDIR/lib

Then you put your Python modules and package tree in your projects ./lib directory. Python automatically adds the PYTHONPATH environment variable to sys.path.

Then you can run any top-level script from the shell without specifying the path, and any imports from your library modules are looked for in the lib directory.

I recommend very simple top-level scripts, such as:

#!/usr/bin/python

import sys
import mytool

mytool.main(sys.argv)

Then you never have to change that, you just edit the module code, and also benefit from the byte-code caching.

羁〃客ぐ 2025-01-11 03:50:11

您可以通过创建一个托管每个项目的迷你包来轻松实现您的目标。使用粘贴脚本创建一个简单的项目框架。要使其可执行,只需通过 setup.pydevelopment 安装它。现在你的 bin 脚本只需要导入这个包的入口点并执行它。

You can easily achieve your goals by creating a mini package that hosts each one of your projects. Use paste scripts to create a simple project skeleton. And to make it executable, just install it via setup.py develop. Now your bin scripts just need to import the entry point to this package and execute it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文