General refactoring

Fix some pseudo-hungarian type notation
Fix out of date docstrings
Fix arbitrary argument ordering in function signatures
Remove interchangable usage of dep/dependency variable naming
Remove interchangable usage of packages/package_map for same data
This commit is contained in:
Ethan Paul 2021-02-09 23:53:56 -05:00
parent b8ea98b3ad
commit 08a6962d3f
No known key found for this signature in database
GPG Key ID: C5F5542B54A4D9C6
2 changed files with 95 additions and 102 deletions

View File

@ -4,11 +4,9 @@ All implementations of tox hooks are defined here, as well as any single-use hel
specifically related to implementing the hooks (to keep the size/readability of the hook functions specifically related to implementing the hooks (to keep the size/readability of the hook functions
themselves manageable). themselves manageable).
""" """
from typing import List
from typing import Optional from typing import Optional
import tox import tox
from poetry.core.packages import Package as PoetryPackage
from tox.action import Action as ToxAction from tox.action import Action as ToxAction
from tox.config import Parser as ToxParser from tox.config import Parser as ToxParser
from tox.venv import VirtualEnv as ToxVirtualEnv from tox.venv import VirtualEnv as ToxVirtualEnv
@ -92,13 +90,13 @@ def tox_testenv_install_deps(venv: ToxVirtualEnv, action: ToxAction) -> Optional
f"Unlocked dependencies '{venv.envconfig.deps}' specified for environment '{venv.name}' which requires locked dependencies" f"Unlocked dependencies '{venv.envconfig.deps}' specified for environment '{venv.name}' which requires locked dependencies"
) )
package_map: PackageMap = { packages: PackageMap = {
package.name: package package.name: package
for package in poetry.locker.locked_repository(True).packages for package in poetry.locker.locked_repository(True).packages
} }
if venv.envconfig.install_dev_deps: if venv.envconfig.install_dev_deps:
dev_deps = utilities.find_dev_dependencies(poetry, package_map) dev_deps = utilities.find_dev_deps(packages, poetry)
tox.reporter.verbosity1( tox.reporter.verbosity1(
f"{constants.REPORTER_PREFIX} Identified {len(dev_deps)} development dependencies to install to env" f"{constants.REPORTER_PREFIX} Identified {len(dev_deps)} development dependencies to install to env"
) )
@ -108,15 +106,17 @@ def tox_testenv_install_deps(venv: ToxVirtualEnv, action: ToxAction) -> Optional
f"{constants.REPORTER_PREFIX} Env does not install development dependencies, skipping" f"{constants.REPORTER_PREFIX} Env does not install development dependencies, skipping"
) )
env_deps = utilities.find_env_dependencies(venv, poetry, package_map) env_deps = utilities.find_additional_deps(
packages, poetry, venv.envconfig.locked_deps
)
tox.reporter.verbosity1( tox.reporter.verbosity1(
f"{constants.REPORTER_PREFIX} Identified {len(env_deps)} environment dependencies to install to env" f"{constants.REPORTER_PREFIX} Identified {len(env_deps)} environment dependencies to install to env"
) )
if not venv.envconfig.skip_install and not venv.envconfig.config.skipsdist: if not venv.envconfig.skip_install and not venv.envconfig.config.skipsdist:
project_deps: List[PoetryPackage] = utilities.find_project_dependencies( project_deps = utilities.find_project_deps(
venv, poetry, package_map packages, poetry, venv.envconfig.extras
) )
else: else:
project_deps = [] project_deps = []

View File

