Skip to content

Pick best available installer for generic Python project setup#591

Merged
basnijholt merged 2 commits into
mainfrom
python-setup-installer-fallback
Jun 10, 2026
Merged

Pick best available installer for generic Python project setup#591
basnijholt merged 2 commits into
mainfrom
python-setup-installer-fallback

Conversation

@basnijholt

Copy link
Copy Markdown
Owner

Problem

ag dev new on a generic Python project (bare pyproject.toml or requirements.txt) hardcodes pip:

→ Running: pip install -e .
Warning: Setup failed: /bin/sh: pip: command not found

macOS commonly has no bare pip on PATH (Homebrew/Xcode Python only ship pip3), so worktree setup always failed on these projects.

Fix

Choose the installer at detection time, following the existing _unidep_cmd availability-check pattern:

  1. uv (preferred): uv venv && uv pip install ...uv venv creates ./.venv and uv pip install targets it from the working directory (docs). run_setup() already clears VIRTUAL_ENV from the subprocess env, so the caller's activated environment doesn't hijack the install (verified live).
  2. pip: previous behavior.
  3. pip3: macOS fallback.
  4. None available: detection skips setup gracefully instead of failing.

Bonus: since uv creates ./.venv during setup, the subsequent direnv step now generates a source .venv/bin/activate .envrc for generic Python projects (it previously found no venv).

Tests

  • Fallback tier tests with mocked shutil.which, with evidence docstrings per repo convention (uv docs + live verification with uv 0.9).
  • Verified end-to-end: detect_project_type + run_setup on a temp pyproject project creates .venv and installs editable.
  • Full suite: 1419 passed, 4 skipped.

Generic pyproject.toml and requirements.txt projects hardcoded pip,
which fails on systems without a bare pip on PATH (e.g. macOS with
Homebrew Python only ships pip3) with:

    Warning: Setup failed: /bin/sh: pip: command not found

Choose the installer at detection time instead, preferring uv
(uv venv + uv pip install, which targets the freshly created ./.venv
since run_setup clears VIRTUAL_ENV), then pip, then pip3. When no
installer is available, detection skips setup instead of failing.

As a bonus, the uv-created .venv means the direnv step now generates
a 'source .venv/bin/activate' .envrc for generic Python projects.
@greptile-apps

greptile-apps Bot commented Jun 10, 2026

Copy link
Copy Markdown

Greptile Summary

Replaces the hardcoded pip install commands for generic Python projects with a tiered installer-detection helper (uvpippip3) chosen at detection time, matching the existing _unidep_cmd pattern. When no installer is found, detection returns None and setup is skipped gracefully instead of failing with a command-not-found error.

  • _python_install_commands checks shutil.which for uv, pip, and pip3 in order; the uv path emits uv venv && uv pip install … so a .venv is created in the project directory, and run_setup's existing VIRTUAL_ENV clearing ensures uv pip targets that venv rather than the caller's activated environment.
  • _detect_pip_install_project extracts the requirements.txt and generic pyproject.toml branches from detect_project_type, each delegating to the new helper, and returns None when no installer is available.
  • Tests add shutil.which mocks to the two pre-existing detection tests (addressing prior environment-sensitivity feedback) and introduce five new focused tests covering all installer tiers and the no-installer case.

Confidence Score: 5/5

Safe to merge — the change is a targeted, well-tested fix with no regressions on existing project-type detection paths.

The new helper follows an already-established pattern (_unidep_cmd), every code path has a corresponding test with proper shutil.which mocking, run_setup's existing VIRTUAL_ENV clearing correctly handles the uv venv case, and the no-installer fallback (returning None) is the graceful behavior described in the PR and covered by a dedicated test.

No files require special attention.

Important Files Changed

Filename Overview
agent_cli/dev/project.py Adds _python_install_commands and _detect_pip_install_project helpers that detect the best available installer (uv → pip → pip3) at detection time; refactors the two hardcoded pip install branches out of detect_project_type. Logic is clean and mirrors the existing _unidep_cmd pattern.
tests/dev/test_project.py Adds shutil.which mocks to the two pre-existing pip/generic tests (fixing the environment-sensitivity gap noted in a previous review) and adds five new installer-tier tests covering uv preference, pip/pip3 fallbacks, and the no-installer-available case. test_python_unidep_excludes_test_example_dirs also gains the mock to avoid a false-None from the new pip fallback path.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[detect_project_type] --> B{uv.lock or uv in pyproject.toml?}
    B -- Yes --> C[python-uv: uv sync]
    B -- No --> D{pixi.toml / pixi.lock?}
    D -- Yes --> E[pixi: pixi install]
    D -- No --> F{unidep project?}
    F -- Yes --> G[python-unidep / monorepo]
    F -- No --> H{poetry.lock?}
    H -- Yes --> I[python-poetry: poetry install]
    H -- No --> J[_detect_pip_install_project]

    J --> K{requirements.txt exists?}
    K -- Yes --> L[_python_install_commands]
    K -- No --> M{pyproject.toml exists?}
    L --> N{uv on PATH?}
    N -- Yes --> O[python-pip: uv venv + uv pip install]
    N -- No --> P{pip on PATH?}
    P -- Yes --> Q[python-pip: pip install]
    P -- No --> R{pip3 on PATH?}
    R -- Yes --> S[python-pip: pip3 install]
    R -- No --> M

    M -- Yes --> T[_python_install_commands]
    M -- No --> U[None — skip setup]
    T --> V{uv on PATH?}
    V -- Yes --> W[python: uv venv + uv pip install -e .]
    V -- No --> X{pip on PATH?}
    X -- Yes --> Y[python: pip install -e .]
    X -- No --> Z{pip3 on PATH?}
    Z -- Yes --> AA[python: pip3 install -e .]
    Z -- No --> U
Loading

Reviews (2): Last reviewed commit: "Mock shutil.which in environment-sensiti..." | Re-trigger Greptile

Generic Python detection now requires an installer on PATH, so tests
asserting it must not depend on the host having uv/pip/pip3 installed.
Addresses review feedback on #591.
@basnijholt basnijholt merged commit 683ad13 into main Jun 10, 2026
9 of 10 checks passed
@basnijholt basnijholt deleted the python-setup-installer-fallback branch June 10, 2026 18:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant