Skip to content

Dry runs 1.3 ​

Every command that changes your environment can show what it would do first. --dry-run prints the plan: each step in order, its exact command line, the files it would create or change, and why, under the solver's reason for the chosen Python. Nothing is executed, written or downloaded.

bash
pypilot setup --dry-run
pypilot install httpx --dry-run
pypilot fix python --dry-run
pypilot fix cuda --dry-run
pypilot doctor --fix --dry-run      # the report, then the plan "Fix environment" would run
pypilot setup --dry-run --json      # the plan as JSON

--dry-run needs engine 1.3.0 or newer; 1.2.2 and older do not have it.

What a plan shows ​

~/src/demo
$ pypilot setup --dry-run
PyPilot setup --dry-run: C:\src\demo (uv mode, Python 3.12)
  Python 3.12 chosen: dependencies support 3.12; mediapipe caps the upper bound (supports 3.9–3.12).
  • ensure uv: uv 0.13.5 (on PATH)
── Plan (nothing was changed) ───────────────────────────
  1. uv init
     $ uv init --bare --no-workspace --pin-python --python 3.12
     writes: pyproject.toml, .python-version
     why: the project has no pyproject.toml; create a bare one pinned to Python 3.12 so `uv add` has a manifest to record dependencies in
  2. uv python install 3.12
     $ uv python install 3.12
     why: make CPython 3.12 available (uv downloads it into its own Python store if missing)
  3. uv venv
     $ uv venv --clear --python 3.12 C:\src\demo\.venv
     writes: .venv
     why: create the project environment on Python 3.12, replacing any existing one
  4. uv add -r requirements.txt
     $ uv add -r requirements.txt
     writes: pyproject.toml, uv.lock, .venv
     why: move requirements.txt's dependencies into pyproject.toml and install them

  Dry run only; run without --dry-run to apply.
  • The header names the mode (uv, uv-pip, pip or pixi) and the Python the run would use, then the solver's reason for it.
  • Lines with • are the read-only checks the real run makes first (here: is uv on PATH). They run during a dry run too, because the plan depends on them.
  • Each numbered step is a process the real run would start, with $ and its argument vector, writes: (paths relative to the project) and why:. A step that is not a process (writing the PyTorch index into pyproject.toml, downloading uv, the GPU self-test) has no $ line.
  • Nothing to do. when the environment already matches, for example fix cuda in a project without torch or tensorflow.

Why you can trust it ​

The plan is not a separate description of what the command does. The command runs its own code path with every change recorded instead of made: each subprocess, file write and download goes through one executor that, in a dry run, notes the step and returns. So the plan is what the real run does on this machine, today, with these settings. Only the probes and PyPI lookups the analysis always makes actually run.

What it cannot know in advance: the result of a step that never ran. If the real uv add would fail on a resolver conflict, the plan still lists uv add; pypilot doctor and the uv dry-run finding are where such conflicts show up.

When the real run would stop ​

If the run would stop before it finishes, the plan says where, and the command exits with status 1. Here pip mode needs a Python that is not installed, and pip cannot fetch one:

text
PyPilot setup --dry-run: C:\src\pipdemo (pip mode, Python 3.12)
  Python 3.12 chosen: dependencies support 3.9–3.12; mediapipe caps the upper bound (supports 3.9–3.12).
  ✗ select interpreter: Python 3.12 is required but not installed. Install it (e.g. from python.org or your package manager), then run setup again. pip mode cannot fetch interpreters.
── Plan (nothing was changed) ───────────────────────────
  Nothing to do.

  ✗ The run would stop here: select interpreter: Python 3.12 is required but not installed. Install it (e.g. from python.org or your package manager), then run setup again. pip mode cannot fetch interpreters.
pypilot setup: the plan stops before it finishes: select interpreter: Python 3.12 is required but not installed. Install it (e.g. from python.org or your package manager), then run setup again. pip mode cannot fetch interpreters.

In scripts, the exit status is the quickest check: 0 means the plan runs to the end.

JSON ​

With --json the plan replaces the command's usual document. command is the command as typed (doctor --fix for that one), dry_run is true, and ok is true exactly when plan.blocked is null:

KeyMeaning
plan.modeA resolved_mode value: uv_full, uv_pip_compat, pure_pip or pixi
plan.pythonThe Python the run would use, or null
plan.whyThe solver's reason, as in the text header
plan.steps[{ "name", "command": [argv], "writes": [paths], "why" }]. command is the exact argument vector, program first; empty for a step that is not a process. writes holds absolute paths
plan.notesThe read-only checks: [{ "name", "ok", "detail" }]
plan.blockedWhy the real run would stop, else null

pypilot setup --dry-run --json for the project above:

json
{
  "pypilot": "1.3.0",
  "command": "setup",
  "ok": true,
  "dry_run": true,
  "plan": {
    "mode": "uv_full",
    "python": "3.12",
    "why": "Python 3.12 chosen: dependencies support 3.12; mediapipe caps the upper bound (supports 3.9–3.12).",
    "steps": [
      {
        "name": "uv init",
        "command": [
          "uv",
          "init",
          "--bare",
          "--no-workspace",
          "--pin-python",
          "--python",
          "3.12"
        ],
        "writes": [
          "C:\\src\\demo\\pyproject.toml",
          "C:\\src\\demo\\.python-version"
        ],
        "why": "the project has no pyproject.toml; create a bare one pinned to Python 3.12 so `uv add` has a manifest to record dependencies in"
      },
      {
        "name": "uv python install 3.12",
        "command": [
          "uv",
          "python",
          "install",
          "3.12"
        ],
        "writes": [],
        "why": "make CPython 3.12 available (uv downloads it into its own Python store if missing)"
      },
      {
        "name": "uv venv",
        "command": [
          "uv",
          "venv",
          "--clear",
          "--python",
          "3.12",
          "C:\\src\\demo\\.venv"
        ],
        "writes": [
          "C:\\src\\demo\\.venv"
        ],
        "why": "create the project environment on Python 3.12, replacing any existing one"
      },
      {
        "name": "uv add -r requirements.txt",
        "command": [
          "uv",
          "add",
          "-r",
          "requirements.txt"
        ],
        "writes": [
          "C:\\src\\demo\\pyproject.toml",
          "C:\\src\\demo\\uv.lock",
          "C:\\src\\demo\\.venv"
        ],
        "why": "move requirements.txt's dependencies into pyproject.toml and install them"
      }
    ],
    "notes": [
      {
        "name": "ensure uv",
        "ok": true,
        "detail": "uv 0.13.5 (on PATH)"
      }
    ],
    "blocked": null
  }
}

In the editors ​

The editors' buttons (Fix environment, quick fixes) run the same code without --dry-run. To see what one of them would do, run the matching command with --dry-run in the project folder: Fix environment is pypilot setup (or pypilot doctor --fix), an install quick fix is pypilot install <package>, and pypilot fix python shows the rebuild onto the recommended Python that a "Rebuild environment on Python X.Y" quick fix starts with.

Engine: AGPL-3.0-or-later. Zed and VS Code extensions: Apache-2.0. pypilot-cli: AGPL-3.0-or-later.