我试图遵循PEP 328,其目录结构如下:

pkg/
  __init__.py
  components/
    core.py
    __init__.py
  tests/
    core_test.py
    __init__.py

在core_test.py中,我有以下import语句

from ..components.core import GameLoopEvents

然而,当我运行时,我得到以下错误:

tests$ python core_test.py 
Traceback (most recent call last):
  File "core_test.py", line 3, in <module>
    from ..components.core import GameLoopEvents
ValueError: Attempted relative import in non-package

四处搜索,我发现“相对路径即使使用__init__.py也无法工作”和“从相对路径导入模块”,但它们都没有帮助。

这里有什么我遗漏的吗?


当前回答

对你没有把它当作一个包。

python -m pkg.tests.core_test

其他回答

我也遇到过类似的问题,作为一名软件工程师,我认为这里提出的一些解决方案并不理想。如果您想要相对导入,则不应尝试/except,然后有时进行绝对导入。此外,要运行程序,您不必更改sys.path。

此外,程序应该始终运行,独立于当前的工作目录和启动方式。

因此,我创建了一个新的实验导入库:ultraimport它允许基于文件系统的导入,无论您如何运行代码。

从最初的问题中,您可以将core_test.py更改为

import ultraimport
GameLoopEvents = ultraimport('__dir__/../components/core.py', 'GameLoopEvents')
print(GameLoopEvents)

无论您如何运行测试,它都会找到它。

$ python -m tests.core_test
<class 'core.GameLoopEvents'>
 python ./tests/core_test.py 
<class 'core.GameLoopEvents'>

我还将此示例放入git repo的examples文件夹中。

由于图书馆是实验性的,我对反馈感兴趣。它对我有效,但尚未得到广泛测试。

正如Paolo所说,我们有两种调用方法:

1) python -m tests.core_test
2) python tests/core_test.py

它们之间的一个区别是sys.path[0]字符串。由于在执行导入时解释将搜索sys.path,因此我们可以使用tests/core_test.py:

if __name__ == '__main__':
    import sys
    from pathlib import Path
    sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
    from components import core
    <other stuff>

之后,我们可以使用其他方法运行core_test.py:

cd tests
python core_test.py
python -m core_test
...

注意,仅测试了py36。

对你没有把它当作一个包。

python -m pkg.tests.core_test

如果将当前目录附加到sys.path,则可以直接使用import components.core:

if __name__ == '__main__' and __package__ is None:
    from os import sys, path
    sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))

试试这个

import components
from components import *