aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes/python.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/progmodes/python.el')
-rw-r--r--lisp/progmodes/python.el151
1 files changed, 145 insertions, 6 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 895117b9ee3..d4226e5ce7b 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -2113,20 +2113,25 @@ remote host, the returned value is intended for
2113(defun python-shell-calculate-exec-path () 2113(defun python-shell-calculate-exec-path ()
2114 "Calculate `exec-path'. 2114 "Calculate `exec-path'.
2115Prepends `python-shell-exec-path' and adds the binary directory 2115Prepends `python-shell-exec-path' and adds the binary directory
2116for virtualenv if `python-shell-virtualenv-root' is set. If 2116for virtualenv if `python-shell-virtualenv-root' is set - this
2117`default-directory' points to a remote host, the returned value 2117will use the python interpreter from inside the virtualenv when
2118appends `python-shell-remote-exec-path' instead of `exec-path'." 2118starting the shell. If `default-directory' points to a remote host,
2119the returned value appends `python-shell-remote-exec-path' instead
2120of `exec-path'."
2119 (let ((new-path (copy-sequence 2121 (let ((new-path (copy-sequence
2120 (if (file-remote-p default-directory) 2122 (if (file-remote-p default-directory)
2121 python-shell-remote-exec-path 2123 python-shell-remote-exec-path
2122 exec-path)))) 2124 exec-path)))
2125
2126 ;; Windows and POSIX systems use different venv directory structures
2127 (virtualenv-bin-dir (if (eq system-type 'windows-nt) "Scripts" "bin")))
2123 (python-shell--add-to-path-with-priority 2128 (python-shell--add-to-path-with-priority
2124 new-path python-shell-exec-path) 2129 new-path python-shell-exec-path)
2125 (if (not python-shell-virtualenv-root) 2130 (if (not python-shell-virtualenv-root)
2126 new-path 2131 new-path
2127 (python-shell--add-to-path-with-priority 2132 (python-shell--add-to-path-with-priority
2128 new-path 2133 new-path
2129 (list (expand-file-name "bin" python-shell-virtualenv-root))) 2134 (list (expand-file-name virtualenv-bin-dir python-shell-virtualenv-root)))
2130 new-path))) 2135 new-path)))
2131 2136
2132(defun python-shell-tramp-refresh-remote-path (vec paths) 2137(defun python-shell-tramp-refresh-remote-path (vec paths)
@@ -5142,6 +5147,138 @@ returned as is."
5142 (ignore-errors (string-match regexp "") t)) 5147 (ignore-errors (string-match regexp "") t))
5143 5148
5144 5149
5150;;; Flymake integration
5151
5152(defgroup python-flymake nil
5153 "Integration between Python and Flymake."
5154 :group 'python
5155 :link '(custom-group-link :tag "Flymake" flymake)
5156 :version "26.1")
5157
5158(defcustom python-flymake-command '("pyflakes")
5159 "The external tool that will be used to perform the syntax check.
5160This is a non empty list of strings, the checker tool possibly followed by
5161required arguments. Once launched it will receive the Python source to be
5162checked as its standard input.
5163To use `flake8' you would set this to (\"flake8\" \"-\")."
5164 :group 'python-flymake
5165 :type '(repeat string))
5166
5167;; The default regexp accomodates for older pyflakes, which did not
5168;; report the column number, and at the same time it's compatible with
5169;; flake8 output, although it may be redefined to explicitly match the
5170;; TYPE
5171(defcustom python-flymake-command-output-pattern
5172 (list
5173 "^\\(?:<?stdin>?\\):\\(?1:[0-9]+\\):\\(?:\\(?2:[0-9]+\\):\\)? \\(?3:.*\\)$"
5174 1 2 nil 3)
5175 "Specify how to parse the output of `python-flymake-command'.
5176The value has the form (REGEXP LINE COLUMN TYPE MESSAGE): if
5177REGEXP matches, the LINE'th subexpression gives the line number,
5178the COLUMN'th subexpression gives the column number on that line,
5179the TYPE'th subexpression gives the type of the message and the
5180MESSAGE'th gives the message text itself.
5181
5182If COLUMN or TYPE are nil or that index didn't match, that
5183information is not present on the matched line and a default will
5184be used."
5185 :group 'python-flymake
5186 :type '(list regexp
5187 (integer :tag "Line's index")
5188 (choice
5189 (const :tag "No column" nil)
5190 (integer :tag "Column's index"))
5191 (choice
5192 (const :tag "No type" nil)
5193 (integer :tag "Type's index"))
5194 (integer :tag "Message's index")))
5195
5196(defcustom python-flymake-msg-alist
5197 '(("\\(^redefinition\\|.*unused.*\\|used$\\)" . :warning))
5198 "Alist used to associate messages to their types.
5199Each element should be a cons-cell (REGEXP . TYPE), where TYPE must be
5200one defined in the variable `flymake-diagnostic-types-alist'.
5201For example, when using `flake8' a possible configuration could be:
5202
5203 ((\"\\(^redefinition\\|.*unused.*\\|used$\\)\" . :warning)
5204 (\"^E999\" . :error)
5205 (\"^[EW][0-9]+\" . :note))
5206
5207By default messages are considered errors."
5208 :group 'python-flymake
5209 :type `(alist :key-type (regexp)
5210 :value-type (symbol)))
5211
5212(defvar-local python--flymake-proc nil)
5213
5214(defun python--flymake-parse-output (source proc report-fn)
5215 "Collect diagnostics parsing checker tool's output line by line."
5216 (let ((rx (nth 0 python-flymake-command-output-pattern))
5217 (lineidx (nth 1 python-flymake-command-output-pattern))
5218 (colidx (nth 2 python-flymake-command-output-pattern))
5219 (typeidx (nth 3 python-flymake-command-output-pattern))
5220 (msgidx (nth 4 python-flymake-command-output-pattern)))
5221 (with-current-buffer (process-buffer proc)
5222 (goto-char (point-min))
5223 (cl-loop
5224 while (search-forward-regexp rx nil t)
5225 for msg = (match-string msgidx)
5226 for (beg . end) = (flymake-diag-region
5227 source
5228 (string-to-number
5229 (match-string lineidx))
5230 (and colidx
5231 (match-string colidx)
5232 (string-to-number
5233 (match-string colidx))))
5234 for type = (or (and typeidx
5235 (match-string typeidx)
5236 (assoc-default
5237 (match-string typeidx)
5238 python-flymake-msg-alist
5239 #'string-match))
5240 (assoc-default msg
5241 python-flymake-msg-alist
5242 #'string-match)
5243 :error)
5244 collect (flymake-make-diagnostic
5245 source beg end type msg)
5246 into diags
5247 finally (funcall report-fn diags)))))
5248
5249(defun python-flymake (report-fn &rest _args)
5250 "Flymake backend for Python.
5251This backend uses `python-flymake-command' (which see) to launch a process
5252that is passed the current buffer's content via stdin.
5253REPORT-FN is Flymake's callback function."
5254 (unless (executable-find (car python-flymake-command))
5255 (error "Cannot find a suitable checker"))
5256
5257 (when (process-live-p python--flymake-proc)
5258 (kill-process python--flymake-proc))
5259
5260 (let ((source (current-buffer)))
5261 (save-restriction
5262 (widen)
5263 (setq python--flymake-proc
5264 (make-process
5265 :name "python-flymake"
5266 :noquery t
5267 :connection-type 'pipe
5268 :buffer (generate-new-buffer " *python-flymake*")
5269 :command python-flymake-command
5270 :sentinel
5271 (lambda (proc _event)
5272 (when (eq 'exit (process-status proc))
5273 (unwind-protect
5274 (when (with-current-buffer source
5275 (eq proc python--flymake-proc))
5276 (python--flymake-parse-output source proc report-fn))
5277 (kill-buffer (process-buffer proc)))))))
5278 (process-send-region python--flymake-proc (point-min) (point-max))
5279 (process-send-eof python--flymake-proc))))
5280
5281
5145(defun python-electric-pair-string-delimiter () 5282(defun python-electric-pair-string-delimiter ()
5146 (when (and electric-pair-mode 5283 (when (and electric-pair-mode
5147 (memq last-command-event '(?\" ?\')) 5284 (memq last-command-event '(?\" ?\'))
@@ -5255,7 +5392,9 @@ returned as is."
5255 (make-local-variable 'python-shell-internal-buffer) 5392 (make-local-variable 'python-shell-internal-buffer)
5256 5393
5257 (when python-indent-guess-indent-offset 5394 (when python-indent-guess-indent-offset
5258 (python-indent-guess-indent-offset))) 5395 (python-indent-guess-indent-offset))
5396
5397 (add-hook 'flymake-diagnostic-functions #'python-flymake nil t))
5259 5398
5260 5399
5261(provide 'python) 5400(provide 'python)