.. _venvs-link: wibench-venv: virtual environment manager ========================================= Watermarking algorithms, attacks, datasets and metrics often pin conflicting package versions, so a single virtual environment cannot host all of them. ``wibench-venv`` solves this by grouping requirement files into as few mutually compatible sets as possible and building one venv per group. At run time ``wibench`` inspects the pipeline config and transparently re-executes itself with the python of a venv that covers every requirement of the config. File layout ------------ Everything lives under ``profiles/``:: profiles/ ├── common/ # NOT a profile, shared by all profiles │ ├── base/ │ │ └── wibench.txt # mandatory: included in every group of every profile │ └── common.txt # optional: participates in every profile's composition ├── image/ # a profile │ ├── .python-version # (optional) Python version for all venvs of this profile │ ├── requirements/ │ │ ├── common/ # same idea one level down, shared inside this profile only │ │ │ ├── base/ │ │ │ │ └── base.txt # mandatory: included in every group of this profile │ │ │ └── common.txt # optional: participates in this profile's composition │ │ ├── algorithms/ # one txt per entity, e.g. trustmark.txt │ │ ├── attacks/ │ │ ├── datasets/ │ │ └── metrics/ │ └── venvs/ # generated by wibench-venv │ ├── venv0.txt # group: list of requirement files covered by venv0 │ ├── venv0.lock # fully pinned lock compiled from the group │ └── venv0/ # the virtual environment itself ├── audio/ │ ├── .python-version │ ├── requirements/ │ └── venvs/ └── your_profile/ └── ... Requirement file roles: * ``profiles/common/base/*.txt`` — the mandatory base. Every group of every profile starts with these files; a requirement that conflicts with the base cannot be installed at all. * ``profiles/common/*.txt`` — shared optional requirements. They join the composition of every profile like ordinary files: placed into groups where they fit, skipped where they conflict. * ``profiles//requirements/common/base/*.txt`` — the profile's mandatory base. Same as the shared base, but scoped to one profile: every group of this profile starts with these files, other profiles ignore them completely. This is where the profile's runtime stack lives (e.g. ``torch`` for ``image``) instead of ``pyproject.toml``, so an ``audio`` venv is not forced to carry it. * ``profiles//requirements/common/*.txt`` — optional requirements shared inside the profile. They participate only in this profile's composition, like ordinary files. * ``profiles//requirements/**/*.txt`` — profile-specific requirements. The ``/.txt`` naming (e.g. ``algorithms/trustmark.txt``) is what connects a config entry to its requirement file. Commands -------- .. code-block:: console (.venv) wibench-venv [STAGES]... [-p PROFILE] [-j JOBS] [-v] .. list-table:: Stages :header-rows: 1 :widths: 20 80 * - Stage - What it does * - ``validate`` - Checks that each requirement file resolves together with the base; invalid files are excluded from the subsequent stages of this run (with a warning) * - ``compose`` - Builds groups from scratch: computes the pairwise conflict graph, then greedily packs every compatible file into every group; writes ``venvN.txt`` * - ``extend`` - Updates existing groups instead of rebuilding: keeps current members, packs new files into every group where they fit, creates new groups only for files that fit nowhere * - ``lock`` - Compiles each ``venvN.txt`` into a fully pinned ``venvN.lock`` (``uv pip compile``) * - ``install`` - Creates/recreates ``venvN/`` from each lock (``uv venv --clear`` + ``uv pip install``) * - ``rebuild`` - Shortcut for ``validate compose lock install`` — full pipeline, groups built from scratch * - ``update`` - Shortcut for ``validate extend lock install`` — full pipeline, existing groups updated in place Running without arguments executes ``install`` only. Stages can be combined: .. code-block:: console (.venv) wibench-venv rebuild # rebuild the default profile from scratch (.venv) wibench-venv update -p audio # refresh audio venvs after adding a requirement (.venv) wibench-venv compose lock # regroup and lock, don't install ``compose`` and ``extend`` (and therefore ``rebuild`` and ``update``) are mutually exclusive: use ``compose`` for a clean rebuild and ``extend`` to update existing groups in place (e.g. after adding a new requirement file). ``extend`` never removes a file from a group unless it no longer resolves or its requirement file was deleted, so group membership stays stable across runs. Options: * ``-p, --profile`` — profile to operate on. Priority: this option > ``WIBENCH_PROFILE`` environment variable > default (``image``). The name ``common`` is rejected since it is not a profile. * ``-j, --jobs`` — maximum number of concurrent ``uv`` processes (default 8). Compatibility checks and locking run concurrently; results are cached, so repeated checks of the same file combination cost nothing. * ``-v, --verbose`` — escalate logging, same scheme as the main CLI: ``-v`` extended tracebacks (backtrace), ``-vv`` adds variable diagnostics (diagnose), ``-vvv`` and beyond lower the log level one step per extra ``v`` (``-vvv`` = DEBUG). Failed resolutions during ``compose``/``extend`` are logged at DEBUG (conflicts there are expected and numerous), so use ``-vvv`` to see why two files don't fit into one venv; failures on the other stages are visible without it. Per‑profile Python version -------------------------- Put the desired version into ``profiles//.python-version`` (a single line, e.g. ``3.11``). It is passed to every ``uv pip compile`` and ``uv venv`` call, so both resolution and the built venvs use that version. Without the file, ``uv`` picks the interpreter as usual (including the repository-level ``.python-version``). After changing the version, rerun ``wibench-venv rebuild -p `` — resolution results may differ. How the pipeline picks a venv ----------------------------- When you run ``wibench --config ...``, it collects the requirements of every entity in the config and looks for a group (``venvN.txt``) that covers all of them: * with an explicit profile (``wibench --profile`` or ``WIBENCH_PROFILE``), only that profile is searched; * otherwise all profiles are searched, the default one first. If the current interpreter is not from a matching venv, ``wibench`` re-executes itself with the matched venv's python and pins the profile via ``WIBENCH_PROFILE`` for its worker subprocesses. If no group covers the config, the error lists what is missing per group — remove those entries from the config or rebuild the venvs. Practical notes --------------- * **Determinism.** Group composition is deterministic: files are ordered by conflict degree with ties broken by path, so the same inputs always produce the same groups. * **Pin git dependencies to a commit.** Unpinned refs like ``git+https://github.com/foo/bar`` force a network round-trip on every resolution and are the main source of rate-limit errors and slowdowns; pin them (``...@``) so ``uv`` can resolve from its cache. * **Transient network errors** (HTTP 429, git fetch failures) are retried with exponential backoff. During ``validate`` a file that keeps failing is marked invalid with a warning — check the log before trusting a rebuild made on a flaky network, otherwise the file silently drops out of the groups. * **Stale artifacts.** When a rebuild produces fewer groups than before, the leftover ``venvN.txt``, ``venvN.lock`` and ``venvN/`` are deleted automatically.