mirror of
				https://github.com/enpaul/tox-poetry-installer.git
				synced 2025-11-04 07:46:06 +00:00 
			
		
		
		
	Restructure config options to support tox's native change detection
Remove custom handling of deps option Add locked_deps option Stop modifying the envconfig.deps option at runtime
This commit is contained in:
		@@ -17,10 +17,3 @@ PEP508_VERSION_DELIMITERS: Tuple[str, ...] = ("~=", "==", "!=", ">", "<")
 | 
				
			|||||||
# Prefix all reporter messages should include to indicate that they came from this module in the
 | 
					# Prefix all reporter messages should include to indicate that they came from this module in the
 | 
				
			||||||
# console output.
 | 
					# console output.
 | 
				
			||||||
REPORTER_PREFIX = f"[{__about__.__title__}]:"
 | 
					REPORTER_PREFIX = f"[{__about__.__title__}]:"
 | 
				
			||||||
 | 
					 | 
				
			||||||
# Suffix that indicates an env dependency should be treated as a locked dependency and thus be
 | 
					 | 
				
			||||||
# installed from the lockfile. Will be automatically stripped off of a dependency name during
 | 
					 | 
				
			||||||
# sorting so that the resulting string is just the valid package name. This becomes optional when
 | 
					 | 
				
			||||||
# the "require_locked_deps" option is true for an environment; in that case a bare dependency like
 | 
					 | 
				
			||||||
# 'foo' is treated the same as an explicitly locked dependency like 'foo@poetry'
 | 
					 | 
				
			||||||
MAGIC_SUFFIX_MARKER = "@poetry"
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +1,8 @@
 | 
				
			|||||||
"""Definitions for typehints/containers used by the plugin"""
 | 
					"""Definitions for typehints/containers used by the plugin"""
 | 
				
			||||||
from typing import Dict
 | 
					from typing import Dict
 | 
				
			||||||
from typing import List
 | 
					 | 
				
			||||||
from typing import NamedTuple
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from poetry.core.packages import Package as PoetryPackage
 | 
					from poetry.core.packages import Package as PoetryPackage
 | 
				
			||||||
from tox.config import DepConfig as ToxDepConfig
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Map of package names to the package object
 | 
					# Map of package names to the package object
 | 
				
			||||||
