Python 导入挂钩以添加路径

Python Import Hook to Prepend Path

我正在尝试根据 QuantConnect 的目录结构修复我的“库”导入。他们组织“用户库”的方式是这样的:

假设我创建了一个名为“Project”的项目,通过 UI 选择选择了一个名为“Utilities”的库。 QC 创建以下文件夹结构:

.
├── Project
    |── main.py
├── Library
    ├── Utilities
        ├── Whatever.py

然而,QC 如何导入“Utilities”库出现了问题。它通过在删除顶级目录名称的同时导入目录的所有内容来实现。您可以将结果结构视为:

.
├── Project
    |── main.py
    ├── Whatever.py

因此,我无法再使用 from Utilities.Whatever import *。因此,为了缓解他们平台上的这个问题,我将每个库的所有内容放入同名文件夹中。所以原来的结构现在看起来像:

.
├── Project
    |── main.py
├── Library
    ├── Utilities
        ├── Utilities
            ├── Whatever.py

...最终结构如下:

.
├── Project
    |── main.py
    ├── Utilities
        ├── Whatever.py

现在导入工作正常。只是现在它们只能通过 QC 的在线“算法实验室”按预期工作,而不是在本地!由于 QC 导入用户库的方式,我无法更改此布局,因此我需要创建一个 python 导入挂钩,它将尝试找到一个环境变量,如果未设置,则默认为不执行钩子;但是当找到时,它在非 QC 环境中被假定为 运行,并且应该在导入的第一级目录名称前加上。即,将 from Utilities.Whatever import * 翻译成 from Utilities.Utilities.Whatever import *.

我读过很多 articles/tutorials 关于 python 的导入挂钩,但它们都提供了广泛不同的解决方案来解决我正在寻找的问题,而且我无法理解 hook 结构的内部工作原理。

我最终创建了两个名为 'Library.py' 的文件。一个是空的,放在Library/Utilities/Utilities,另一个(不是空的)放在Library/Utilities。所以现在,当我在 QC 环境中的任何给定脚本中键入 import Utilities.Library 时,运行 没有任何反应(应该如此),因为被引用的 Library.py 文件是空的;当它 运行s 在本地环境中时,执行以下代码:

import os
import sys

# Use env variable to ensure we only update the sys path once
env_check = 'Checked-Library-Environment'
if os.environ.get(env_check) is None:
    os.environ[env_check] = 'True'

    _path = None
    path = os.getcwd()
    target = "Library"
    library = None

    # Stop searching when we've reached the root
    while path is not _path:
        test_path = os.path.join(path, target)
        if os.path.isdir(test_path):
            library = test_path
            break
        _path = path
        path = os.path.dirname(path)

    # If we've found the Library directory, add its contents to the module path list
    if library is not None:
        for name in os.listdir(library):
            path = os.path.join(library, name)
            if not path in sys.path:
                sys.path.append(path)