*layers/+lang/python: enahnce the virtual environment detection

This commit is contained in:
Lin Sun 2022-12-20 00:00:07 +00:00 committed by Maxi Wolff
parent b74da79dbb
commit 3afc9afa4c
4 changed files with 80 additions and 67 deletions

View File

@ -355,7 +355,7 @@ If you wish to be able to access these functionalities from other modes,
in your user config section, do: in your user config section, do:
#+BEGIN_SRC elisp #+BEGIN_SRC elisp
(add-to-list 'spacemacs--python-pipenv-mode 'your-mode) (add-to-list 'spacemacs--python-pipenv-modes 'your-mode)
#+END_SRC #+END_SRC
This will allow you to use [[https://github.com/pwalsh/pipenv.el][pipenv]] bindings from the mode your-mode. This will allow you to use [[https://github.com/pwalsh/pipenv.el][pipenv]] bindings from the mode your-mode.

View File

@ -95,6 +95,8 @@ Possible values are `on-visit', `on-project-switch' or `nil'.")
(defvar spacemacs--python-poetry-modes nil (defvar spacemacs--python-poetry-modes nil
"List of major modes where to add poetry support.") "List of major modes where to add poetry support.")
(defvar spacemacs--python-shell-interpreter-origin nil
"Origin python-shell-interpreter value.")
;; inferior-python-mode needs these variables to be defined. The python ;; inferior-python-mode needs these variables to be defined. The python
;; package declares them but does not initialize them. ;; package declares them but does not initialize them.
(defvar python-shell--interpreter nil) (defvar python-shell--interpreter nil)

View File

@ -150,35 +150,46 @@ as the pyenv version then also return nil. This works around https://github.com/
executable)) executable))
(executable-find command))) (executable-find command)))
(defun spacemacs//python-setup-shell (&rest args) (defun spacemacs//python-setup-shell (&optional root-dir)
(if (spacemacs/pyenv-executable-find "ipython") "Setup the python shell if no customer prefered value or the value be cleaned.
(progn ROOT-DIR should be the directory path for the environment, `nil' for clean up."
(setq python-shell-interpreter "ipython") (when (or (null python-shell-interpreter)
(let ((version (replace-regexp-in-string "\\(\\.dev\\)?[\r\n|\n]$" "" (equal python-shell-interpreter spacemacs--python-shell-interpreter-origin))
(shell-command-to-string (if-let* ((root-dir)
(format "\"%s\" --version" (default-directory root-dir))
(string-trim (spacemacs/pyenv-executable-find "ipython"))))))) (if-let* ((ipython (spacemacs/pyenv-executable-find "ipython"))
(if (or (version< version "5") (version (replace-regexp-in-string
(string-blank-p version)) "\\(\\.dev\\)?[\r\n|\n]$" ""
(setq python-shell-interpreter-args "-i") (shell-command-to-string (format "\"%s\" --version" ipython)))))
(setq python-shell-interpreter-args "--simple-prompt -i")))) (setq-local python-shell-interpreter ipython
(progn python-shell-interpreter-args
(setq python-shell-interpreter-args "-i" (concat "-i" (unless (version< version "5") " --simple-prompt")))
python-shell-interpreter "python")))) ;; else try python3 or python
(setq-local python-shell-interpreter
(or (spacemacs/pyenv-executable-find "python3")
(spacemacs/pyenv-executable-find "python")
"python3")
python-shell-interpreter-args "-i"))
;; args is nil, clean up the variables
(setq-local python-shell-interpreter nil
python-shell-interpreter-args nil))))
(defun spacemacs//python-setup-checkers (&optional root-dir)
(defun spacemacs//python-setup-checkers (&rest args) "Setup the checkers.
ROOT-DIR should be the path for the environemnt, `nil' for clean up"
(when (fboundp 'flycheck-set-checker-executable) (when (fboundp 'flycheck-set-checker-executable)
(let ((pylint (spacemacs/pyenv-executable-find "pylint")) (if-let* ((root-dir)
(flake8 (spacemacs/pyenv-executable-find "flake8"))) (default-directory root-dir))
(when pylint (dolist (x '("pylint" "flake8"))
(flycheck-set-checker-executable "python-pylint" pylint)) (when-let ((exe (spacemacs/pyenv-executable-find x)))
(when flake8 (flycheck-set-checker-executable (concat "python-" x) exe)))
(flycheck-set-checker-executable "python-flake8" flake8))))) ;; else root-dir is nil
(dolist (x '("pylint" "flake8"))
(set (flycheck-checker-executable-variable (concat "python-" x)) nil)))))
(defun spacemacs/python-setup-everything (&rest args) (defun spacemacs/python-setup-everything (&optional root-dir)
(apply 'spacemacs//python-setup-shell args) (apply 'spacemacs//python-setup-shell root-dir)
(apply 'spacemacs//python-setup-checkers args)) (apply 'spacemacs//python-setup-checkers root-dir))
(defun spacemacs/python-toggle-breakpoint () (defun spacemacs/python-toggle-breakpoint ()
"Add a break point, highlight it." "Add a break point, highlight it."
@ -219,22 +230,20 @@ as the pyenv version then also return nil. This works around https://github.com/
(defun spacemacs//pyenv-mode-set-local-version () (defun spacemacs//pyenv-mode-set-local-version ()
"Set pyenv version from \".python-version\" by looking in parent directories." "Set pyenv version from \".python-version\" by looking in parent directories."
(interactive) (interactive)
(let ((root-path (locate-dominating-file default-directory (when-let* ((root-path (locate-dominating-file default-directory
".python-version"))) ".python-version"))
(when root-path (file-path (expand-file-name ".python-version" root-path))
(let* ((file-path (expand-file-name ".python-version" root-path)) (version
(version (with-temp-buffer
(with-temp-buffer (insert-file-contents-literally file-path)
(insert-file-contents-literally file-path) (nth 0 (split-string (buffer-substring-no-properties
(nth 0 (split-string (buffer-substring-no-properties (line-beginning-position)
(line-beginning-position) (line-end-position)))))))
(line-end-position))))))) (cond ((member version (pyenv-mode-versions))
(if (member version (pyenv-mode-versions)) (setenv "VIRTUAL_ENV" version)
(progn (pyenv-mode-set version))
(setenv "VIRTUAL_ENV" version) (t (message "pyenv: version `%s' is not installed (set by %s)"
(pyenv-mode-set version)) version file-path)))))
(message "pyenv: version `%s' is not installed (set by %s)"
version file-path))))))
(defun spacemacs//pyvenv-mode-set-local-virtualenv () (defun spacemacs//pyvenv-mode-set-local-virtualenv ()
"Set pyvenv virtualenv from \".venv\" by looking in parent directories. "Set pyvenv virtualenv from \".venv\" by looking in parent directories.
@ -242,25 +251,25 @@ Handle \".venv\" being a virtualenv directory or a file specifying either
absolute or relative virtualenv path. Relative path is checked relative to absolute or relative virtualenv path. Relative path is checked relative to
location of \".venv\" file, then relative to pyvenv-workon-home()." location of \".venv\" file, then relative to pyvenv-workon-home()."
(interactive) (interactive)
(let ((root-path (locate-dominating-file default-directory ".venv"))) (when-let* ((root-path (locate-dominating-file default-directory ".venv"))
(when root-path (file-path (expand-file-name ".venv" root-path)))
(let ((file-path (expand-file-name ".venv" root-path))) (cond ((file-directory-p file-path)
(cond ((file-directory-p file-path) (pyvenv-activate file-path)
(pyvenv-activate file-path) (setq-local pyvenv-activate file-path)) (setq-local pyvenv-activate file-path))
(t (let* ((virtualenv-path-in-file (t (let* ((virtualenv-path-in-file
(with-temp-buffer (with-temp-buffer
(insert-file-contents-literally file-path) (insert-file-contents-literally file-path)
(buffer-substring-no-properties (line-beginning-position) (buffer-substring-no-properties (line-beginning-position)
(line-end-position)))) (line-end-position))))
(virtualenv-abs-path (virtualenv-abs-path
(if (file-name-absolute-p virtualenv-path-in-file) (if (file-name-absolute-p virtualenv-path-in-file)
virtualenv-path-in-file virtualenv-path-in-file
(format "%s/%s" root-path virtualenv-path-in-file)))) (format "%s/%s" root-path virtualenv-path-in-file))))
(cond ((file-directory-p virtualenv-abs-path) (cond ((file-directory-p virtualenv-abs-path)
(pyvenv-activate virtualenv-abs-path) (pyvenv-activate virtualenv-abs-path)
(setq-local pyvenv-activate virtualenv-abs-path)) (setq-local pyvenv-activate virtualenv-abs-path))
(t (pyvenv-workon virtualenv-path-in-file) (t (pyvenv-workon virtualenv-path-in-file)
(setq-local pyvenv-workon virtualenv-path-in-file)))))))))) (setq-local pyvenv-workon virtualenv-path-in-file))))))))
;; Tests ;; Tests

View File

@ -319,7 +319,10 @@
'spacemacs//pyenv-mode-set-local-version))) 'spacemacs//pyenv-mode-set-local-version)))
;; setup shell correctly on environment switch ;; setup shell correctly on environment switch
(dolist (func '(pyenv-mode-set pyenv-mode-unset)) (dolist (func '(pyenv-mode-set pyenv-mode-unset))
(advice-add func :after 'spacemacs/python-setup-everything)) (advice-add func :after
#'(lambda (&optional version)
(spacemacs/python-setup-everything
(when args (pyenv-mode-full-path version))))))
(spacemacs/set-leader-keys-for-major-mode 'python-mode (spacemacs/set-leader-keys-for-major-mode 'python-mode
"vu" 'pyenv-mode-unset "vu" 'pyenv-mode-unset
"vs" 'pyenv-mode-set)))) "vs" 'pyenv-mode-set))))
@ -387,10 +390,7 @@
'spacemacs/python-start-or-switch-repl "python") 'spacemacs/python-start-or-switch-repl "python")
(spacemacs//bind-python-repl-keys) (spacemacs//bind-python-repl-keys)
(add-hook 'python-mode-local-vars-hook 'spacemacs//python-setup-backend) (add-hook 'python-mode-local-vars-hook 'spacemacs//python-setup-backend)
(add-hook 'python-mode-hook 'spacemacs//python-default) (add-hook 'python-mode-hook 'spacemacs//python-default))
;; call `spacemacs//python-setup-shell' once, don't put it in a hook
;; (see issue #5988)
(spacemacs//python-setup-shell))
:config :config
(progn (progn
;; add support for `ahs-range-beginning-of-defun' for python-mode ;; add support for `ahs-range-beginning-of-defun' for python-mode
@ -424,6 +424,8 @@
"sl" 'spacemacs/python-shell-send-line "sl" 'spacemacs/python-shell-send-line
"ss" 'spacemacs/python-shell-send-with-output) "ss" 'spacemacs/python-shell-send-with-output)
(setq spacemacs--python-shell-interpreter-origin
(eval (car (get 'python-shell-interpreter 'standard-value))))
;; Set `python-indent-guess-indent-offset' to `nil' to prevent guessing `python-indent-offset ;; Set `python-indent-guess-indent-offset' to `nil' to prevent guessing `python-indent-offset
;; (we call python-indent-guess-indent-offset manually so python-mode does not need to do it) ;; (we call python-indent-guess-indent-offset manually so python-mode does not need to do it)
(setq-default python-indent-guess-indent-offset nil) (setq-default python-indent-guess-indent-offset nil)