From 9dd73e48439382150f9926e86059dfad65f0f554 Mon Sep 17 00:00:00 2001 From: Jimmy Yuen Ho Wong Date: Mon, 4 Aug 2025 17:32:32 +0100 Subject: [PATCH] feat(virtualenv): add default environment support for pixi, conda, and mamba MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds pixi, conda, and mamba to virtualenv resolution order: - Pixi: extract default environment from `pixi info --json` - Conda/Mamba: read prefix from `environment*.yml` files - Update virtualenv resolution order steps 3-4 - Add comprehensive tests for all three tools 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- pet.el | 21 +++++++++++++---- test/pet-virtualenv-root-test.el | 40 ++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/pet.el b/pet.el index e95ae5d..b28f5c0 100644 --- a/pet.el +++ b/pet.el @@ -1037,15 +1037,28 @@ Selects a virtualenv in the following order: 1. Cached virtualenv path (from previous detection or manual switching). 2. The value of the environment variable `VIRTUAL_ENV' if defined. -3. Poetry virtualenv from `pyproject.toml'. -4. Pipenv virtualenv from `Pipfile'. -5. A directory in `pet-venv-dir-names' in the project root if found. -6. Pyenv virtualenv from `.python-version'." +3. Pixi default environment from `pixi.toml' or `pyproject.toml'. +4. Conda/Mamba environment from `environment*.yml'. +5. Poetry virtualenv from `pyproject.toml'. +6. Pipenv virtualenv from `Pipfile'. +7. A directory in `pet-venv-dir-names' in the project root if found. +8. Pyenv virtualenv from `.python-version'." (let ((root (pet-project-root))) (or (pet-cache-get (list root :virtualenv)) (let ((venv-path (cond ((when-let* ((ev (getenv "VIRTUAL_ENV"))) (expand-file-name ev))) + ((when-let* ((program (pet-use-pixi-p))) + (let* ((result (pet-run-process-get-output program "info" "--json")) + (info (pet-parse-json result))) + (let-alist info + (when .environments_info + (let-alist (alist-get 'default .environments_info) + .prefix)))))) + ((when-let* ((program (or (pet-use-conda-p) (pet-use-mamba-p))) + (env-config (pet-environment))) + (let-alist env-config + .prefix))) ((when-let* ((program (pet-use-poetry-p)) (default-directory (file-name-directory (pet-pyproject-path)))) (pet-run-process-get-output program "env" "info" "--no-ansi" "--path"))) diff --git a/test/pet-virtualenv-root-test.el b/test/pet-virtualenv-root-test.el index 42b17aa..012cd2b 100644 --- a/test/pet-virtualenv-root-test.el +++ b/test/pet-virtualenv-root-test.el @@ -91,6 +91,46 @@ (expect (pet-cache-get (list project-root :virtualenv)) :to-equal pyenv-virtualenv-truename) (expect 'process-file :to-have-been-called-with pyenv-path nil t nil "prefix")) + (it "should return the absolute path of the virtualenv for a project using `pixi'" + (spy-on 'pet-use-conda-p) + (spy-on 'pet-use-mamba-p) + (spy-on 'pet-use-poetry-p) + (spy-on 'pet-use-pipenv-p) + (spy-on 'locate-dominating-file) + (spy-on 'pet-use-pyenv-p) + (spy-on 'pet-use-pixi-p :and-return-value pixi-path) + (spy-on 'pet-run-process-get-output :and-call-fake + (lambda (program &rest args) + (when (and (equal program pixi-path) + (equal args '("info" "--json"))) + (format "{\"environments_info\":{\"default\":{\"prefix\":\"%s\"}}}" pixi-virtualenv)))) + (expect (pet-virtualenv-root) :to-equal pixi-virtualenv) + (expect (pet-cache-get (list project-root :virtualenv)) :to-equal pixi-virtualenv)) + + (it "should return the absolute path of the virtualenv for a project using `conda'" + (spy-on 'pet-use-pixi-p) + (spy-on 'pet-use-mamba-p) + (spy-on 'pet-use-poetry-p) + (spy-on 'pet-use-pipenv-p) + (spy-on 'locate-dominating-file) + (spy-on 'pet-use-pyenv-p) + (spy-on 'pet-use-conda-p :and-return-value conda-path) + (spy-on 'pet-environment :and-return-value `((prefix . ,conda-virtualenv))) + (expect (pet-virtualenv-root) :to-equal conda-virtualenv) + (expect (pet-cache-get (list project-root :virtualenv)) :to-equal conda-virtualenv)) + + (it "should return the absolute path of the virtualenv for a project using `mamba'" + (spy-on 'pet-use-pixi-p) + (spy-on 'pet-use-conda-p) + (spy-on 'pet-use-poetry-p) + (spy-on 'pet-use-pipenv-p) + (spy-on 'locate-dominating-file) + (spy-on 'pet-use-pyenv-p) + (spy-on 'pet-use-mamba-p :and-return-value mamba-path) + (spy-on 'pet-environment :and-return-value `((prefix . ,mamba-virtualenv))) + (expect (pet-virtualenv-root) :to-equal mamba-virtualenv) + (expect (pet-cache-get (list project-root :virtualenv)) :to-equal mamba-virtualenv)) + (it "should return the absolute path of the virtualenv for a project if the root is found in cache" (pet-cache-put (list project-root :virtualenv) "/home/user/.venvs/env/") (expect (pet-virtualenv-root) :to-equal "/home/user/.venvs/env/")))