7 Commits
0.1.2 ... 0.1.3

Author SHA1 Message Date
66f2c3c768 Bump patch version 2020-09-25 01:04:12 -04:00
fd2637113f Remove excessive bandit output from security checks 2020-09-25 01:03:31 -04:00
b10e796ca1 Standardize log message usage of 'dev-package' and 'env' terminology 2020-09-25 01:02:30 -04:00
5dfbca4ff6 Update docs to indicate dev package installation support 2020-09-25 00:56:21 -04:00
db09acd8fe Fix install of dev package dependencies from lockfile
Override default pip behavior by preemptively installing dev package dependencies
Keep support for tox default skip_install config flag
2020-09-25 00:54:45 -04:00
b339e3d6d9 Update poetry requirement to mitigate coming breaking API changes
Poetry 1.1 is due any day and when it does much of the functionality this
  module uses will be moved to poetry-core. Until this module is updated
  to use poetry-core 1.1 will be a breaking change
2020-09-25 00:38:20 -04:00
9db6838d94 Update logging calls to use the tox reporter 2020-09-24 23:56:36 -04:00
5 changed files with 66 additions and 30 deletions

View File

@@ -255,7 +255,7 @@ usage in production systems.
### Path to Beta
- [ ] Verify that primary package dependencies (from the `.package` env) are installed
- [X] Verify that primary package dependencies (from the `.package` env) are installed
correctly using the Poetry backend.
- [ ] Support the [`extras`](https://tox.readthedocs.io/en/latest/config.html#conf-extras)
Tox configuration option

11
poetry.lock generated
View File

@@ -364,7 +364,7 @@ marker = "python_version >= \"3.6.1\" and python_version < \"4.0.0\""
name = "identify"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
version = "1.5.4"
version = "1.5.5"
[package.extras]
license = ["editdistance"]
@@ -787,6 +787,7 @@ wcwidth = "*"
[[package]]
category = "main"
description = "Run a subprocess in a pseudo terminal"
marker = "python_version >= \"3.7\" and python_version < \"4.0\" and sys_platform != \"win32\""
name = "ptyprocess"
optional = false
python-versions = "*"
@@ -1171,7 +1172,7 @@ version = "1.12.1"
[[package]]
category = "main"
description = "Backport of pathlib-compatible object wrapper for zip files"
marker = "python_version >= \"3.5\" and python_version < \"3.8\" or python_version < \"3.8\" or python_version >= \"3.6.1\" and python_version < \"3.8\" or python_version >= \"3.5\" and python_version < \"3.8\" and (python_version >= \"3.5\" and python_version < \"3.8\" or python_version < \"3.8\" or python_version >= \"3.6.1\" and python_version < \"3.8\") or python_version >= \"3.6.1\" and python_version < \"3.7\" or python_version >= \"3.6.1\" and python_version < \"3.7\" and (python_version >= \"3.6.1\" and python_version < \"3.7\" or python_version < \"3.7\") or python_version >= \"3.6.1\" and python_version < \"3.8\" and (python_version >= \"3.5\" and python_version < \"3.8\" or python_version < \"3.8\" or python_version >= \"3.6.1\" and python_version < \"3.8\")"
marker = "python_version >= \"3.5\" and python_version < \"3.8\" or python_version < \"3.8\" or python_version >= \"3.6.1\" and python_version < \"3.7\" or python_version >= \"3.6.1\" and python_version < \"3.8\""
name = "zipp"
optional = false
python-versions = ">=3.6"
@@ -1182,7 +1183,7 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
[metadata]
content-hash = "e4a4d7c9fd7fa351a513ea4ab590e227f7c6be042a4a8a3156509f7f5df7a523"
content-hash = "8df0839a479a0483c969368ef8f61f553773f27bdc0a569603c7141b6c360680"
python-versions = "^3.6"
[metadata.files]
@@ -1392,8 +1393,8 @@ html5lib = [
{file = "html5lib-1.1.tar.gz", hash = "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f"},
]
identify = [
{file = "identify-1.5.4-py2.py3-none-any.whl", hash = "sha256:d7da7de6825568daa4449858ce328ecc0e1ada2554d972a6f4f90e736aaf499a"},
{file = "identify-1.5.4.tar.gz", hash = "sha256:e4db4796b3b0cf4f9cb921da51430abffff2d4ba7d7c521184ed5252bd90d461"},
{file = "identify-1.5.5-py2.py3-none-any.whl", hash = "sha256:da683bfb7669fa749fc7731f378229e2dbf29a1d1337cbde04106f02236eb29d"},
{file = "identify-1.5.5.tar.gz", hash = "sha256:7c22c384a2c9b32c5cc891d13f923f6b2653aa83e2d75d8f79be240d6c86c4f4"},
]
idna = [
{file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"},

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "tox-poetry-installer"
version = "0.1.2"
version = "0.1.3"
license = "MIT"
authors = ["Ethan Paul <24588726+enpaul@users.noreply.github.com>"]
description = "Tox plugin to install Tox environment dependencies using the Poetry backend and lockfile"
@@ -27,7 +27,7 @@ poetry_installer = "tox_poetry_installer"
[tool.poetry.dependencies]
python = "^3.6"
poetry = "^1.0.0"
poetry = ">=1.0.0, <1.1.0"
tox = "^2.3.0 || ^3.0.0"
[tool.poetry.dev-dependencies]

View File

@@ -57,6 +57,6 @@ deps =
allowlist_externals =
bash
commands =
bandit --recursive {toxinidir}/tox_poetry_installer.py
bash -c "bandit --skip B101 {toxinidir}/tests/*.py"
bandit --quiet {toxinidir}/tox_poetry_installer.py
bash -c "bandit --quiet --skip B101 {toxinidir}/tests/*.py"
bash -c "poetry export --format requirements.txt --without-hashes --dev | safety check --stdin --bare"

View File

@@ -5,11 +5,11 @@ installation functionality to install dependencies from the Poetry lockfile for
does this by using ``poetry`` to read in the lockfile, identify necessary dependencies, and then
use Poetry's ``PipInstaller`` class to install those packages into the Tox environment.
"""
import logging
from pathlib import Path
from typing import Dict
from typing import List
from typing import Optional
from typing import Sequence
from typing import Tuple
from poetry.factory import Factory as PoetryFactory
@@ -20,13 +20,14 @@ from poetry.packages import Package as PoetryPackage
from poetry.puzzle.provider import Provider as PoetryProvider
from poetry.utils.env import VirtualEnv as PoetryVirtualEnv
from tox import hookimpl
from tox import reporter
from tox.action import Action as ToxAction
from tox.venv import VirtualEnv as ToxVirtualEnv
__title__ = "tox-poetry-installer"
__summary__ = "Tox plugin to install Tox environment dependencies using the Poetry backend and lockfile"
__version__ = "0.1.2"
__version__ = "0.1.3"
__url__ = "https://github.com/enpaul/tox-poetry-installer/"
__license__ = "MIT"
__authors__ = ["Ethan Paul <24588726+enpaul@users.noreply.github.com>"]
@@ -34,6 +35,8 @@ __authors__ = ["Ethan Paul <24588726+enpaul@users.noreply.github.com>"]
_PEP508_VERSION_DELIMITERS: Tuple[str, ...] = ("~=", "==", "!=", ">", "<")
_REPORTER_PREFIX = f"[{__title__}]:"
class ToxPoetryInstallerException(Exception):
"""Error while installing locked dependencies to the test environment"""
@@ -43,9 +46,24 @@ class NoLockedDependencyError(ToxPoetryInstallerException):
"""Cannot install a package that is not in the lockfile"""
def _make_poetry(venv: ToxVirtualEnv) -> Poetry:
"""Helper to make a poetry object from a toxenv"""
return PoetryFactory().create_poetry(venv.envconfig.config.toxinidir)
def _install_to_venv(
poetry: Poetry, venv: ToxVirtualEnv, packages: Sequence[PoetryPackage]
):
"""Install a bunch of packages to a virtualenv
:param poetry: Poetry object the packages were sourced from
:param venv: Tox virtual environment to install the packages to
:param packages: List of packages to install to the virtual environment
"""
installer = PoetryPipInstaller(
env=PoetryVirtualEnv(path=Path(venv.envconfig.envdir)),
io=PoetryNullIO(),
pool=poetry.pool,
)
for dependency in packages:
reporter.verbosity1(f"{_REPORTER_PREFIX} installing {dependency}")
installer.install(dependency)
def _find_locked_dependencies(
@@ -72,6 +90,9 @@ def _find_locked_dependencies(
def find_transients(name: str) -> List[PoetryPackage]:
if name in PoetryProvider.UNSAFE_PACKAGES:
reporter.warning(
f"{_REPORTER_PREFIX} installing '{name}' using Poetry is not supported; skipping"
)
return []
transients = [packages[name]]
for dep in packages[name].requires:
@@ -109,34 +130,48 @@ def tox_testenv_install_deps(
:param action: Tox action object
"""
logger = logging.getLogger(__name__)
if action.name == venv.envconfig.config.isolated_build_env:
logger.debug(
f"Environment {action.name} is isolated build environment; skipping Poetry-based dependency installation"
reporter.verbosity1(
f"{_REPORTER_PREFIX} skipping isolated build env '{action.name}'"
)
return None
poetry = _make_poetry(venv)
poetry = PoetryFactory().create_poetry(venv.envconfig.config.toxinidir)
logger.debug(f"Loaded project pyproject.toml from {poetry.file}")
reporter.verbosity1(
f"{_REPORTER_PREFIX} loaded project pyproject.toml from {poetry.file}"
)
dependencies: List[PoetryPackage] = []
for env_dependency in venv.envconfig.deps:
dependencies += _find_locked_dependencies(poetry, env_dependency.name)
logger.debug(
f"Identified {len(dependencies)} dependencies for environment {action.name}"
reporter.verbosity1(
f"{_REPORTER_PREFIX} identified {len(dependencies)} actual dependencies from {len(venv.envconfig.deps)} specified env dependencies"
)
installer = PoetryPipInstaller(
env=PoetryVirtualEnv(path=Path(venv.envconfig.envdir)),
io=PoetryNullIO(),
pool=poetry.pool,
reporter.verbosity0(
f"{_REPORTER_PREFIX} ({venv.name}) installing {len(dependencies)} env dependencies from lockfile"
)
_install_to_venv(poetry, venv, dependencies)
for dependency in dependencies:
logger.info(f"Installing environment dependency: {dependency}")
installer.install(dependency)
if not venv.envconfig.skip_install:
reporter.verbosity1(
f"{_REPORTER_PREFIX} env specifies 'skip_install = false', performing installation of dev-package dependencies"
)
primary_dependencies = poetry.locker.locked_repository(False).packages
reporter.verbosity1(
f"{_REPORTER_PREFIX} identified {len(primary_dependencies)} dependencies of dev-package"
)
reporter.verbosity0(
f"{_REPORTER_PREFIX} ({venv.name}) installing {len(primary_dependencies)} dev-package dependencies from lockfile"
)
_install_to_venv(poetry, venv, primary_dependencies)
else:
reporter.verbosity1(
f"{_REPORTER_PREFIX} env specifies 'skip_install = true', skipping installation of dev-package package"
)
return dependencies