Как я могу заставить tox и поэзию работать вместе для поддержки тестирования нескольких версий зависимости Python?

Я переключаю проект, который в настоящее время использует pipenv на poetry в качестве теста, чтобы увидеть, в чем разница. Проект представляет собой простое распространяемое приложение Django. Он поддерживает Python 3.6-8, а также Django 2.2 и 3.0. У меня есть tox.ini файл, который охватывает все комбинации Python и Django, таким образом:

[tox]
envlist = py{36,37,38}-django{22,30}

[testenv]
whitelist_externals = poetry
skip_install = true

deps =
    django22: Django==2.2
    django30: Django==3.0

commands =
    poetry install -vvv
    poetry run pytest --cov=my_app tests/
    poetry run coverage report -m

Проблема, с которой я столкнулся (которой не существует в мире pipenv), заключается в том, что оператор poetry install всегда перезаписывает все, что находится в разделе deps, тем, что находится в файле poetry.lock (который будет автоматически сгенерирован, если он не существует) . Это означает, что тестовая матрица никогда не будет тестироваться на Django 2.2 - поскольку каждый виртуальный токсиколог устанавливает Django 3.0 по умолчанию.

Я не понимаю, как это должно работать - следует ли при установке зависимостей с poetry уважать существующую среду, в которую она устанавливается, или нет?

Итак - мой вопрос - как мне настроить многоверсионную тестовую матрицу tox (или travis) с поэзией в качестве менеджера зависимостей?

Мой pyproject.toml определяет версии Python / Django как:

[tool.poetry.dependencies]
python = "^3.6"
django = "^2.2 || ^3.0"

Сгенерированный файл poetry.lock (не зафиксированный) содержит следующую информацию о версии Django:

[[package]]
category = "main"
description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design."
name = "django"
optional = false
python-versions = ">=3.6"
version = "3.0"

ОБНОВЛЕНИЕ: включить вывод чистого tox

Это результат, когда я удаляю файл блокировки и воссоздаю среду tox. Как видите, tox устанавливает Django==2.2 как зависимость в virtualenv, но poetry затем обновляет его до 3.0 при установке.

Мне нужно решение, которое запускает поэтическую установку, соблюдая существующие установки пакетов. т.е. если в pyproject.toml указано Django = "^2.2 || ^3.0", а версия 2.2 уже установлена, закрепите эту версию - не пытайтесь выполнить обновление.

my-app$ tox -r -e py36-django22
py36-django22 recreate: .tox/py36-django22
py36-django22 installdeps: Django==2.2
py36-django22 installed: Django==2.2,my-app==0.1.0,pytz==2019.3,sqlparse==0.3.0
py36-django22 run-test: commands[0] | poetry install -vvv
Using virtualenv: .tox/py36-django22
Updating dependencies
Resolving dependencies...
   1: derived: django (^2.2 || ^3.0)
   ...
PyPI: 10 packages found for django >=2.2,<4.0
   ...
   1: Version solving took 3.330 seconds.
   1: Tried 1 solutions.

Writing lock file

Package operations: 52 installs, 1 update, 0 removals, 3 skipped

  - ...
  - Updating django (2.2 -> 3.0)
  - ...

ОБНОВЛЕНИЕ 2

Следуя инструкциям sinoroc ниже - я обновил файл tox, чтобы удалить skip_dist и включить isolated_build. Это вроде как работает. tox собирает пакет и устанавливает его, но только версию, отличную от разработчика, которая не включает pytest, coverage и множество инструментов линтинга, которые я хотел бы включить позже. то есть инструменты, которые я хочу запустить через tox, указаны как dev-dependencies в поэзии. Здесь есть решение - включить все это в файл tox - но это кажется обреченным на провал - поскольку тогда у меня есть поэзия и tox, оба объявляющие зависимости.

[tool.poetry.dependencies]
python = "^3.6"
django = "^2.2 || ^3.0"

