¿Cómo puedo hacer que tox y poesía funcionen juntos para soportar la prueba de múltiples versiones de una dependencia de Python?

17

Estoy cambiando un proyecto que utiliza actualmente pipenva poetryuna prueba para ver cuáles son las diferencias. El proyecto es una aplicación Django simple y redistribuible. Es compatible con Python 3.6-8 y Django 2.2 y 3.0. Tengo un tox.iniarchivo que cubre todas las combinaciones de Python y Django así:

[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

El problema que tengo (que no existe en el pipenvmundo) es que la poetry installdeclaración siempre sobrescribirá lo que esté en la depssección con lo que esté en el poetry.lockarchivo (que se generará automáticamente si no existe). Esto significa que la matriz de prueba nunca probará contra Django 2.2, ya que cada virtualenv tox tiene Django 3.0 instalado por defecto.

No entiendo cómo se supone que funciona esto: ¿la instalación de dependencias debe poetryrespetar el entorno existente en el que se está instalando, o no?

Entonces, mi pregunta es: ¿cómo configuro una matriz de prueba tox (o travis) de múltiples versiones, con la poesía como administrador de dependencias?

My pyproject.tomldefine las versiones de Python / Django como:

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

El poetry.lockarchivo generado (no confirmado) tiene esta información de versión de 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"

ACTUALIZACIÓN: incluye salida de toxinas limpia

Este es el resultado cuando elimino el archivo de bloqueo y recreo el entorno tóxico. Como puede ver, tox se instala Django==2.2como una dependencia en virtualenv, pero poetryluego lo actualiza 3.0cuando se instala.

Necesito una solución que ejecute la instalación de poesía, respetando las instalaciones de paquetes existentes. es decir, si pyproject.tomlestados Django = "^2.2 || ^3.0", y 2.2 ya está instalado, entonces ancle a esa versión - no intente actualizar.

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)
  - ...

ACTUALIZACIÓN 2

Siguiendo las instrucciones de sinoroc a continuación, he actualizado el archivo tox para eliminar skip_diste incluir isolated_build. Esto funciona, más o menos. tox crea el paquete y lo instala, pero solo la versión que no es de desarrollo, que no incluye pytest, coveragey una gran cantidad de herramientas de linting que me gustaría incluir en un momento posterior. es decir, las herramientas que quiero ejecutar con tox se especifican como dev-dependencies en poesía. Hay una solución aquí, para incluir todos estos dentro del archivo tox, pero eso parece contraproducente, ya que entonces tengo poesía y tox que declaran dependencias.

[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"

ACTUALIZACIÓN 3: solución

[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
2
  • Yo mismo no soy un usuario de poesía , así que no estoy 100% seguro porque no puedo probarlo, pero ... intentaría seguir este consejo , así como eliminar skip_instally whitelist_externals, y usar los comandos directamente sin poetry installo poetry rundentro commands.
    sinoroc
    29/12/19 a las 18:49
  • Creo que sería más claro mover la solución a su propia respuesta :) 3 ago.20 a las 13:40
13
+100

No lo he probado a fondo, pero creo que algo como esto debería funcionar:

[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

Consulte la sección " poesía " en el capítulo "empaquetado" de la documentación de toxinas .


Con el fin de evitar la repetición de las dev dependencias, se podría tratar de la siguiente variación en base al extras función :

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]
# ...

Hoy en día existen complementos tóxicos que intentan lograr una mejor integración con proyectos basados ​​en poesía :

3
  • 1
    Esto está muy cerca, así que gracias por eso ( isolated_buildes la clave), sin embargo, solo está instalando las dependencias que no son de desarrollo, lo que significa que no puede encontrar pytestpara ejecutar las pruebas. Idealmente, todas las dependencias para las pruebas de funcionamiento ( pytest, coverage, etc.) estarían en dev-dependencias y no empaquetado con la aplicación. 31/12/19 a las 9:58
  • Creo que usó las dependencias de desarrollo en mi prueba rápida, pero no lo recuerdo con claridad, no le dediqué mucho tiempo. Pero sí, entiendo que las dependencias de desarrollo ahora están tanto en poesía como en tox. Con setuptools configuro las dependencias de desarrollo como extras y le digo a tox que instale los extras.
    sinoroc
    31 dic 2019 a las 18:03
  • @Hugo He actualizado la respuesta a mostrar una sugerencia de cómo evitar la repetición de las dev dependencias. Funciona perfectamente para mis casos de uso, pero puedo ver cómo tiene sus inconvenientes para otros casos de uso ...
    sinoroc
    8 de enero de 2020 a las 8:59