Use pyenv to manage your Python versions within Emacs using pyenv. This is useful to make sure your code completion backend has the correct PYTHONPATH
set up so auto-completion, jump to def, etc work as expected in each project. It can also display the current pyenv
version running in the modeline as a reminder of the environment you're working in.
This repo was originally forked from pyenv.el, which was forked from rbenv.el.
This version has been changed quite a bit to support a variety of features:
- Allow multiple pyenv versions enabled at once (just like pyenv)
- Use a global pyenv mode
- Only activate pyenv mode by setting
PYENV_VERSION
environment variable - Allow easy customization of modeline text
- Support use of pyenv-version-alias
- Make it easy to auto-switch pyenv when switching between buffers
- Allow hooks to run when pyenv changes
Why not pyenv-mode?
- Aside from setting the environment variable,
pyenv-mode
also sets thepython-shell-virtualenv-root
which doesn't make much sense in the context of using pyenv, since pyenv enables using multiple versions at once as well as using non-virtualenv versions. It would be though to change that design. pyenv-mode
depends onpythonic
, and to get something resemblingglobal-mode
you also need pyenv-mode-auto.- I forked this a long time ago to enable using multiple versions at once like pyenv. It was easier to continue modifying this than try to re-architect and hope my PRs get accepted with
pyenv-mode
Clone this repo into a directory and:
(add-to-list 'load-path (expand-file-name "/path/to/pyenv.el/"))
(require 'pyenv)
(global-pyenv-mode)
Alternatively, use straight.el:
(use-package pyenv
:straight (:host github :repo "aiguofer/pyenv.el")
:config
(global-pyenv-mode))
global-pyenv-mode
activate / deactivate pyenv.el (The current Python version is shown in the modeline)pyenv-use-global
will activate your global pythonpyenv-use
allows you to choose what python version you want to usepyenv-use-corresponding
searches for .python-version and activates the corresponding python
By default pyenv.el assumes that you installed pyenv into
~/.pyenv
. If you use a different installation location you can
customize pyenv.el to search in the right place:
(setq pyenv-installation-dir "/usr/local/pyenv")
IMPORTANT:: Currently you need to set this variable before you load pyenv.el
pyenv.el will show you the active python in the modeline. If you don't like this feature you can disable it:
(setq pyenv-show-active-python-in-modeline nil)
The default modeline representation is the python version (colored red) in square brackets. You can change the format by customizing the variable:
;; this will remove the colors
(setq pyenv-modeline-function 'pyenv--modeline-plain)
You can also define your own function to format the python version as you like.
You can also configure the pre/post-fix if you don't like the square brackets, for example, to set the prefix to the python glyph using Nerd Fonts:
(setq pyenv-modestring-prefix " ")
(setq pyenv-modestring-postfix nil)
If using pyenv-version-alias, you can enable it with:
(setq pyenv-use-alias 't)
In order to automatically switch to the corresponding pyenv when switching between Python buffers, you can use switch-buffer-functions and set it up like this (note I only update when changing to a Python buffer):
(use-package switch-buffer-functions
:straight t
:config
(defun pyenv-update-on-buffer-switch (prev curr)
(if (string-equal "Python" (format-mode-line mode-name nil nil curr))
(pyenv-use-corresponding)))
(add-hook 'switch-buffer-functions 'pyenv-update-on-buffer-switch))
If you have a jupyter kernel per pyenv version installed onto a "global" jupyter install (for example, using pyenv-jupyter-kernel), you could make sure all your shell related commands (python-shell-send-buffer/region
) work on the right (currently active) kernel using:
(setq python-shell-interpreter "jupyter-console"
python-shell-interpreter-args "--simple-prompt"
python-shell-prompt-detect-failure-warning nil)
(add-to-list 'python-shell-completion-native-disabled-interpreters
"jupyter-console")
(defun my-setup-python (orig-fun &rest args)
"Use corresponding kernel"
(let* ((curr-python (car (split-string (pyenv/version-name) ":")))
(python-shell-buffer-name (concat "Python-" curr-python))
(python-shell-interpreter-args (concat "--simple-prompt --kernel=" curr-python)))
(apply orig-fun args)))
(advice-add 'python-shell-get-process-name :around #'my-setup-python)
By default, pyenv.el
will set up the PATH
to make sure the necessary pyenv
directories ($PYENV_ROOT/{bin,shims}
) are in your PATH
. If Emacs has already inherited the correct PATH
, you can disable this behavior by setting:
(setq pyenv-set-path nil)
Note: this needs to be before you call (global-pyenv-mode)
You can use pyenv-mode-hook
to do things when you change your pyenv. This can be useful for updating code completion backends. For example, you could run elpy-rpc-restart
when you switch pyenv versions like so:
(add-hook 'pyenv-mode-hook 'elpy-rpc-restart)