linluk
linluk

Reputation: 1670

automatically call pyvenv-activate on elpy-mode-hook

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.

Upvotes: 0

Views: 180

Answers (1)

linluk
linluk

Reputation: 1670

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.

Upvotes: 0

Related Questions