Skip to content

Resolve

Resolves a package — and its transitive dependencies — into an isolated directory, for trustedlicenses check. Independent of whatever installer the consuming project actually uses. See Usage Guide § Checking a package before you add it.

trustedlicenses.resolve_packages(packages, target)

Install packages and their transitive dependencies into target.

Tries uv pip install first, since it's an order of magnitude faster and already this project's own tooling; falls back to python -m pip install (available in nearly every Python installation) when uv isn't on PATH. Neither call touches the current environment -- both install into target only, via --target.

Parameters:

Name Type Description Default
packages list[str]

Package requirement strings (e.g. "requests", "django>=5,<6"), exactly as you'd pass to pip install.

required
target Path

An existing, empty directory to install into.

required

Raises:

Type Description
ResolutionError

Neither uv nor pip is usable, or resolution failed (a typo'd package name, a version conflict, no network, ...).

Source code in src/trustedlicenses/resolve.py
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
def resolve_packages(packages: list[str], target: Path) -> None:
    """Install ``packages`` and their transitive dependencies into ``target``.

    Tries ``uv pip install`` first, since it's an order of magnitude faster and
    already this project's own tooling; falls back to ``python -m pip install``
    (available in nearly every Python installation) when ``uv`` isn't on ``PATH``.
    Neither call touches the current environment -- both install into ``target``
    only, via ``--target``.

    Args:
        packages: Package requirement strings (e.g. ``"requests"``,
            ``"django>=5,<6"``), exactly as you'd pass to ``pip install``.
        target: An existing, empty directory to install into.

    Raises:
        ResolutionError: Neither ``uv`` nor ``pip`` is usable, or resolution failed
            (a typo'd package name, a version conflict, no network, ...).
    """
    uv = shutil.which("uv")
    command = (
        [uv, "pip", "install", "--target", str(target), "--python", sys.executable, *packages]
        if uv is not None
        else [sys.executable, "-m", "pip", "install", "--target", str(target), *packages]
    )

    try:
        result = subprocess.run(command, capture_output=True, text=True, check=False)  # noqa: S603
    except FileNotFoundError as error:
        message = (
            "could not resolve packages: neither `uv` nor a working `pip` is available. "
            "Install either to use `trustedlicenses check`."
        )
        raise ResolutionError(message) from error

    if result.returncode != 0:
        message = f"could not resolve {', '.join(packages)}:\n{result.stderr.strip()}"
        raise ResolutionError(message)

trustedlicenses.ResolutionError

Bases: Exception

Packages could not be resolved -- no installer available, or resolution failed.