@ -21,20 +21,55 @@ if typing.TYPE_CHECKING:
from tox_poetry_installer import _poetry from tox_poetry_installer import _poetry
def check_preconditions(venv: ToxVirtualEnv, action: ToxAction) -> "_poetry.Poetry":
"""Check that the local project environment meets expectations"""
# Skip running the plugin for the provisioning environment. The provisioned environment,
# for alternative Tox versions and/or the ``requires`` meta dependencies is specially
# handled by Tox and is out of scope for this plugin. Since one of the ways to install this
# plugin in the first place is via the Tox provisioning environment, it quickly becomes a
# chicken-and-egg problem.
if action.name == venv.envconfig.config.provision_tox_env:
raise exceptions.SkipEnvironment(
f"Skipping Tox provisioning env '{action.name}'"
)
# Skip running the plugin for the packaging environment. PEP-517 front ends can handle
# that better than we can, so let them do their thing. More to the point: if you're having
# problems in the packaging env that this plugin would solve, god help you.
if action.name == venv.envconfig.config.isolated_build_env:
raise exceptions.SkipEnvironment(
f"Skipping isolated packaging build env '{action.name}'"
)
from tox_poetry_installer import _poetry
try:
return _poetry.Factory().create_poetry(venv.envconfig.config.toxinidir)
# Support running the plugin when the current tox project does not use Poetry for its
# environment/dependency management.
#
# ``RuntimeError`` is dangerous to blindly catch because it can be (and in Poetry's case,
# is) raised in many different places for different purposes.
except RuntimeError:
raise exceptions.SkipEnvironment(
"Project does not use Poetry for env management, skipping installation of locked dependencies"
) from None
def identify_transients( def identify_transients(
packages: PackageMap, dependency_name: str, allow_missing: Sequence[str] = () packages: PackageMap, dep_name: str, allow_missing: Sequence[str] = ()
) -> List[PoetryPackage]: ) -> List[PoetryPackage]:
"""Using a poetry object identify all dependencies of a specific dependency """Using a pool of packages, identify all transient dependencies of a given package name
:param packages: All packages from the lockfile to use for identifying dependency relationships. :param packages: All packages from the lockfile to use for identifying dependency relationships.
:param dependency_name: Bare name (without version) of the dependency to fetch the transient :param dep_name: Bare name (without version) of the dependency to fetch the transient
dependencies of. dependencies of.
:param allow_missing: Sequence of package names to allow to be missing from the lockfile. Any :param allow_missing: Sequence of package names to allow to be missing from the lockfile. Any
packages that are not found in the lockfile but their name appears in this packages that are not found in the lockfile but their name appears in this
list will be silently skipped from installation. list will be silently skipped from installation.
:returns: List of packages that need to be installed for the requested dependency. :returns: List of packages that need to be installed for the requested dependency.
.. note:: The package corresponding to the dependency named by ``dependency_name`` is included .. note:: The package corresponding to the dependency named by ``dep_name`` is included
in the list of returned packages. in the list of returned packages.
""" """
from tox_poetry_installer import _poetry from tox_poetry_installer import _poetry
@ -90,98 +125,60 @@ def identify_transients(
transients.append(package) transients.append(package)
try: try:
find_deps_of_deps(packages[dependency_name].name) find_deps_of_deps(packages[dep_name].name)
except KeyError: except KeyError:
if dependency_name in _poetry.Provider.UNSAFE_PACKAGES: if dep_name in _poetry.Provider.UNSAFE_PACKAGES:
tox.reporter.warning( tox.reporter.warning(
f"{constants.REPORTER_PREFIX} Installing package '{dependency_name}' using Poetry is not supported and will be skipped" f"{constants.REPORTER_PREFIX} Installing package '{dep_name}' using Poetry is not supported and will be skipped"
) )
return [] return []
if any( if any(
delimiter in dependency_name delimiter in dep_name for delimiter in constants.PEP508_VERSION_DELIMITERS
for delimiter in constants.PEP508_VERSION_DELIMITERS
): ):
raise exceptions.LockedDepVersionConflictError( raise exceptions.LockedDepVersionConflictError(
f"Locked dependency '{dependency_name}' cannot include version specifier" f"Locked dependency '{dep_name}' cannot include version specifier"
) from None ) from None
raise exceptions.LockedDepNotFoundError( raise exceptions.LockedDepNotFoundError(
f"No version of locked dependency '{dependency_name}' found in the project lockfile" f"No version of locked dependency '{dep_name}' found in the project lockfile"
) from None ) from None
return transients return transients
def check_preconditions(venv: ToxVirtualEnv, action: ToxAction) -> "_poetry.Poetry": def find_project_deps(
"""Check that the local project environment meets expectations""" packages: PackageMap, poetry: "_poetry.Poetry", extras: Sequence[str] = ()
# Skip running the plugin for the provisioning environment. The provisioned environment,
# for alternative Tox versions and/or the ``requires`` meta dependencies is specially
# handled by Tox and is out of scope for this plugin. Since one of the ways to install this
# plugin in the first place is via the Tox provisioning environment, it quickly becomes a
# chicken-and-egg problem.
if action.name == venv.envconfig.config.provision_tox_env:
raise exceptions.SkipEnvironment(
f"Skipping Tox provisioning env '{action.name}'"
)
# Skip running the plugin for the packaging environment. PEP-517 front ends can handle
# that better than we can, so let them do their thing. More to the point: if you're having
# problems in the packaging env that this plugin would solve, god help you.
if action.name == venv.envconfig.config.isolated_build_env:
raise exceptions.SkipEnvironment(
f"Skipping isolated packaging build env '{action.name}'"
)
from tox_poetry_installer import _poetry
try:
return _poetry.Factory().create_poetry(venv.envconfig.config.toxinidir)
# Support running the plugin when the current tox project does not use Poetry for its
# environment/dependency management.
#
# ``RuntimeError`` is dangerous to blindly catch because it can be (and in Poetry's case,
# is) raised in many different places for different purposes.
except RuntimeError:
raise exceptions.SkipEnvironment(
"Project does not use Poetry for env management, skipping installation of locked dependencies"
) from None
def find_project_dependencies(
venv: ToxVirtualEnv, poetry: "_poetry.Poetry", packages: PackageMap
) -> List[PoetryPackage]: ) -> List[PoetryPackage]:
"""Find the root package dependencies """Find the root project dependencies
Recursively identify the root package dependencies Recursively identify the dependencies of the root project package
:param venv: Tox virtual environment to install the packages to :param packages: Mapping of all locked package names to their corresponding package object
:param poetry: Poetry object the packages were sourced from :param poetry: Poetry object for the current project
:param packages: Mapping of package names to the corresponding package object :param extras: Sequence of extra names to include the dependencies of
""" """
base_dependencies: List[PoetryPackage] = [ base_deps: List[PoetryPackage] = [
packages[item.name] packages[item.name]
for item in poetry.package.requires for item in poetry.package.requires
if not item.is_optional() if not item.is_optional()
] ]
extra_dependencies: List[PoetryPackage] = [] extra_deps: List[PoetryPackage] = []
for extra in venv.envconfig.extras: for extra in extras:
tox.reporter.verbosity1( tox.reporter.verbosity1(
f"{constants.REPORTER_PREFIX} Processing project extra '{extra}'" f"{constants.REPORTER_PREFIX} Processing project extra '{extra}'"
) )
try: try:
extra_dependencies += [ extra_deps += [packages[item.name] for item in poetry.package.extras[extra]]
packages[item.name] for item in poetry.package.extras[extra]
]
except KeyError: except KeyError:
raise exceptions.ExtraNotFoundError( raise exceptions.ExtraNotFoundError(
f"Environment '{venv.name}' specifies project extra '{extra}' which was not found in the lockfile" f"Environment specifies project extra '{extra}' which was not found in the lockfile"
) from None ) from None
dependencies: List[PoetryPackage] = [] dependencies: List[PoetryPackage] = []
for dep in base_dependencies + extra_dependencies: for dep in base_deps + extra_deps:
dependencies += identify_transients( dependencies += identify_transients(
packages, dep.name.lower(), allow_missing=[poetry.package.name] packages, dep.name.lower(), allow_missing=[poetry.package.name]
) )
@ -189,43 +186,39 @@ def find_project_dependencies(
return dependencies return dependencies
def find_dev_dependencies( def find_additional_deps(
poetry: "_poetry.Poetry", packages: PackageMap packages: PackageMap, poetry: "_poetry.Poetry", dep_names: Sequence[str]
) -> List[PoetryPackage]:
"""Find additional dependencies
Recursively identify the dependencies of an arbitrary list of package names
:param packages: Mapping of all locked package names to their corresponding package object
:param poetry: Poetry object for the current project
:param dep_names: Sequence of additional dependency names to recursively find the transient
dependencies for
"""
deps: List[PoetryPackage] = []
for dep_name in dep_names:
deps += identify_transients(
packages, dep_name.lower(), allow_missing=[poetry.package.name]
)
return deps
def find_dev_deps(
packages: PackageMap, poetry: "_poetry.Poetry"
) -> List[PoetryPackage]: ) -> List[PoetryPackage]:
"""Find the dev dependencies """Find the dev dependencies
Recursively identify the Poetry dev dependencies Recursively identify the Poetry dev dependencies
:param venv: Tox virtual environment to install the packages to :param packages: Mapping of all locked package names to their corresponding package object
:param poetry: Poetry object the packages were sourced from :param poetry: Poetry object for the current project
:param packages: Mapping of package names to the corresponding package object
""" """
dependencies: List[PoetryPackage] = [] return find_additional_deps(
for dep_name in ( packages,
poetry.pyproject.data["tool"]["poetry"].get("dev-dependencies", {}).keys() poetry,
): poetry.pyproject.data["tool"]["poetry"].get("dev-dependencies", {}).keys(),
dependencies += identify_transients( )
packages, dep_name, allow_missing=[poetry.package.name]
)
return dependencies
def find_env_dependencies(
venv: ToxVirtualEnv, poetry: "_poetry.Poetry", packages: PackageMap
) -> List[PoetryPackage]:
"""Find the environment dependencies
Recursively identify the dependencies to install for the current environment
:param venv: Tox virtual environment to install the packages to
:param poetry: Poetry object the packages were sourced from
:param packages: Mapping of package names to the corresponding package object
"""
dependencies: List[PoetryPackage] = []
for dep in venv.envconfig.locked_deps:
dependencies += identify_transients(
packages, dep.lower(), allow_missing=[poetry.package.name]
)
return dependencies