我的目录布局如下
project\
project\setup.py
project\scripts\foo.py
project\scripts\bar.py
project\scripts\__init__.py
project\tests\test_foo.py
project\tests\__init__.py
我的测试文件如下所示
project\tests\test_fo.py
from ..scripts import foo
def test_one():
assert 0
当我这样做时,我收到以下错误
cd C:\project
C:\virtualenvs\test_env\Scripts\activate
python setup.py install
python setup.py test
E ValueError:尝试相对导入超出顶级包
我做错了什么? 这是我的setup.py
setup(
name = 'project',
setup_requires=['pytest-runner'],
tests_require=['pytest'],
packages = ["scripts","tests"],
package_data={
'scripts': ['*.py'],
'tests': ['*.py'],
},
)
答案 0 :(得分:3)
相对导入仅在包中。 scripts
可能是一个包,tests
也是如此,但project
目录不是(也不应该是)。这会使scripts
和tests
顶级软件包成为可能。您不能使用相对语法引用其他顶级名称。
此外,测试不会与tests
包一起运行;测试运行器导入test_foo
模块,而不是tests.test_foo
模块,所以就Python而言 test_foo
是顶层模块。
scripts
是顶级名称,只需直接使用即可。但是,您必须将project
目录添加到sys.path
。您可以在test_foo.py
文件的顶部执行此操作:
import os
import sys
TEST_DIR = os.path.dirname(os.path.abspath(__file__))
PROJECT_DIR = os.path.abspath(os.path.join(TEST_DIR, os.pardir))
sys.path.insert(0, PROJECT_DIR)
然后从scripts
导入绝对路径:
from scripts import foo
但请注意,当您运行python setup.py
时,无论如何,您当前的工作目录都会添加到sys.path
,因此scripts
可以直接使用,而不必使用sys.path
。< / p>
此外,pytest 已为你做的工作;对于任何给定的测试文件,它将确保其中包含 no __init__.py
文件的第一个父目录位于sys.path
。在您的情况下,这是project/
目录,因此可以直接从scripts
导入pytest
。见Good Practices:
如果
basedir
在递归到文件系统时找到“a / b / test_module.py”测试文件,则确定导入名称如下:
- 确定
__init__.py
:这是第一个“向上”(朝向根)目录,不包含__init__.py
。如果是a和b都包含sys.path.insert(0, basedir)
文件,然后a的父目录将成为basedir。- 执行
import a.b.test_module
以使测试模块可以在完全限定的导入名称下导入。pytest
其中路径是通过将路径分隔符/转换为“。”字符来确定的。这意味着您必须遵循将目录和文件名直接映射到导入名称的约定。
请注意,为了在您使用setup.py test
时实际使用setup.cfg
来运行测试,您需要在project/
文件中注册别名(在{{1}中创建)如果你没有):
[aliases]
test = pytest