From 02d97f2b2f6b078aa5e4cfd6174d5f5d62558021 Mon Sep 17 00:00:00 2001 From: Jeremy Dormitzer Date: Tue, 28 Apr 2020 12:52:41 -0400 Subject: [PATCH] Improve python venv handling --- emacs/init.org | 165 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 115 insertions(+), 50 deletions(-) diff --git a/emacs/init.org b/emacs/init.org index 248032e..afc3cdf 100755 --- a/emacs/init.org +++ b/emacs/init.org @@ -2820,8 +2820,8 @@ Emacs support for the Language Server Protocol #+END_SRC * Python +** General #+BEGIN_SRC emacs-lisp - ;; (leader-def-key "sp" #'elpy-shell-switch-to-shell) (leader-def-key "sp" #'run-python) (add-hook 'python-mode-hook #'disable-tab-insert) #+END_SRC @@ -2845,37 +2845,6 @@ Font-lock for f-strings: (0 font-lock-variable-name-face t))))))) #+END_SRC - -Elpy is a python IDE package: -#+BEGIN_SRC emacs-lisp :tangle no - (use-package elpy - :init (elpy-enable) - :config (setq elpy-rpc-python-command "python3")) -#+END_SRC - -Alternatively, use the LSP python client: -#+BEGIN_SRC emacs-lisp - (add-hook 'python-mode-hook #'lsp-deferred) - (general-def 'normal python-mode-map "C-c C-d" #'lsp-describe-thing-at-point) -#+END_SRC - -Support pyvenv within Emacs: -#+BEGIN_SRC emacs-lisp - (use-package pyvenv - :commands (pyvenv-mode pyvenv-workon pyvenv-activate) - :init - (add-hook 'after-init-hook #'pyvenv-mode)) - - (defun eshell/workon (name) - (pyvenv-workon name)) - - (defun eshell/activate (dir) - (pyvenv-activate dir)) - - (defun eshell/deactivate () - (pyvenv-deactivate)) -#+END_SRC - ISort is a Python utility to sort imports: #+BEGIN_SRC emacs-lisp (use-package py-isort @@ -2886,24 +2855,6 @@ ISort is a Python utility to sort imports: (python-mode-map "C-c C-i" #'py-isort-buffer)) #+END_SRC -Pipenv is the Python standard dependency management/virtual environment tool. pipenv.el teaches Emacs its ways: -#+BEGIN_SRC emacs-lisp - (use-package pipenv - :hook (python-mode . pipenv-mode) - :commands (pipenv-mode - pipenv-activate - pipenv-run)) -#+END_SRC - -A function to run a pipenv-aware python repl: -#+BEGIN_SRC emacs-lisp - (defun run-pipenv () - "Runs a pipenv-aware Python shell" - (interactive) - (pipenv-activate) - (run-python nil nil t)) -#+END_SRC - Run black on the current buffer: #+BEGIN_SRC emacs-lisp (general-def 'normal python-mode-map "C-M-\\" #'format-all-buffer) @@ -2915,12 +2866,126 @@ Run black on the current buffer: :hook ((python-mode . sphinx-doc-mode))) #+END_SRC +** Dev environment/IDE stuff +Support pyvenv within Emacs: +#+BEGIN_SRC emacs-lisp + (use-package pyvenv + :commands (pyvenv-mode + pyvenv-workon + pyvenv-activate + pyvenv-track-virtualenv)) + + (defun eshell/workon (name) + (pyvenv-workon name)) + + (defun eshell/activate (dir) + (pyvenv-activate dir)) + + (defun eshell/deactivate () + (pyvenv-deactivate)) +#+END_SRC + +Pipenv is a dependency management/virtual environment tool. pipenv.el teaches Emacs its ways: +#+BEGIN_SRC emacs-lisp + (use-package pipenv + :commands (pipenv-mode + pipenv-activate + pipenv-run) + :custom + (pipenv-with-projectile nil) + (pipenv-with-flycheck nil)) +#+END_SRC + And support pyenv (NOT pyvenv) to change Python versions: #+BEGIN_SRC emacs-lisp (use-package pyenv-mode :defer t) #+END_SRC +Add a hook to set the correct python for the current buffer: +#+BEGIN_SRC emacs-lisp + (defvar python-buffer-venv nil) + (make-variable-buffer-local 'python-buffer-venv) + + (defun save-buffer-venv (&rest args) + (setq python-buffer-venv pyvenv-virtual-env)) + + (advice-add 'pyvenv-activate :after #'save-buffer-venv) + (advice-add 'pyvenv-workon :after #'save-buffer-venv) + (advice-add 'pyvenv-track-virtualenv :after #'save-buffer-venv) + + (defun activate-buffer-venv () + "Activates the virtualenv that was previously set in this buffer." + (when (and python-buffer-venv + (not (eq python-buffer-venv pyvenv-virtual-env))) + (pyvenv-activate python-buffer-venv))) + + (defun maybe-activate-venv () + "Activates the virtual env for the current buffer if one exists. + Returns `t' if a venv was activated." + (interactive) + (cond + ((pipenv-activate) t) + ((or pyvenv-activate pyvenv-workon) + (progn (pyvenv-track-virtualenv) t)))) + + (defun activate-venv-post-command () + (ignore-errors (activate-buffer-venv))) + + (define-minor-mode python-env-mode + "Global minor mode to track Python environment." + :global t + (cond + (python-env-mode + (add-to-list 'mode-line-misc-info '(python-env-mode pyvenv-mode-line-indicator)) + (add-hook 'hack-local-variables-hook #'maybe-activate-venv) + (add-hook 'post-command-hook #'activate-venv-post-command)) + ((not python-env-mode) + (setq mode-line-misc-info (delete '(python-env-mode pyvenv-mode-line-indicator) + mode-line-misc-info)) + (remove-hook 'hack-local-variable-hook #'maybe-activate-venv) + (remove-hook 'post-command-hook #'activate-venv-post-command)))) + + (add-hook 'after-init-hook #'python-env-mode) +#+END_SRC + +Use the LSP python client: +#+BEGIN_SRC emacs-lisp + (defun python-lsp () + "Activates the project virtualenv if one exists then runs LSP." + (interactive) + (maybe-activate-venv) + (lsp-deferred)) + + (add-hook 'python-mode-hook #'python-lsp) + + (general-def 'normal python-mode-map "C-c C-d" #'lsp-describe-thing-at-point) +#+END_SRC + +Fix the doom-modeline Python display for Pipenv projects: +#+BEGIN_SRC emacs-lisp + (with-eval-after-load 'doom-modeline-env + (doom-modeline-def-env python + :hooks 'python-mode-hook + :command (lambda () + (let ((old (getenv "PIPENV_VERBOSITY"))) + (setenv "PIPENV_VERBOSITY" "-1") + (cond ((and (fboundp 'pipenv-project-p) + (pipenv-project-p)) + (list "pipenv" "run" + (or doom-modeline-env-python-executable + python-shell-interpreter + "python") + "--version")) + ((list (or doom-modeline-env-python-executable + python-shell-interpreter + "python") + "--version"))) + (setenv "PIPENV_VERBOSITY" old))) + :parser (lambda (line) (cadr (split-string line))))) +#+END_SRC + + ** Autoflake [[https://pypi.org/project/autoflake/][Autoflake]] is a tool that removes unused imports and variables from Python code: #+BEGIN_SRC emacs-lisp