【问题标题】:Adding module to sys.modules to deal with non-relative submodule imports将模块添加到 sys.modules 以处理非相对子模块导入
【发布时间】:2021-09-28 07:02:08
【问题描述】:

我有一个我正在销售的子模块,其中写得不好(它不使用相对导入,但有两个包。需要说明的是,我没有安装这些包(因为它们没有维护良好的包) 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?

【问题讨论】:

    标签: python python-3.x python-import


    【解决方案1】:

    __init__.py 或缺少 PEP 420's Implicit Namespace Packages 与现代 (3.3+) Python 上的某个包是否算作包无关。

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

    解决方案是将他们的包安装到sys.path 位置或更新sys.path 以包含他们的位置,因此package_1package_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
    

    【讨论】:

    • 我认为这完全正确!那么我该怎么做呢?只需将 sys.path.append("vendor/submodule") 放在导入此文件的每个文件的顶部?或者是否有一个全局位置可以将其附加到 sys.path?
    • @aronchick:目前还不清楚你打算如何安装你的包(如果它被正确安装的话),所以很难说。如果仅从您的根包调用供应商模块,则可以选择在加载根包时手动处理sys.path。您也可以在 .pth 文件上查找文档,site 模块在将它们安装在 site-packages 目录(第三方的标准安装位置)中时,使用这些文件将任意路径添加到模块搜索路径包)。
    • 这是我解决它的方法 - 通过手动弄乱 sys.path 并将供应商/子模块目录附加到第一个使用位置。 (是否有一个全局的地方我应该把那个追加?)如果你想把它添加到你的答案中,我会给你打勾 - 否则,我会详细说明我在答案中做了什么。
    • @aronchick:我举了一个例子,说明如何让root/code/file.py 将相对于它自己的安装位置的路径插入sys.path。但是,您运行file.py,它会知道自己的路径,并且可以使用它来查找供应商模块的路径,如果它们安装在与您的目录树图所示的file.py 相关的相同位置。
    • @aronchick:如果它们都在同一个根包下,根的__init__.py 将处理它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-12
    • 1970-01-01
    • 1970-01-01
    • 2016-03-04
    • 2017-03-04
    • 1970-01-01
    • 2017-05-01
    相关资源
    最近更新 更多