Skip to main content

xnv — Python Virtual Environment Doctor

Diagnose and fix broken Python virtual environments, stale poetry locks, and pip issues.

Zero dependencies. Single file. Works when pip is broken.

python3 xnv.py fix   # repairs venv without needing pip

Table of Contents

Why?

Common Python environment failures:

Problem Cause xnv solution
pip: cannot execute: required file not found venv symlinks point to deleted/upgraded Python Detect broken symlinks → recreate venv
poetry.lock out of sync pyproject.toml edited without poetry lock Run poetry lock automatically
Conda + venv conflicts PATH confusion between conda base and project venv Detect CONDA_ACTIVE vs VIRTUAL_ENV mismatch
pyvenv.cfg stale home System Python relocated after venv creation Check pyvenv.cfg home dir exists
Broken pip shim pip binary broken but python -m pip works Reinstall pip via ensurepip

When pip is broken, you can't pip install a fix tool. xnv solves this by running as a single file with zero dependencies.

Quick Start (no install needed)

# 1. Download/copy xnv.py to your project
wget https://raw.githubusercontent.com/youruser/xnv/main/xnv.py
# or simply copy the file manually

# 2. Diagnose
python3 xnv.py                          # current directory
python3 xnv.py doctor /path/to/project  # specific project

# 3. Fix auto-magically
python3 xnv.py fix                      # diagnose + repair + install deps
python3 xnv.py fix --force              # force recreate venv
python3 xnv.py fix --no-install         # repair only, skip pip install

# 4. Manual operations
python3 xnv.py nuke                     # remove venv completely
python3 xnv.py create                   # create fresh venv
python3 xnv.py lock                     # regenerate poetry.lock

Installation (optional)

If you want the xnv shortcut command:

# Development install (editable)
pip install -e .

# Or use pipx for isolated install
pipx install .

# Then use `xnv` instead of `python3 xnv.py`
xnv doctor
xnv fix

Commands

doctor [path] — Diagnose environment

$ python3 xnv.py doctor

xnv doctor — /home/user/myproject

  ✓ [VENV_PYTHON_OK] venv Python: Python 3.12.4
  ✓ [VENV_PIP_OK] venv pip: pip 24.0
  ⚠ [NO_PYPROJECT] No pyproject.toml found
  ✗ [POETRY_LOCK_STALE] poetry.lock out of sync with pyproject.toml
      hint: poetry lock

  1 errors / 1 warnings / 2 ok

✗ Issues found — run 'python3 xnv.py fix' to repair

fix [options] [path] — Auto-repair

Options:

  • --force, -f — Force recreate venv even if it appears healthy
  • --no-install — Skip dependency installation (repair only)
  • --dev — Install dev dependencies too (with Poetry)
# Standard repair
python3 xnv.py fix

# Force clean slate
python3 xnv.py fix --force

# Repair without installing packages
python3 xnv.py fix --no-install

What fix does:

  1. Runs full diagnosis
  2. If poetry.lock stale → poetry lock
  3. If venv broken → rm -rf venv && python3 -m venv venv
  4. Upgrades pip in new venv
  5. Installs dependencies (Poetry preferred, pip fallback)
  6. Verifies the fix

nuke [path] — Remove venv

python3 xnv.py nuke              # remove ./venv
python3 xnv.py nuke --name .venv # remove ./.venv

create [options] [path] — Create venv

python3 xnv.py create                    # create ./venv
python3 xnv.py create --name .venv       # create ./.venv
python3 xnv.py create --force            # recreate if exists

lock [path] — Fix poetry.lock

python3 xnv.py lock   # runs 'poetry lock'

Error Codes

Code Severity Description Auto-fixed by fix?
VENV_BROKEN_PYTHON error Python symlink points to missing target ✅ Yes
VENV_NO_PYTHON error Python binary missing from venv ✅ Yes
VENV_PYTHON_FAIL error Python binary not executable ✅ Yes
VENV_BROKEN_PIP error pip symlink broken ✅ Yes
VENV_NO_PIP error pip binary missing ✅ Yes (via ensurepip)
VENV_PIP_FAIL error pip not functional ✅ Yes
VENV_PIP_SHIM_BROKEN error pip shim broken but python -m pip works ✅ Yes (reinstall pip)
VENV_STALE_HOME error pyvenv.cfg home dir missing ✅ Yes
POETRY_LOCK_STALE error poetry.lock out of sync ✅ Yes
VENV_MISMATCH warn Active VIRTUAL_ENV ≠ project venv ❌ Manual fix
NO_VENV warn No venv found ✅ Yes (creates one)
NO_PYPROJECT warn No pyproject.toml ❌ N/A
POETRY_NO_LOCK warn poetry.lock missing ✅ Yes
CONDA_ACTIVE info Conda environment detected —
VENV_EXTERNAL info Using external venv —
VENV_PYTHON_OK info Python works —
VENV_PIP_OK info pip works —
POETRY_LOCK_OK info poetry.lock in sync —

Troubleshooting

"pip: cannot execute: required file not found"

Symptom: /venv/bin/pip: cannot execute: required file not found

Cause: venv symlinks point to old Python location (e.g., after conda update)