[tool.poetry.dev-dependencies]
pytest = "^3.0"
pytest-cov = "^2.8"
pytest-django = "^3.7"
coverage = "^4.5"
pylint = "^2.4"
pylint-django = "^2.0"
flake8 = "^3.7"
flake8-bandit = "^2.1"
flake8-docstrings = "^1.5"
isort = "^4.3"
mypy = "^0.750.0"
pre-commit = "^1.20"
black = "=19.3b0"

ОБНОВЛЕНИЕ 3: решение

[tox]
isolated_build = True
envlist = lint, mypy, py{36,37,38}-django{22,30}

[travis]
python =
    3.6: lint, mypy, py36
    3.7: lint, mypy, py37
    3.8: lint, mypy, py38

[testenv]
deps =
    pytest
    pytest-cov
    pytest-django
    coverage
    django22: Django==2.2
    django30: Django==3.0

commands =
    django-admin --version
    pytest --cov=my_app tests/

[testenv:lint]
deps =
    pylint
    pylint-django
    flake8
    flake8-bandit
    flake8-docstrings
    isort
    black

commands =
    isort --recursive my_app
    black my_app
    pylint my_app
    flake8 my_app

[testenv:mypy]
deps =
    mypy

commands =
    mypy my_app

person Hugo Rodger-Brown    schedule 17.12.2019    source источник
comment
Я не являюсь пользователем стихов, поэтому не уверен на 100%, так как не могу это проверить, но ... Я бы попробовал подписаться на этот совет, а также удалить skip_install и whitelist_externals и использовать команды напрямую без poetry install или poetry run в commands.   -  person sinoroc    schedule 29.12.2019
comment
Думаю, было бы понятнее переместить решение в отдельный ответ :)   -  person Jacob Pavlock    schedule 03.08.2020


Ответы (1)


Тщательно не тестировал, но я считаю, что что-то вроде этого должно работать:

[tox]
envlist = py{36,37,38}-django{22,30}
isolated_build = True

[testenv]
deps =
    django22: Django==2.2
    django30: Django==3.0
    # plus the dev dependencies
    pytest
    coverage

commands =
    pytest --cov=my_app tests/
    coverage report -m

См. Раздел поэзия на упаковке главу tox документации.


Чтобы избежать повторения зависимостей dev, можно попробовать следующий вариант, основанный на дополнительные функции:

tox.ini

[tox]
# ...

[testenv]
# ...
deps =
    django22: Django==2.2
    django30: Django==3.0
extras =
    test

pyproject.toml

[tool.poetry]
# ...

[tool.poetry.dependencies]
python = "^3.6"
django = "^2.2 || ^3.0"
#
pytest = { version = "^5.2", optional = true }

[tool.poetry.extras]
test = ["pytest"]

[build-system]
# ...

В настоящее время существуют подключаемые модули tox, которые пытаются улучшить интеграцию с проектами на основе поэзии:

person sinoroc    schedule 29.12.2019
comment
Это очень близко - так что спасибо за это (isolated_build - это ключ) - однако он устанавливает только зависимости, не относящиеся к разработчикам, что означает, что он не может найти pytest для фактического запуска тестов. В идеале все зависимости для запуска тестов (pytest, coverage и т. Д.) Должны находиться в dev-dependencies, а не в пакете с приложением. - person Hugo Rodger-Brown; 31.12.2019
comment
Я думаю, что он использовал зависимости разработчиков в моем быстром тесте, но я не помню четко, я не тратил на это много времени. Но да, я понимаю, что зависимости разработчиков теперь находятся как в поэзии, так и в токсикологии. С помощью setuptools я устанавливаю зависимости разработчика как дополнительные и говорю tox установить дополнительные. - person sinoroc; 31.12.2019
comment
@Hugo Я обновил ответ, чтобы показать предложение о том, как избежать повторения зависимостей dev. Он отлично работает для моих вариантов использования, но я вижу, что у него есть недостатки для других вариантов использования ... - person sinoroc; 08.01.2020