为什么相对路径在python测试中不起作用?

时间:2016-07-06 18:42:02

标签: python relative-path setuptools pytest setup.py

我的目录布局如下

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'],
         },
)

1 个答案:

答案 0 :(得分:3)

相对导入仅在包中scripts可能是一个包,tests也是如此,但project目录不是(也不应该是)。这会使scriptstests 顶级软件包成为可能。您不能使用相对语法引用其他顶级名称。

此外,测试不会与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