Fix:

python3 xnv.py fix --force

poetry.lock keeps being stale

Symptom: POETRY_LOCK_STALE keeps appearing

Cause: pyproject.toml dependencies changed without updating lock

Fix:

python3 xnv.py lock      # regenerate lock
python3 xnv.py fix       # reinstall with new lock

Conda base env active

Symptom: CONDA_ACTIVE shows (base) even though you want project venv

Fix:

conda deactivate
python3 xnv.py fix
source venv/bin/activate

Venv exists but xnv says "NO_VENV"

Symptom: venv/ exists but xnv doesn't detect it

Check: Does venv/pyvenv.cfg exist? If not, it's not a proper venv.

Fix:

python3 xnv.py fix --force

Architecture

Two modes of operation

┌─────────────────┐     ┌─────────────────┐
│  Standalone     │     │  Package        │
│  xnv.py         │     │  pip install -e │
│                 │     │                 │
│  • Zero deps    │     │  • CLI shortcut │
│  • Copy anywhere│     │  • Importable   │
│  • Works when   │     │    API          │
│    pip broken   │     │                 │
└─────────────────┘     └─────────────────┘
         │                       │
         └───────────┬───────────┘
                     │
              ┌──────▼──────┐
              │  Core logic  │
              │  (diagnose, │
              │   fix)       │
              └─────────────┘

Detection logic

def diagnose(project_dir) -> Diagnosis:
    1. Find venv (venv, .venv, env, .env)
    2. Check Python binary exists & is executable
    3. Check pip binary exists & works
    4. Check pyvenv.cfg home dir valid
    5. Check poetry.lock sync (if poetry available)
    6. Check conda vs venv conflicts
    7. Return list of Issues

Makefile Integration

Add to your project's Makefile:

# Use standalone xnv.py (no install needed)
fix-env:
	@python3 $(XNV_PATH)/xnv.py fix .

doctor-env:
	@python3 $(XNV_PATH)/xnv.py doctor .

# Or if xnv installed
fix-env:
	@xnv fix .

Python API

For programmatic use after pip install -e .:

from xnv.diagnose import diagnose, Issue
from xnv.fix import fix

# Diagnose
 diag = diagnose("/path/to/project")
print(f"Healthy: {diag.healthy}")
print(f"Venv: {diag.venv_path}")

for issue in diag.issues:
    print(f"[{issue.severity}] {issue.code}: {issue.message}")
    if issue.fix_hint:
        print(f"  Hint: {issue.fix_hint}")

# Fix
ok = fix("/path/to/project", force_recreate=False, install=True, dev=False)
if ok:
    print("Environment fixed!")
else:
    print("Some issues remain")

Data classes

@dataclass
class Issue:
    code: str           # e.g., "VENV_BROKEN_PYTHON"
    severity: str       # "error", "warn", "info"
    message: str        # Human-readable description
    fix_hint: str       # Suggested fix command

@dataclass
class Diagnosis:
    project_dir: Path
    venv_path: Path | None
    python_path: Path | None
    pip_path: Path | None
    poetry_available: bool
    poetry_lock_stale: bool
    conda_active: bool
    issues: list[Issue]
    
    @property
    def healthy(self) -> bool: ...
    @property
    def errors(self) -> list[Issue]: ...
    @property
    def warnings(self) -> list[Issue]: ...

How it works (single file)

xnv.py is a self-contained Python script that:

  1. Uses only stdlib (argparse, dataclasses, pathlib, subprocess, etc.)
  2. Implements all diagnosis/fix logic inline
  3. Has zero external dependencies
  4. Can be copied to any project and run immediately

This is the bootstrap problem solution: when your package manager (pip/poetry) is broken, you can't use it to install a fix tool. xnv bypasses this by not needing installation.

Contributing

  1. Fork and clone
  2. pip install -e ".[dev]"
  3. python3 -m pytest tests/ -v
  4. Make changes, add tests
  5. Submit PR

License

Apache License 2.0 - see LICENSE for details.

Author

Created by Tom Sapletta - tom@sapletta.com

Metadata

Release files for xnv 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for xnv 0.1.2
File Size Uploaded
xnv-0.1.2.tar.gz 15.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for xnv 0.1.2
File Interpreter ABI Platform
xnv-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 27.2 kB

Release files / xnv-0.1.2.tar.gz

Download URL xnv-0.1.2.tar.gz
Size 15.4 kB
Tags Source
SHA-256 checksum
How to use checksums
30500768aaedc510703a55f4e9273398a1b817b5e699bd2d0d744367b859f09f
BLAKE2b-256 checksum
How to use checksums
5f622215e1e90705aa561e622ea8d84aec1667100919dd9d011f40497132395d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.5

Release files / xnv-0.1.2-py3-none-any.whl

Download URL xnv-0.1.2-py3-none-any.whl
Size 11.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
15453bb0e5df2440fc8c72ccbde56f8f7255bc9737f9ac1ce77e90b2401ab48f
BLAKE2b-256 checksum
How to use checksums
e5d5ce90e42fc92181ce6b3d63bd71c863638000e7affe71c3925dbf6b9a9b61
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.5

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page