|
| 1 | +# Python Environment Tools (PET) - AI Coding Agent Instructions |
| 2 | + |
| 3 | +## Project Overview |
| 4 | + |
| 5 | +This is a high-performance Rust-based tool for discovering Python environments and virtual environments. It operates as a JSONRPC server consumed by the VS Code Python extension to avoid spawning Python processes repeatedly. |
| 6 | + |
| 7 | +## Architecture |
| 8 | + |
| 9 | +### Core Concepts |
| 10 | + |
| 11 | +- **Locators**: Modular environment discovery components implementing the `Locator` trait (`crates/pet-core/src/lib.rs`) |
| 12 | +- **JSONRPC Server**: Main communication interface (`crates/pet/src/jsonrpc.rs`) with stdio/stdout protocol |
| 13 | +- **Environment Types**: 15+ supported Python installations (Conda, Poetry, PyEnv, Homebrew, Windows Store, etc.) |
| 14 | +- **Reporter Pattern**: Asynchronous environment discovery reporting via the `Reporter` trait |
| 15 | + |
| 16 | +### Key Architecture Files |
| 17 | + |
| 18 | +- `crates/pet/src/locators.rs` - Ordered locator creation and fallback identification logic |
| 19 | +- `crates/pet/src/find.rs` - Multi-threaded environment discovery coordination |
| 20 | +- `crates/pet-core/src/lib.rs` - Core traits and configuration structures |
| 21 | +- `docs/JSONRPC.md` - Complete API specification with TypeScript interfaces |
| 22 | + |
| 23 | +## Development Workflow |
| 24 | + |
| 25 | +### Building & Testing |
| 26 | + |
| 27 | +```bash |
| 28 | +# Standard build |
| 29 | +cargo build |
| 30 | + |
| 31 | +# Release build (optimized for performance) |
| 32 | +cargo build --release |
| 33 | + |
| 34 | +# Run tests with specific CI features |
| 35 | +cargo test --features ci |
| 36 | +cargo test --features ci-poetry-global |
| 37 | + |
| 38 | +# Run JSONRPC server |
| 39 | +./target/debug/pet server |
| 40 | +``` |
| 41 | + |
| 42 | +### Feature-Gated Testing |
| 43 | + |
| 44 | +Tests use feature flags for different environments: |
| 45 | + |
| 46 | +- `ci` - General CI environment tests |
| 47 | +- `ci-jupyter-container` - Jupyter container-specific tests |
| 48 | +- `ci-homebrew-container` - Homebrew container tests |
| 49 | +- `ci-poetry-*` - Poetry-specific test variants |
| 50 | + |
| 51 | +### Locator Development Pattern |
| 52 | + |
| 53 | +When adding new environment types: |
| 54 | + |
| 55 | +1. **Create new crate**: `crates/pet-{name}/` |
| 56 | +2. **Implement Locator trait**: Key methods are `try_from()` (identification) and `find()` (discovery) |
| 57 | +3. **Add to locator chain**: Update `create_locators()` in `crates/pet/src/locators.rs` - ORDER MATTERS |
| 58 | +4. **Platform-specific**: Use `#[cfg(windows)]`, `#[cfg(unix)]`, `#[cfg(target_os = "macos")]` |
| 59 | + |
| 60 | +Example structure: |
| 61 | + |
| 62 | +```rust |
| 63 | +impl Locator for MyLocator { |
| 64 | + fn get_kind(&self) -> LocatorKind { LocatorKind::MyType } |
| 65 | + fn supported_categories(&self) -> Vec<PythonEnvironmentKind> { vec![PythonEnvironmentKind::MyType] } |
| 66 | + fn try_from(&self, env: &PythonEnv) -> Option<PythonEnvironment> { /* identification logic */ } |
| 67 | + fn find(&self, reporter: &dyn Reporter) { /* discovery logic */ } |
| 68 | +} |
| 69 | +``` |
| 70 | + |
| 71 | +## Critical Patterns |
| 72 | + |
| 73 | +### Performance Principles (from `crates/pet/README.md`) |
| 74 | + |
| 75 | +1. **Avoid spawning processes** - Extract info from files/filesystem when possible |
| 76 | +2. **Report immediately** - Use Reporter pattern for async discovery |
| 77 | +3. **Complete information** - Gather all environment details in one pass, not incrementally |
| 78 | + |
| 79 | +### JSONRPC Communication Flow |
| 80 | + |
| 81 | +1. Client sends `configure` request (must be first) |
| 82 | +2. Client sends `refresh` request to discover environments |
| 83 | +3. Server sends `environment` notifications as discoveries happen |
| 84 | +4. Optional: `resolve` request for individual Python executables |
| 85 | + |
| 86 | +### Testing Verification Pattern |
| 87 | + |
| 88 | +Tests validate discovered environments using 4 verification methods: |
| 89 | + |
| 90 | +1. Spawn Python to verify `sys.prefix` and `sys.version` |
| 91 | +2. Use `try_from()` with executable to get same info |
| 92 | +3. Test symlink identification |
| 93 | +4. Use `resolve` method for consistency |
| 94 | + |
| 95 | +## Environment-Specific Notes |
| 96 | + |
| 97 | +### Conda Environments |
| 98 | + |
| 99 | +- Supports detection from history files and conda-meta directories |
| 100 | +- Manager detection via spawning conda executable in background threads |
| 101 | +- Complex prefix/name relationships for base vs named environments |
| 102 | + |
| 103 | +### Poetry Environments |
| 104 | + |
| 105 | +- Hash-based environment naming: `{project-name}-{hash}-py` |
| 106 | +- Project-specific virtual environments in configured cache directories |
| 107 | +- Configuration hierarchy: local poetry.toml → global config |
| 108 | + |
| 109 | +### Platform Differences |
| 110 | + |
| 111 | +- **Windows**: Registry + Windows Store detection, different path separators |
| 112 | +- **macOS**: Xcode Command Line Tools, python.org, Homebrew paths |
| 113 | +- **Linux**: Global system paths (`/usr/bin`, `/usr/local/bin`) |
| 114 | + |
| 115 | +## Common Gotchas |
| 116 | + |
| 117 | +- **Locator order matters** in `create_locators()` - more specific before generic |
| 118 | +- **Thread safety** - Heavy use of Arc/Mutex for concurrent discovery |
| 119 | +- **Feature flags** - Many tests only run with specific CI features enabled |
| 120 | +- **Path canonicalization** - Symlink resolution varies by platform |
| 121 | +- **Caching** - Optional cache directory for expensive operations (conda spawning) |
| 122 | + |
| 123 | +## Files to Read First |
| 124 | + |
| 125 | +1. `docs/JSONRPC.md` - Understanding the external API |
| 126 | +2. `crates/pet/src/locators.rs` - Core architecture patterns |
| 127 | +3. `crates/pet-core/src/lib.rs` - Essential traits and types |
| 128 | +4. `crates/pet/tests/ci_test.rs` - Comprehensive testing patterns |
| 129 | + |
| 130 | + |
| 131 | +## Scripts |
| 132 | +- Use `cargo fetch` to download all dependencies |
| 133 | +- Use `rustup component add clippy` to install Clippy linter |
| 134 | +- Use `cargo fmt --all` to format code in all packages |
| 135 | +- Use `cargo build` to build the project |
| 136 | +- Use `cargo test --all` to test all packages (this can take a few seconds) |
| 137 | +- Use `cargo test [TESTNAME]` to test a specific test |
| 138 | +- Use `cargo test -p [SPEC]` to test a specific package |
| 139 | +- Use `cargo test --all` to test all packages |
0 commit comments