Как tox-окружение устанавливает свой sys.path - PullRequest
2 голосов
/ 18 апреля 2019

У меня есть проект Python, который требует некоторой компиляции.tox делает sdist и bdist_wheel успешно.Но когда tox запускает тесты, всегда импортируется модуль исходного кода, что приводит к сбою тестов (поскольку там нет двоичных файлов).Это происходит потому, что корнем проекта всегда является первая папка на sys.path, и я не могу понять, как это происходит.

project
├── foo
│   ├── __init__.py
│   └── bar.c <-- turns into bar.so in bdist_wheel
├── tests
│   ├── __init__.py
│   └── test_bar.py
├── tox.ini
└── setup.py

tox.ini

[tox]
envlist =
    py37

[testenv]
changedir = {toxinidir}/tests
setenv =
    PYTHONPATH = {envsitepackagesdir}
commands = {envpython} -m pytest --cov=bar --cov-report=html

Обратите внимание, что яустановите changedir, чтобы убедиться, что корень проекта не является рабочим каталогом.Я также установил PYTHONPATH только для пакетов сайтов среды tox.Я также принудительно запускаю Python для токсикологической среды.

Тем не менее, это sys.path Я вижу, распечатываю ли я его во время пробного запуска:

[
  '/home/me/foo', # Bad, bad, bad
  '/home/me/foo/tests', # Good, this is the CWD
  '/home/me/foo/.tox/py37/lib/python3.7/site-packages', # Good
  '/home/me/foo/.tox/py37/lib/python37.zip', # Umm, ok, this doesn't exist
  '/home/me/foo/.tox/py37/lib/python3.7', # Good
  '/home/me/foo/.tox/py37/lib/python3.7/lib-dynload', # Probably good
  '/home/me/anaconda/envs/foo/lib/python3.7',  # Bad, why is this here?
]

Самый большой нарушитель - /home/me/foo что приводит к загрузке исходного модуля foo вместо установленного в tox.

Еще одним проблемным является /home/me/anaconda/envs/foo/lib/python3.7.Я бы предпочел, чтобы tox не прибегал к системному интерпретатору, если что-то не найдено в среде.

Как tox выбирает эти пути и как мне управлять этим, чтобы он вел себя лучше?

1 Ответ

2 голосов
/ 19 апреля 2019

Это не вызвано токсом;это вызвано pytest. Как описано в документации по pytest , известно, что существует плохое взаимодействие между pytest и инструментами, такими как tox, которые устанавливают дистрибутив в изолированной среде.

Причина этого заключается в том, что pytest изменяет sys.path, поэтому в него добавляются все папки, содержащие тестовые пакеты (тестовые папки с __init__.py в них).Поскольку каталог foo/tests содержит файл __init__.py, pytest добавляет foo/ к sys.path, так что пакет tests можно импортировать с помощью обычного оператора import.

Evenудаления __init__.py может быть недостаточно. Запуск pytest с именем python -m pytest в каталоге foo приведет к добавлению каталога foo в sys.path.Запуск pytest с помощью инструмента командной строки pytest позволит избежать этого.

Рекомендуемое решение - переместить весь источник в выделенный каталог src.Это гарантирует, что исходные пакеты никогда не будут в sys.path, даже если корнем проекта является.

Рекомендуемая структура проекта

project
├── src
│   └── foo
│       ├── __init__.py
│       └── bar.c
├── tests
│   ├── __init__.py
│   └── test_bar.py
├── tox.ini
└── setup.py
...