I am new to emacs and try to learn some elisp to configure it.
I wanted to automatically activate a python virtual environment when entering elpy-mode
.
I have tried all kinds of variations of the following code
(use-package elpy
:init
(elpy-enable)
:config
(add-hook 'elpy-mode-hook
(lambda ()
(let* ((my-venv-root (locate-dominating-file buffer-file-name "venv"))
(my-venv (file-name-as-directory (file-name-concat my-venv-root "venv"))))
(message (concat "Venv Root: " my-venv-root))
(message (concat "Venv: " my-venv))
(when my-venv
(message "Try to activate Virtual Environment")
(pyvenv-activate my-venv))))))
The manual way M-x pyvenv-activate
RET
/path/to/project/venv
RET
followed by C-c C-c
works just fine.
But if I put the above code in my init.el
file I keep getting the Error Wrong type argument: stringp, nil
when trying to run a python file/buffer using C-c C-c
The messages yield correct looking values for my-venv-root
and my-venv
. For Example:
Venv Root: ~/Documents/Code/Test/
Venv: ~/Documents/Code/Test/venv/
Try to activate Virtual Environment
I am using Debian 12 with emacs 28.2 installed from the debian repositories.
I found a/the solution.
TL;DR:
Wrapped the code inside (when buffer-file-name ...
.
A little more detailed:
For some reason the elpy-mode-hook
gets called when C-c C-c
opens the Inferior Python Shell
(But C-h m
didn't show elpy
, ...).
It triggered the hook again with buffer-file-name
returning nil
, because the Inferior Python Shell
has no file name associated with it.
My solution was to wrap everything in (when buffer-file-name ...
.
So my - now working - config looks like that:
(use-package elpy
:init
(elpy-enable)
:config
(pyvenv-mode t)
(add-hook 'elpy-mode-hook
(lambda ()
(when buffer-file-name
(let* ((my-venv-root (locate-dominating-file buffer-file-name "venv"))
(my-venv (file-name-as-directory (file-name-concat my-venv-root "venv"))))
(message (concat "Venv Root: " my-venv-root))
(message (concat "Venv: " my-venv))
(when my-venv
(message "Try to activate Virtual Environment")
(pyvenv-activate my-venv)))))))
I do not fully understand how this could happen, 'cause this is what C-h m
gives me in the Inferior Python Shell
:
Enabled minor modes: Auto-Composition Auto-Compression Auto-Encryption
Blink-Cursor Company Compilation-Shell Display-Line-Numbers
Electric-Indent File-Name-Shadow Font-Lock Global-Company
Global-Display-Line-Numbers Global-Eldoc Global-Font-Lock
Global-Hl-Line Line-Number Menu-Bar Mouse-Wheel Override-Global Pyvenv
Recentf Save-Place Savehist Shell-Dirtrack Show-Paren Tool-Bar Tooltip
Transient-Mark Which-Key Windmove
(Information about these minor modes follows the major mode info.)
Inferior Python mode defined in ‘python.el’:
Major mode for Python inferior process.
Runs a Python interpreter as a subprocess of Emacs, with Python
I/O through an Emacs buffer. Variables ‘python-shell-interpreter’
and ‘python-shell-interpreter-args’ control which Python
interpreter is run. Variables
‘python-shell-prompt-regexp’,
‘python-shell-prompt-output-regexp’,
‘python-shell-prompt-block-regexp’,
‘python-shell-font-lock-enable’,
‘python-shell-completion-setup-code’,
‘python-shell-completion-string-code’,
‘python-eldoc-setup-code’, ‘python-eldoc-string-code’,
‘python-ffap-setup-code’ and ‘python-ffap-string-code’ can
customize this mode for different Python interpreters.
...
So no Elpy
here, like in C-h m
in a something.py
-Buffer:
Enabled minor modes: Auto-Composition Auto-Compression Auto-Encryption
Blink-Cursor Company Display-Line-Numbers Eldoc Electric-Indent Elpy
File-Name-Shadow Flymake Font-Lock Global-Company
Global-Display-Line-Numbers Global-Eldoc Global-Font-Lock
Global-Hl-Line Highlight-Indentation Line-Number Menu-Bar Mouse-Wheel
Override-Global Pyvenv Recentf Save-Place Savehist Shell-Dirtrack
Show-Paren Tool-Bar Tooltip Transient-Mark Which-Key Windmove Yas
(Information about these minor modes follows the major mode info.)
Python mode defined in ‘python.el’:
Major mode for editing Python files.
...
But it works for me.