tox-poetry-installer/tox_poetry_installer.py

79 lines
2.4 KiB
Python
Raw Normal View History

from pathlib import Path
import logging
from typing import Dict, List
from poetry.factory import Factory
from poetry.factory import Poetry
from poetry.packages import Package
from poetry.installation.pip_installer import PipInstaller
from poetry.io.null_io import NullIO
from poetry.utils.env import VirtualEnv
from tox.action import Action as ToxAction
from tox.venv import VirtualEnv as ToxVirtualEnv
from tox import hookimpl
__title__ = "tox-poetry-installer"
__summary__ = "Tox plugin to install Tox environment dependencies using the Poetry backend and lockfile"
__version__ = "0.1.0"
__url__ = "https://github.com/enpaul/tox-poetry-installer/"
__license__ = "MIT"
__authors__ = ["Ethan Paul <e@enp.one>"]
def _make_poetry(venv: ToxVirtualEnv) -> Poetry:
return Factory().create_poetry(venv.envconfig.config.toxinidir)
def _find_locked_dependencies(poetry: Poetry, dependency_name: str) -> List[Package]:
packages: Dict[str, Package] = {
package.name: package
for package in poetry.locker.locked_repository(True).packages
}
try:
top_level = packages[dependency_name]
except KeyError:
raise
def find_transients(name: str) -> List[Package]:
transients = [packages[name]]
for dep in packages[name].requires:
transients += find_transients(dep.name)
return transients
return find_transients(top_level.name)
@hookimpl
def tox_testenv_install_deps(venv: ToxVirtualEnv, action: ToxAction):
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")
return None
poetry = _make_poetry(venv)
logger.debug(f"Loaded project pyproject.toml from {poetry.file}")
dependencies = []
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}")
installer = PipInstaller(
env=VirtualEnv(path=Path(venv.envconfig.envdir)),
io=NullIO(),
pool=poetry.pool
)
for dependency in dependencies:
logger.info(f"Installing environment dependency: {dependency}")
installer.install(dependency)
return dependencies