Python virtual environment doctor — diagnose and fix broken venvs, pip, poetry locks
Project description
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:
- Runs full diagnosis
- If poetry.lock stale →
poetry lock - If venv broken →
rm -rf venv && python3 -m venv venv - Upgrades pip in new venv
- Installs dependencies (Poetry preferred, pip fallback)
- 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:
- Uses only stdlib (
argparse,dataclasses,pathlib,subprocess, etc.) - Implements all diagnosis/fix logic inline
- Has zero external dependencies
- 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
- Fork and clone
pip install -e ".[dev]"python3 -m pytest tests/ -v- Make changes, add tests
- Submit PR
License
Apache License 2.0 - see LICENSE for details.
Author
Created by Tom Sapletta - tom@sapletta.com
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file xnv-0.1.1.tar.gz.
File metadata
- Download URL: xnv-0.1.1.tar.gz
- Upload date:
- Size: 15.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa66295d174e5ba9808c2fc56f65c17a6fb23b6cbf44d7b37c39f6d853d9cc10
|
|
| MD5 |
27e772a54a74037c6d0dd710474acd2e
|
|
| BLAKE2b-256 |
787e2b5466dcf0c6a4469d1e26b2a9a07527984d2d6af022b3d843509b7148c3
|
File details
Details for the file xnv-0.1.1-py3-none-any.whl.
File metadata
- Download URL: xnv-0.1.1-py3-none-any.whl
- Upload date:
- Size: 11.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b74120cf1bec233d1d6508edc55df0baaab25d45793cebe49a362c4b52e833c3
|
|
| MD5 |
319d69ca41d231bf840b1796e0dc6f8f
|
|
| BLAKE2b-256 |
33edb168e8133f85e306b1e2b10b11b9bb6c473eddc8e9b5397fa0780cca1910
|