将模块添加到 sys.modules 以处理非相关子模块导入

Adding module to sys.modules to deal with non-relative submodule imports

我有一个我正在销售的子模块,其中写得不好(它不使用相对导入但有两个包。要清楚,我没有安装这些包(因为它们没有得到很好的维护pypi 上的包,只包括源代码。)

因此布局如下所示:

root
  |
  |-code
  |   |-file.py
  |
  |-vendor
      |-submodule
           |-package_1
           |    |-alpha.py
           |-package_2
                |-beta.py

不幸的是,beta.py 尝试 import package_1 但没有成功,因为没有 __init__.py。因为我在 CI/CD 期间更新了所有子模块,所以缺少相关导入破坏了我的测试。

如果一切都在根目录下,这会起作用,但我无法控制子模块。我也不想更改 alpha.py 或 beta.py 因为我不想处理分叉。

有没有什么办法可以得到一个通用的 __init__.py 或一些等效的东西,这样当 beta.py 导入时,它会看到 package_1 和 alpha.py?

由于 PEP 420's Implicit Namespace Packages.

__init__.py 或缺少它们与某些东西在现代(3.3+)Python 上是否算作一个包无关

有些东西告诉我供应商包希望包含他们两个包的目录(在本例中为 root/vendor/submodule)通过某种机制添加到 sys.path(可能只是安装在顶层)在 site-packages 中,而不是在您设置的某个嵌套目录中);如果您的重新打包未能将它们放入 sys.path 中的 some 条目的根目录中,也没有更新 sys.path 以包含您放置它们的任何位置,那么它们的包将不会没用。

解决方案是将它们的包安装到 sys.path 位置或更新 sys.path 以包括它们的位置,因此 package_1 是顶级包,因为 package_2期待。

假设这些供应商模块仅在 file.py 中使用,您可以导入 file.py 手动更新 sys.path,代码如下:

import pathlib
import sys

# Get the path to file.py, go up to the parent directory, then down to 
# vendor/submodule
vendor_dir = pathlib.Path(__file__).parent.parent / 'vendor' / 'submodule'
sys.path.append(str(vendor_dir))

# import package_1.alpha or package_2.beta will now work