如何将 python git 回购作为包导入

How to import python git repos as packages

我在从两个 git 存储库导入 python 模块时遇到问题,因为代码不是作为一个包设计的,并且存在名称冲突,这使我无法使用 sys.path.append 以一种直截了当的方式(尽管有点老套?)。

请注意,问题不是 git-repos 所特有的,但是由于尝试与现有工作交互,我只在这种情况下遇到过这个问题。

文件夹结构如下所示:

project
  - repo1
    - foo.py
    - bar.py
    - run.py
  - repo2
    - foo.py
    - bar.py
    - run.py
  test.py

Both foo.py import bar.py with import bar statements,只要你在 repo 中 运行ning run.py 脚本就可以正常工作,但是,如果我尝试导入 repo1.foorepo2.foo 我 运行 到多个问题中。

在尝试以下代码时

# test.py
import repo1.foo
import repo2.foo

我收到错误 ModuleNotFoundError: No module named 'bar',这是有道理的,因为路径中没有任何内容使 bar.py 可访问。

但是,如果我尝试附加路径 'repo1' 和 'repo2',那么我只能根据附加顺序导入 repo1.barrepo2.bar,这不是可接受的解决方案。

由于存储库不是我的代码,所以我宁愿不更改它们,而是尽可能将它们包装到命名空间包中,但是我找不到任何解决问题的方法。

TL;DR

Update:: 因为我非常依赖这项工作,所以我将它作为 Python 包发布在这里:https://pypi.org/project/packagify/。您可以安装它而不是复制旧的要点。

在您的代码中添加此要点中的 class:https://gist.github.com/rijulg/3ea372bef35adb68e27080c949c942af,您可以按以下方式使用它

from packagify import Packagify
package = Packagify("/home/workspace/my_package")
object = package.import_module("module", ["object"])
object1, object2 = package.import_module("module", ["object1", "object2"])

尝试过的方法

  1. 使用 setuptools 将目录安装为模块,这在加载模块时不起作用,其中的各个部分抛出 ModuleNotFoundError,因为他们试图访问兄弟姐妹没有命名空间。
  2. 各种importlib函数,有一些允许直接从.py文件加载python模块。如果我想导入的模块包含在一个文件中,这可能会奏效,但也许还有其他解决方案。由于问题所在,我无法使用此方法,因为加载时模块无法找到它的兄弟姐妹。
  3. 如问题中所述添加 sys.path,但我也尝试附加路径、加载模块,然后在加载其他模块之前删除路径。这也不起作用,因为大概模块被加载到 python 缓存中,并且由于名称冲突而忽略了来自不同目录的后续加载。
  4. 最后,当我使用 __import__ 函数更改导入级别时,我注意到发生了一些奇怪的事情,我尝试了以下代码段,它在我的玩具示例中运行良好。然而,这仍然有我在尝试加载我想要使用的实际回购协议时遇到的各种问题。由于解决方案似乎朝着正确的方向发展,我在 post.
  5. 的开头提到了要点中链接的 class
import builtins

original_import = __import__

def my_import(name, globals, locals, fromlist, level):
    print("my_import", name, globals['__package__'], level)
    try:
        return original_import(name, globals, locals, fromlist, level)
    except:
        level = level + 1 if globals['__package__'] is not None else level
        return original_import(name, globals, locals, fromlist, level)

builtins.__import__ = my_import

from repo1.foo import main as main_a
from repo2.foo import main as main_b

main_a()
main_b()