[英]Automatically patching PYTHONPATH (when using Fabric tasks)
I wrap function calls within my initialization module with a decorator that patches PYTHONPATH to add current directory to it so I can use relative imports within my modules without worrying about adding the package to PYTHONPATH explicitly (edited based on @abarnert's comments)我在我的初始化模块中包装函数调用,装饰器修补 PYTHONPATH 以将当前目录添加到它,这样我就可以在我的模块中使用相对导入,而不必担心将包显式添加到 PYTHONPATH(根据@abarnert 的评论进行编辑)
def patch_python_path(f):
@wraps(f)
def wrap(*args, **kwargs):
ROOT = os.pathsep.join([os.path.abspath(os.path.dirname(__file__))])
if not os.environ.has_key("PYTHONPATH"):
os.environ["PYTHONPATH"] = ""
if not (ROOT in os.environ["PYTHONPATH"].split(":")):
os.environ["PYTHONPATH"] = "%s:%s" % (os.environ["PYTHONPATH"], ROOT)
if not ROOT in sys.path:
sys.path.append(ROOT)
return f(*args, **kwargs)
return wrap
Here's how I use it:这是我如何使用它:
@patch_python_path
def initialize():
#at this point any code being run has access to local modules through relative imports
pass
Are there any major issues with this approach that I am not aware of?这种方法有什么我不知道的重大问题吗?
My objectives with this are the following:我的目标如下:
[EDIT] I'm actually realizing that the problem I am facing has more to do with the way Fabric runs tasks as opposed to pure Python module importing. [编辑] 我实际上意识到我面临的问题更多地与 Fabric 运行任务的方式有关,而不是纯 Python 模块导入。 If I attempt to run a task from a python shell (as opposed to fab task1) all the imports are resolved correctly without any patching required.如果我尝试从 python shell(而不是 fab task1)运行任务,则所有导入都会正确解析,无需任何修补。 Running a task through fab causes import errors通过 fab 运行任务会导致导入错误
os.environ
is global. os.environ
是全球性的。 You're modifying it, and not modifying it back afterward.你正在修改它,之后不会再修改它。 So, after doing @patch_python_path
on any function, you've now done the equivalent for everything else you define after that—including in other modules and in the top-level script.因此,在对任何函数执行@patch_python_path
之后,您现在已经为之后定义的所有其他内容执行了等效操作——包括在其他模块和顶级脚本中。sys.path
is also global, and again you're modifying it and not restoring it. sys.path
也是全局的,您再次修改它而不是恢复它。PYTHONPATH
and sys.path
.您永远不需要同时修改PYTHONPATH
和sys.path
。 (In particular, it's the former that you usually shouldn't need.) (特别是,您通常不需要前者。).
您正在添加.
to PYTHONPATH
, but os.getcwd()
to sys.path
.到PYTHONPATH
,但os.getcwd()
到sys.path
。 If you ever do need to modify both, everything will stop working after an os.chdir()
, which will effectively change the PYTHONPATH
but not the sys.path
.如果您确实需要修改两者,那么在os.chdir()
之后一切都将停止工作,这将有效地更改PYTHONPATH
而不是sys.path
。@functools.wraps
on your wrap
function.在你的wrap
函数上使用@functools.wraps
。Those are all just issues with your implementation, without getting into whether it's a good idea in the first place.这些都只是你的实现的问题,而没有首先考虑它是否是一个好主意。
The most common reasons people want something like this are (a) make Python XY packages work like Python VW, and (b) allow importing a package from the source tree to work the same as importing it after install, even from the interpreter shell.人们想要这样的东西的最常见原因是 (a) 使 Python XY 包像 Python VW 一样工作,以及 (b) 允许从源树导入包与在安装后导入包一样工作,即使是从解释器 shell。 The former is probably a bad idea;前者可能是个坏主意; the latter is handy, but there are other ways to accomplish it.后者很方便,但还有其他方法可以实现。 If you have some different higher-level goal, you'll have to tell us what that goal is before anyone can tell you whether this is the best way to accomplish it.如果你有一些不同的更高层次的目标,你必须先告诉我们那个目标是什么,然后任何人才能告诉你这是否是实现它的最佳方式。
You might simply add current path to sys.path
:您可以简单地将当前路径添加到sys.path
:
import sys
def patch_python_path(f):
def wrap(*args, **kwargs):
if not '.' in sys.path:
sys.path.append('.')
return f(*args, **kwargs)
return wrap
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.