hope you are all well.
Before stating problem, let me tell you my setup. I am using Emacs 27.1
, using pyvenv
, projectile
, lsp-mode
, lsp-python-ms
for python-mode
. I have set WORKON_HOME
environmental variable to ~/.pyenv/versions
and created an env named venv3.8
. I can activate the venv using <M-x> pyvenv-workon <RET> venv3.8 <RET>
. After that i can start lsp with lsp
command.
My idea was to set virtualenv (using pyvenv-workon
) automatically upon opening a project (python project) or opening a python script (not part of a project). So the concept was like this -
- If a project is opened, meaning
projectile-project-name
is available first check if there is a virtualenv with the same name, if thats available activate it. If thats not available check a special variable (which i set withdefcustom
) namepython-env-name
for a hint, now if the specified env is available then activate it. Else do nothing. - If a standalone script is opened, then check if
pyhton-env-name
for a hint, if the specified env is available, activate it. Else do nothing. - After activating the virtualenv, start lsp-mode.
The custom variable python-env-name
is supposed to be available to set in a .dir-local.el
so that i can easily set per project venv if necessary.
Here is my current code -
(defcustom python-env-name "venv"
"Set the virtualenv name to be used.
The virtualenv name is the folder name of a virtualenv
located under WORKON_HOME directory. It is set to be
~/.pyenv/versions."
:type 'string
:tag "Python Virtual Environment Name"
:group 'python
:safe 'stringp)
(defun my/log (message)
"Log MESSAGE to *my-logs* buffer.
MESSAGE is string value."
(interactive "sMessage: ")
(if (stringp message)
(with-current-buffer (get-buffer-create "*my-logs*")
(insert message))))
(defun my/activate-venv-for-project ()
"Activates virtualenv for current project."
(let ((project-venv-path (concat (getenv "WORKON_HOME") "/"
projectile-project-name))
(default-venv-path (concat (getenv "WORKON_HOME") "/"
(buffer-local-value 'python-env-name (current-buffer)))))
(my/log (format "Project venv: %s, found: %s\n" project-venv-path
(file-directory-p project-venv-path)))
(my/log (format "Default venv: %s, found: %s\n" default-venv-path
(file-directory-p default-venv-path)))
(if (file-directory-p project-venv-path)
(pyvenv-workon projectile-project-name)
(if (file-directory-p default-venv-path)
(pyvenv-workon python-env-name)))))
(defun my/activate-venv-for-script ()
"Activate virtualenv for a standalone script."
(let ((default-venv-path (concat (getenv "WORKON_HOME") "/"
(buffer-local-value 'python-env-name (current-buffer)))))
(my/log (format "Script default venv: %s, found: %s\n" default-venv-path
(file-directory-p default-venv-path)))
(if (file-directory-p default-venv-path)
(pyvenv-workon python-env-name))))
(defun my/setup-python-environment ()
"Setup the python virtual env for project or python script.
This function first checks if we opened a project, if so either the
virtualenv named as the projectile-project-name or the value of
python-env-name will be used to activate virtualenv. If none are
aviable no virtualenv will be activated. If we didnt open any
project, then simply check the python-env-name variable, if
the env is available then activate it or not. Afterwards it will
start up lsp-mode."
(interactive)
(hack-local-variables-apply)
(hack-dir-local-variables)
(if (bound-and-true-p projectile-project-name)
(my/activate-venv-for-project)
(my/activate-venv-for-script))
(require 'lsp-python-ms)
(lsp))
(add-hook 'python-mode-hook 'my/setup-python-environment)
As you can see, i tried to show some message while setting up the environment. Then i opened a python project (using projectile), and opened a python file. I have already set the python-env-name
in a dir-local file as follows -
((python-mode . ((python-env-name . "venv3.8"))))
Here is the text from *my-logs*
buffer -
Project venv: ~/.pyenv/versions/python-check, found: nil
Default venv: ~/.pyenv/versions/venv, found: nil
So clearly, the dir-local value is not used in the my/setup-python-environment
. But if i put the cursor at the python file and run <M-x> eval-expression <RET> python-env-name <RET>
it shows "venv3.8"
in the minibuffer. So the dir local variables are read. What am i doing wrong? Please help. Forgive my if i am doing anything wrong as i am very new to elisp. Thanks in advance. I hope i was clear enough.