Source code for edgetest.lib
"""Default virtual environment hook."""
import logging
import platform
from pathlib import Path
import click
import pluggy
from uv import find_uv_bin
from edgetest.utils import _run_command
LOG = logging.getLogger(__name__)
hookimpl = pluggy.HookimplMarker("edgetest")
[docs]
@hookimpl(trylast=True)
def path_to_python(basedir: str, envname: str) -> str:
"""Return the path to the python executable."""
if platform.system() == "Windows":
return str(Path(basedir) / envname / "Scripts" / "python.exe")
else:
return str(Path(basedir) / envname / "bin" / "python")
[docs]
@hookimpl(trylast=True)
def create_environment(basedir: str, envname: str, conf: dict):
"""Create the virtual environment for testing.
Creates an environment using ``uv``.
Parameters
----------
basedir : str
The base directory location for the environment.
envname : str
The name of the virtual environment.
conf : dict
Ignored.
Raises
------
RuntimeError
Error raised if the environment cannot be created.
"""
try:
uv_ = find_uv_bin()
callargs_ = [uv_, "venv", str(Path(basedir, envname))]
if (py_version := conf.get("python_version")) is not None:
callargs_.append(f"--python={py_version}")
if Path(basedir, envname).is_dir():
callargs_.append("--clear")
_run_command(*callargs_)
except Exception as err:
raise RuntimeError(f"Unable to create {envname} in {basedir}") from err
[docs]
@hookimpl(trylast=True)
def run_update(basedir: str, envname: str, upgrade: list, conf: dict):
"""Update packages from upgrade list.
Parameters
----------
basedir : str
The base directory location for the environment.
envname : str
The name of the virtual environment.
upgrade : list
The list of packages to upgrade
conf : dict
The configuration dictionary. The configuration is parsed for ``exclude_newer``,
which maps to the parameter of the same name in ``uv``.
Raises
------
RuntimeError
Error raised if the packages cannot be updated.
"""
python_path = path_to_python(basedir, envname)
uv_ = find_uv_bin()
callargs_ = [
uv_,
"pip",
"install",
f"--python={python_path}",
*upgrade,
"--upgrade",
]
ctx = click.get_current_context()
if (cooldown_ := conf.get("exclude_newer")) is not None and not ctx.params[
"ignore_cooldown"
]:
callargs_.append(f"--exclude-newer={cooldown_}")
try:
_run_command(*callargs_)
except Exception as err:
raise RuntimeError(f"Unable to pip upgrade: {upgrade}") from err
[docs]
@hookimpl(trylast=True)
def run_install_lower(basedir: str, envname: str, lower: list[str], conf: dict):
"""Install lower bounds of packages provided.
Parameters
----------
basedir : str
The base directory location for the environment.
envname : str
Environment to install into.
lower : list[str]
Lower bounds of packages to install.
conf : dict
The configuration dictionary for the environment. This is useful if you
want to add configuration arguments for additional dependencies that can
only be installed through the environment manager (e.g. Conda).
"""
python_path = path_to_python(basedir, envname)
try:
uv_ = find_uv_bin()
_run_command(uv_, "pip", "install", f"--python={python_path}", *lower)
except Exception as err:
raise RuntimeError(f"Unable to pip install: {lower}") from err
[docs]
@hookimpl(tryfirst=True)
def post_run_hook(testers: list, conf: dict):
"""Refresh ``uv.lock`` based on the test output."""
ctx = click.get_current_context()
if not ctx.params["export"]:
LOG.info(
"Skipping ``uv lock --upgrade`` as the requirements have not been updated."
)
elif not all(tester.status for tester in testers):
LOG.info("Skipping ``uv.lock`` refresh as not every environment passed.")
elif (Path(ctx.params["config"]).parent / "uv.lock").is_file():
# uv.lock exists already and the whole matrix is green
try:
uv_ = find_uv_bin()
_run_command(uv_, "lock", "--upgrade")
except RuntimeError:
LOG.info("Unable to update the ``uv.lock`` file.")
else:
LOG.info(
"Skipping ``uv.lock`` refresh as we couldn't find an existing ``uv.lock`` file."
)