2016-07-06 6 views
1

Моя схема каталогов выглядят следующим образомПочему относительный путь не работает в тестах python?

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

ответ

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.

Кроме того, pytest будет уже выполнить работу за вас; для любого заданного тестового файла он будет убедиться, что первый родительский каталог с нет__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.

Обратите внимание, что для того, чтобы реально использовать pytest для запуска тестов при использовании setup.py test, необходимо зарегистрировать псевдоним в файле setup.cfg (создать его в project/, если у вас нет):

[aliases] 
test = pytest 
+0

после того, как изменить его из сценариев импорта Foo Я получаю эту ошибку (test_123) D: \ Projects \ тестовый проект> питон setup.py работает тест работает egg_info написание project.egg-инфо \ PKG-INFO написание имен верхнего уровня для project.egg-инфо \ top_level.txt пишущие dependency_links к project.egg-инфо \ dependency_links.txt чтения файла манифеста 'project.egg-info \ SOURCES.txt' файл манифеста 'project.egg-info \ SOURCES.txt' running build_ext ------------------- -------------------------------------------------- - Ran 0 тестов в 0.000s OK – user330612

+0

@ user330612: Завтра я посмотрю. –

+0

@ user330612: обратите внимание на ссылку «Хорошая практика» в моем ответе; там есть информация о необходимости добавления псевдонима в файл 'setup.cfg', прежде чем' pytest' используется для запуска тестов. –