PackageMap = Dict[str, PoetryPackage]
 | 
					PackageMap = Dict[str, PoetryPackage]
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class SortedEnvDeps(NamedTuple):
 | 
					 | 
				
			||||||
    """Container for the two types of environment dependencies"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    unlocked_deps: List[ToxDepConfig]
 | 
					 | 
				
			||||||
    locked_deps: List[ToxDepConfig]
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,3 +26,7 @@ class LockedDepNotFoundError(ToxPoetryInstallerException):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class ExtraNotFoundError(ToxPoetryInstallerException):
 | 
					class ExtraNotFoundError(ToxPoetryInstallerException):
 | 
				
			||||||
    """Project package extra not defined in project's pyproject.toml"""
 | 
					    """Project package extra not defined in project's pyproject.toml"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LockedDepsRequiredError(ToxPoetryInstallerException):
 | 
				
			||||||
 | 
					    """Environment cannot specify unlocked dependencies when locked dependencies are required"""
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,6 +43,12 @@ def tox_addoption(parser: ToxParser):
 | 
				
			|||||||
        help="Require all dependencies in the environment be installed using the Poetry lockfile",
 | 
					        help="Require all dependencies in the environment be installed using the Poetry lockfile",
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    parser.add_testenv_attribute(
 | 
				
			||||||
 | 
					        name="locked_deps",
 | 
				
			||||||
 | 
					        type="line-list",
 | 
				
			||||||
 | 
					        help="List of locked dependencies to install to the environment using the Poetry lockfile",
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@hookimpl
 | 
					@hookimpl
 | 
				
			||||||
def tox_testenv_install_deps(venv: ToxVirtualEnv, action: ToxAction):
 | 
					def tox_testenv_install_deps(venv: ToxVirtualEnv, action: ToxAction):
 | 
				
			||||||
@@ -87,6 +93,11 @@ def tox_testenv_install_deps(venv: ToxVirtualEnv, action: ToxAction):
 | 
				
			|||||||
        for package in poetry.locker.locked_repository(True).packages
 | 
					        for package in poetry.locker.locked_repository(True).packages
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if venv.envconfig.require_locked_deps and venv.envconfig.deps:
 | 
				
			||||||
 | 
					        raise exceptions.LockedDepsRequiredError(
 | 
				
			||||||
 | 
					            f"Unlocked dependencies '{venv.envconfig.deps}' specified for environment '{venv.name}' which requires locked dependencies"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Handle the installation of any locked env dependencies from the lockfile
 | 
					    # Handle the installation of any locked env dependencies from the lockfile
 | 
				
			||||||
    _install_env_dependencies(venv, poetry, package_map)
 | 
					    _install_env_dependencies(venv, poetry, package_map)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -119,12 +130,11 @@ def _install_env_dependencies(
 | 
				
			|||||||
    :param poetry: Poetry object the packages were sourced from
 | 
					    :param poetry: Poetry object the packages were sourced from
 | 
				
			||||||
    :param packages: Mapping of package names to the corresponding package object
 | 
					    :param packages: Mapping of package names to the corresponding package object
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    env_deps = utilities.sort_env_deps(venv)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dependencies: List[PoetryPackage] = []
 | 
					    dependencies: List[PoetryPackage] = []
 | 
				
			||||||
    for dep in env_deps.locked_deps:
 | 
					    for dep in venv.envconfig.locked_deps:
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            dependencies += utilities.find_transients(packages, dep.name.lower())
 | 
					            dependencies += utilities.find_transients(packages, dep.lower())
 | 
				
			||||||
        except exceptions.ToxPoetryInstallerException as err:
 | 
					        except exceptions.ToxPoetryInstallerException as err:
 | 
				
			||||||
            venv.status = "lockfile installation failed"
 | 
					            venv.status = "lockfile installation failed"
 | 
				
			||||||
            reporter.error(f"{constants.REPORTER_PREFIX} {err}")
 | 
					            reporter.error(f"{constants.REPORTER_PREFIX} {err}")
 | 
				
			||||||
@@ -148,14 +158,9 @@ def _install_env_dependencies(
 | 
				
			|||||||
        dependencies = list(set(dev_dependencies + dependencies))
 | 
					        dependencies = list(set(dev_dependencies + dependencies))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    reporter.verbosity1(
 | 
					    reporter.verbosity1(
 | 
				
			||||||
        f"{constants.REPORTER_PREFIX} identified {len(dependencies)} total dependencies from {len(env_deps.locked_deps)} locked env dependencies"
 | 
					        f"{constants.REPORTER_PREFIX} identified {len(dependencies)} total dependencies from {len(venv.envconfig.locked_deps)} locked env dependencies"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    reporter.verbosity1(
 | 
					 | 
				
			||||||
        f"{constants.REPORTER_PREFIX} updating env config with {len(env_deps.unlocked_deps)} unlocked env dependencies for installation using the default backend"
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    venv.envconfig.deps = env_deps.unlocked_deps
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    reporter.verbosity0(
 | 
					    reporter.verbosity0(
 | 
				
			||||||
        f"{constants.REPORTER_PREFIX} ({venv.name}) installing {len(dependencies)} env dependencies from lockfile"
 | 
					        f"{constants.REPORTER_PREFIX} ({venv.name}) installing {len(dependencies)} env dependencies from lockfile"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,58 +15,6 @@ from tox.venv import VirtualEnv as ToxVirtualEnv
 | 
				
			|||||||
from tox_poetry_installer import constants
 | 
					from tox_poetry_installer import constants
 | 
				
			||||||
from tox_poetry_installer import exceptions
 | 
					from tox_poetry_installer import exceptions
 | 
				
			||||||
from tox_poetry_installer.datatypes import PackageMap
 | 
					from tox_poetry_installer.datatypes import PackageMap
 | 
				
			||||||
from tox_poetry_installer.datatypes import SortedEnvDeps
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def sort_env_deps(venv: ToxVirtualEnv) -> SortedEnvDeps:
 | 
					 | 
				
			||||||
    """Sorts the environment dependencies by lock status
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Lock status determines whether a given environment dependency will be installed from the
 | 
					 | 
				
			||||||
    lockfile using the Poetry backend, or whether this plugin will skip it and allow it to be
 | 
					 | 
				
			||||||
    installed using the default pip-based backend (an unlocked dependency).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .. note:: A locked dependency must follow a required format. To avoid reinventing the wheel
 | 
					 | 
				
			||||||
              (no pun intended) this module does not have any infrastructure for parsing PEP-508
 | 
					 | 
				
			||||||
              version specifiers, and so requires locked dependencies to be specified with no
 | 
					 | 
				
			||||||
              version (the installed version being taken from the lockfile). If a dependency is
 | 
					 | 
				
			||||||
              specified as locked and its name is also a PEP-508 string then an error will be
 | 
					 | 
				
			||||||
              raised.
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    reporter.verbosity1(
 | 
					 | 
				
			||||||
        f"{constants.REPORTER_PREFIX} sorting {len(venv.envconfig.deps)} env dependencies by lock requirement"
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    unlocked_deps = []
 | 
					 | 
				
			||||||
    locked_deps = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for dep in venv.envconfig.deps:
 | 
					 | 
				
			||||||
        if venv.envconfig.require_locked_deps:
 | 
					 | 
				
			||||||
            reporter.verbosity1(
 | 
					 | 
				
			||||||
                f"{constants.REPORTER_PREFIX} lock required for env, treating '{dep.name}' as locked env dependency"
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            dep.name = dep.name.replace(constants.MAGIC_SUFFIX_MARKER, "")
 | 
					 | 
				
			||||||
            locked_deps.append(dep)
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            if dep.name.endswith(constants.MAGIC_SUFFIX_MARKER):
 | 
					 | 
				
			||||||
                reporter.verbosity1(
 | 
					 | 
				
			||||||
                    f"{constants.REPORTER_PREFIX} specification includes marker '{constants.MAGIC_SUFFIX_MARKER}', treating '{dep.name}' as locked env dependency"
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
                dep.name = dep.name.replace(constants.MAGIC_SUFFIX_MARKER, "")
 | 
					 | 
				
			||||||
                locked_deps.append(dep)
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                reporter.verbosity1(
 | 
					 | 
				
			||||||
                    f"{constants.REPORTER_PREFIX} specification does not include marker '{constants.MAGIC_SUFFIX_MARKER}', treating '{dep.name}' as unlocked env dependency"
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
                unlocked_deps.append(dep)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    reporter.verbosity1(
 | 
					 | 
				
			||||||
        f"{constants.REPORTER_PREFIX} identified {len(locked_deps)} locked env dependencies: {[item.name for item in locked_deps]}"
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    reporter.verbosity1(
 | 
					 | 
				
			||||||
        f"{constants.REPORTER_PREFIX} identified {len(unlocked_deps)} unlocked env dependencies: {[item.name for item in unlocked_deps]}"
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return SortedEnvDeps(locked_deps=locked_deps, unlocked_deps=unlocked_deps)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def install_to_venv(
 | 
					def install_to_venv(
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user