Use python shell from virtual environment if there is one in Emacs
About a week ago, I made a function to use python from a virtual environment if there existed a directory called venv within the project the file is inside. This works for me since I tend to call virtual environment directories venv. The point of the function is to get access to the packages within that virtual environment when using the python shell to evaluate code from a file or interact with its functions, classes and variables through the REPL. I usually write my code and then test it through the REPL and do the necessary adjustments when there are mistakes. (I probably do this since I learned basic programming principles by teaching myself HyperTalk by reading the Help stack and experimenting in the Message Box (a REPL) in HyperCard in the late 80s.) I think a lot of people overlook this great way of working in interpreted languages.
Today, I had a look at that function again. I thought it would be really nice if I could find the python executable within a virtual environment no matter what the virtual environment directory is called. I found that this would work:
(defun einar-python-virtualenv () "Sets the python shell to python from a virtual environment if one exists." (when (project-current) (let ((pythonpath (nth 0 (directory-files-recursively (nth 2 (project-current)) (if (eq system-type 'gnu/linux) "python$" "python.exe$"))))) (when (file-exists-p pythonpath) (setq-local python-shell-interpreter pythonpath)))))
I need to run this function whenever I open a python file to set the correct path to the python shell for that file. This is done by adding the function to the python-mode hook like this since the mode hook is run every time you open a python file:
(add-hook 'python-mode-hook 'einar-python-virtualenv))
With this in place, whenever I open a python shell with C-c C-p from a python file, I get a python shell from within the virtual environment of that file's project, or I get the system python if there isn't a virtual environment within the project the file is part of.