确实,addsitedir()
不处理 zip 文件;但它应该很容易复制行为。
见site.addsitedir()
源代码;该代码只是尝试调用os.listdir()
路径然后发现.pth
文件:
try:
names = os.listdir(sitedir)
except os.error:
return
dotpth = os.extsep + "pth"
names = [name for name in names if name.endswith(dotpth)]
for name in sorted(names):
addpackage(sitedir, name, known_paths)
addpackage()
只是在哪里site.addpackage()
。您可以将上面names
的列表替换为.pth
zipfile 中的文件列表。您还必须复制该site.addpackage()
行为,该函数期望能够读取.pth
文件。
简化后,该函数执行以下操作:
with f:
for n, line in enumerate(f):
if line.startswith("#"):
continue
if line.startswith(("import ", "import\t")):
exec line
continue
line = line.rstrip()
dir, dircase = makepath(sitedir, line)
if not dircase in known_paths and os.path.exists(dir):
sys.path.append(dir)
known_paths.add(dircase)
混合了异常处理。makepath()
is site.makepath()
,并known_paths
确保找到的任何路径只添加一次。
因此,从本质上讲,所有以 by 命名的项目都会.pth
添加到您的文件中,sys.path
但以 开头的任何内容import
都会在那里执行,然后为.pth
文件提供一个进入site.py
加载阶段的钩子。
基于 - 的包使用该import
钩子setuptools
来构建命名空间包;这是命名空间中的一个包中的一个zc
:
import sys,types,os; p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('zc',)); ie = os.path.exists(os.path.join(p,'__init__.py')); m = not ie and sys.modules.setdefault('zc',types.ModuleType('zc')); mp = (m or []) and m.__dict__.setdefault('__path__',[]); (p not in mp) and mp.append(p)
sys.modules
它使用函数中的sitedir
局部变量创建一个空模块对象addpackage()
。注意os.path.exists()
通话;对于压缩鸡蛋,这将失败(不添加空模块对象),因此您可能需要检测命名空间包并为这些包提供您自己的版本。命名空间中的任何包都zc
只是确保ModuleType()
它关心的父命名空间有一个对象,其__path__
属性指向{sitedir}/{packagename}/__init__.py
.
另一种选择是将命名空间包合并到一个目录结构中。