为什么相对路径在 python 测试中不起作用?
Why is relative path not working in python tests?
我的目录布局如下
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'],
},
)
相对导入仅在 包内有效。 scripts
可能是一个包,tests
也是,但是 project
目录 不是 (也不应该是)。这使得 scripts
和 tests
顶级包 。您不能使用相对语法引用其他顶级名称。
此外,测试不是 运行 tests
包;测试 运行ner 导入 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
可以直接使用,而无需 [=74] =] 与 sys.path
.
此外,pytest 已经 为您完成这项工作;对于任何给定的测试文件,它将确保第一个包含 no __init__.py
文件的父目录位于 sys.path
上。在您的情况下,这是 project/
目录,因此再次 scripts
可直接从中导入。见 Good Practices:
If pytest
finds a “a/b/test_module.py” test file while recursing into the filesystem it determines the import name as follows:
- determine
basedir
: this is the first “upward” (towards the root) directory not containing an __init__.py
. If e.g. both a and b contain an __init__.py
file then the parent directory of a will become the basedir.
- perform
sys.path.insert(0, basedir)
to make the test module importable under the fully qualified import name.
import a.b.test_module
where the path is determined by converting path separators / into ”.” characters. This means you must follow the convention of having directory and file names map directly to the import names.
请注意,为了在使用 setup.py test
时实际使用 pytest
到 运行 测试,您需要在 setup.cfg
文件中注册一个别名(创建它在 project/
如果你没有):
[aliases]
test = pytest
我的目录布局如下
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'],
},
)
相对导入仅在 包内有效。 scripts
可能是一个包,tests
也是,但是 project
目录 不是 (也不应该是)。这使得 scripts
和 tests
顶级包 。您不能使用相对语法引用其他顶级名称。
此外,测试不是 运行 tests
包;测试 运行ner 导入 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
可以直接使用,而无需 [=74] =] 与 sys.path
.
此外,pytest 已经 为您完成这项工作;对于任何给定的测试文件,它将确保第一个包含 no __init__.py
文件的父目录位于 sys.path
上。在您的情况下,这是 project/
目录,因此再次 scripts
可直接从中导入。见 Good Practices:
If
pytest
finds a “a/b/test_module.py” test file while recursing into the filesystem it determines the import name as follows:
- determine
basedir
: this is the first “upward” (towards the root) directory not containing an__init__.py
. If e.g. both a and b contain an__init__.py
file then the parent directory of a will become the basedir.- perform
sys.path.insert(0, basedir)
to make the test module importable under the fully qualified import name.import a.b.test_module
where the path is determined by converting path separators / into ”.” characters. This means you must follow the convention of having directory and file names map directly to the import names.
请注意,为了在使用 setup.py test
时实际使用 pytest
到 运行 测试,您需要在 setup.cfg
文件中注册一个别名(创建它在 project/
如果你没有):
[aliases]
test = pytest