This document provides comprehensive lists of all Python virtual environment tools and Emacs packages that pet supports.
- pre-commit
- poetry
- pipenv
- direnv
- venv, virtualenv or virtualenvwrapper (virtualenvwrapper caveats)
- maturin
- uv
- pdm
- hatch
- pipx
- pyenv (very poorly maintained; don't use it unless you are using Homebrew on macOS)
- docker
- pixi
- conda (no support for conda-project yet)
- mamba
- micromamba
- Whatever is on your
VIRTUAL_ENVenvironment variable - Even when you aren't in a virtual environment
- Built-in project.el
- projectile
- Built-in TRAMP
Short answer:
Use envrc.
(require 'envrc)
(add-hook 'change-major-mode-after-body-hook 'envrc-mode)Longer answer:
There are a number of packages similar to envrc such as direnv
and buffer-env that claim to be able to configure direnv in
Emacs. However, they all suffer from various problems such as changing
the environment and exec-path for the entire Emacs process, unable
to activate early enough or being too general to support direnv tightly.
Because pet needs to configure the buffer-local variables before
the rest of the minor modes are activated, but after exec-path
has been set up by direnv, one must take care to choose a minor mode
package that allows the user to customize when it takes effect. This
requirement rules out direnv.el [1].
| [1] | Earlier versions of pet suggested direnv.el as a solution; it is
no longer recommended for this reason. |
You can use envrc + this direnv configuration to
activate your virtualenv or auto-virtualenvwrapper. Note
that in any case, your virtualenv must be activated before turning on
pet-mode in order to make the environment variable VIRTUAL_ENV
available to it. For example:
(require 'auto-virtualenvwrapper)
(require 'pet)
(add-hook 'python-base-mode-hook
(lambda ()
(auto-virtualenvwrapper-activate)
(pet-mode))
-10)
(add-hook 'window-configuration-change-hook #'auto-virtualenvwrapper-activate)
(add-hook 'focus-in-hook #'auto-virtualenvwrapper-activate)For users who want fine-grained control over specific packages:
(use-package exec-path-from-shell
:if (memq (window-system) '(mac ns))
:config (exec-path-from-shell-initialize))
(use-package flycheck)
(use-package lsp)
(use-package lsp-jedi
:after lsp)
(use-package lsp-pyright
:after lsp)
(use-package dap-python
:after lsp)
(use-package eglot)
(use-package python-pytest)
(use-package python-black)
(use-package python-isort)
(use-package ruff-format)
(use-package pet
;; Optional: ensure external tools are installed
;; :ensure-system-package ((dasel . "dasel")
;; (sqlite3 . "sqlite3"))
:config
(add-hook 'python-mode-hook
(lambda ()
(setq-local python-shell-interpreter (pet-executable-find "python")
python-shell-virtualenv-root (pet-virtualenv-root))
;; (pet-eglot-setup)
;; (eglot-ensure)
(pet-flycheck-setup)
(flycheck-mode)
(setq-local lsp-jedi-executable-command
(pet-executable-find "jedi-language-server"))
(setq-local lsp-pyright-python-executable-cmd python-shell-interpreter
lsp-pyright-venv-path python-shell-virtualenv-root)
(lsp)
(setq-local dap-python-executable python-shell-interpreter)
(setq-local python-pytest-executable (pet-executable-find "pytest"))
(when-let ((ruff-executable (pet-executable-find "ruff")))
(setq-local ruff-format-command ruff-executable)
(ruff-format-on-save-mode))
(when-let ((black-executable (pet-executable-find "black")))
(setq-local python-black-command black-executable)
(python-black-on-save-mode))
(when-let ((isort-executable (pet-executable-find "isort")))
(setq-local python-isort-command isort-executable)
(python-isort-on-save-mode)))))Note
Most of this configuration is handled automatically by pet-mode. This
example is useful for understanding how pet works internally or when you
need to customize specific package integrations.