GNU bug report logs - #28808
[PATCH] Implement Python backend for Flymake

Previous Next

Package: emacs;

Reported by: Lele Gaifax <lele <at> metapensiero.it>

Date: Fri, 13 Oct 2017 09:55:02 UTC

Severity: wishlist

Tags: fixed, patch

Fixed in version 26.1

Done: joaotavora <at> gmail.com (João Távora)

Bug is archived. No further changes may be made.

To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 28808 in the body.
You can then email your comments to 28808 AT debbugs.gnu.org in the normal way.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-gnu-emacs <at> gnu.org:
bug#28808; Package emacs. (Fri, 13 Oct 2017 09:55:03 GMT) Full text and rfc822 format available.

Acknowledgement sent to Lele Gaifax <lele <at> metapensiero.it>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs <at> gnu.org. (Fri, 13 Oct 2017 09:55:03 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Lele Gaifax <lele <at> metapensiero.it>
To: bug-gnu-emacs <at> gnu.org
Subject: [PATCH] Implement Python backend for Flymake
Date: Fri, 13 Oct 2017 11:54:13 +0200
[Message part 1 (text/plain, inline)]
Hi,

here below you can find an implementation of a Python backend for the new
Flymake facility.

I'm quite satisfied by it: I tested both the default settings (targeting
`pyflakes') and the `flake8' customization suggested in the docstrings.

As always, I'm willing to apply whatever tweak/fix you may find reasonable.

Thanks a lot,
ciao, lele.

[0001-Fix-typo.patch (text/x-diff, inline)]
From 16828afebe3e732e3cbf856b093dfff65d3319ff Mon Sep 17 00:00:00 2001
From: Lele Gaifax <lele <at> metapensiero.it>
Date: Fri, 13 Oct 2017 10:43:13 +0200
Subject: [PATCH 1/2] Fix typo

---
 lisp/progmodes/flymake.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el
index 8c9c4b211a..8fa763a4b8 100644
--- a/lisp/progmodes/flymake.el
+++ b/lisp/progmodes/flymake.el
@@ -124,7 +124,7 @@ flymake-gui-warnings-enabled
 			"it no longer has any effect." "26.1")
 
 (defcustom flymake-start-on-flymake-mode t
-  "Start syntax check when `flymake-mode'is enabled.
+  "Start syntax check when `flymake-mode' is enabled.
 Specifically, start it when the buffer is actually displayed."
   :type 'boolean)
 
-- 
2.15.0.rc0

[0002-Add-a-Flymake-backend-for-Python.patch (text/x-diff, inline)]
From 84a4dd4ef7a6ae9e49cb7442070744b5d6e3ec95 Mon Sep 17 00:00:00 2001
From: Lele Gaifax <lele <at> metapensiero.it>
Date: Fri, 13 Oct 2017 10:44:02 +0200
Subject: [PATCH 2/2] Add a Flymake backend for Python

* lisp/progmodes/python.el: Implement new Flymake backend with
  related customizable settings.
  (python-flymake-command, python-flymake-command-output-regexp,
   python-flymake-msg-alist): New defcustom.
  (python-flymake): New function.
  (python-flymake-activate): New function.
---
 lisp/progmodes/python.el | 101 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 101 insertions(+)

diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index f79d9a47d3..866e02ffbd 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -5141,6 +5141,107 @@ python-util-valid-regexp-p
   (ignore-errors (string-match regexp "") t))
 
 
+;;; Flymake integration
+
+(defgroup python-flymake nil
+  "Integration between Python and Flymake."
+  :group 'python
+  :link '(custom-group-link :tag "Flymake" flymake)
+  :version "26.1")
+
+(defcustom python-flymake-command '("pyflakes")
+  "The external tool that will be used to perform the syntax check.
+This is a non empty list of strings, the checker tool possibly followed by
+required arguments: to use `flake8' you would set this to (\"flake8\" \"-\")."
+  :group 'python-flymake
+  :type '(repeat string))
+
+;; The default regexp accomodates for older pyflakes, which did not
+;; report the column number
+(defcustom python-flymake-command-output-regexp
+  "^\\(?:<stdin>\\):\\(?1:[0-9]+\\):\\(?:\\(?2:[0-9]+\\):\\)? \\(?3:.*\\)$"
+  "The regexp used to parse the output of the specified tool.
+It must contain two or three groups: group 1 is the line number, group 2 the
+optional column number and the third is the actual message."
+  :group 'python-flymake
+  :type 'regexp)
+
+(defcustom python-flymake-msg-alist
+  '(("\\(^redefinition\\|.*unused.*\\|used$\\)" . :warning))
+  "Alist used to associate messages to their types.
+Each element should be a cons-cell (REGEXP . TYPE), where TYPE must be
+one defined in the variable `flymake-diagnostic-types-alist'.
+For example, when using `flake8' a possible configuration could be:
+
+  ((\"\\(^redefinition\\|.*unused.*\\|used$\\)\" . :warning)
+   (\"^E999\" . :error)
+   (\"^[EW][0-9]+\" . :note))
+
+By default messages are considered errors."
+  :group 'python-flymake
+  :type `(alist :key-type (regexp)
+                :value-type (symbol)))
+
+(defvar-local python--flymake-proc nil)
+
+(defun python-flymake (report-fn &rest _args)
+  "Flymake backend for Python.
+This backend uses `python-flymake-command' (which see) to launch a process
+that is passed the current buffer's content via stdin.
+REPORT-FN is Flymake's callback function."
+  (unless (executable-find (car python-flymake-command))
+    (error "Cannot find a suitable checker"))
+
+  (unless (derived-mode-p 'python-mode)
+    (error "Can only work on `python-mode' buffers"))
+
+  (when (process-live-p python--flymake-proc)
+    (kill-process python--flymake-proc))
+
+  (let ((source (current-buffer)))
+    (save-restriction
+      (widen)
+      (setq python--flymake-proc
+            (make-process
+             :name "python-flymake"
+             :noquery t
+             :connection-type 'pipe
+             :buffer (generate-new-buffer " *python-flymake*")
+             :command python-flymake-command
+             :sentinel
+             (lambda (proc _event)
+               (when (eq 'exit (process-status proc))
+                 (unwind-protect
+                     (when (eq proc python--flymake-proc)
+                       (with-current-buffer (process-buffer proc)
+                         (goto-char (point-min))
+                         (cl-loop
+                          while (search-forward-regexp
+                                 python-flymake-command-output-regexp nil t)
+                          for msg = (match-string 3)
+                          for (beg . end) = (flymake-diag-region
+                                             source
+                                             (string-to-number (match-string 1))
+                                             (and (match-string 2)
+                                                  (string-to-number
+                                                   (match-string 2))))
+                          for type = (or (assoc-default msg
+                                                        python-flymake-msg-alist
+                                                        #'string-match)
+                                         :error)
+                          collect (flymake-make-diagnostic
+                                   source beg end type msg)
+                          into diags
+                          finally (funcall report-fn diags))))
+                   (kill-buffer (process-buffer proc)))))))
+      (process-send-region python--flymake-proc (point-min) (point-max))
+      (process-send-eof python--flymake-proc))))
+
+(defun python-flymake-activate ()
+  "Activate the Flymake syntax check on all python-mode buffers."
+  (add-hook 'flymake-diagnostic-functions #'python-flymake nil t))
+
+
 (defun python-electric-pair-string-delimiter ()
   (when (and electric-pair-mode
              (memq last-command-event '(?\" ?\'))
-- 
2.15.0.rc0

[Message part 4 (text/plain, inline)]
-- 
nickname: Lele Gaifax | Quando vivrò di quello che ho pensato ieri
real: Emanuele Gaifas | comincerò ad aver paura di chi mi copia.
lele <at> metapensiero.it  |                 -- Fortunato Depero, 1929.

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#28808; Package emacs. (Fri, 13 Oct 2017 21:04:02 GMT) Full text and rfc822 format available.

Message #8 received at 28808 <at> debbugs.gnu.org (full text, mbox):

From: joaotavora <at> gmail.com (João Távora)
To: Lele Gaifax <lele <at> metapensiero.it>
Cc: 28808 <at> debbugs.gnu.org
Subject: Re: [PATCH] Implement Python backend for Flymake
Date: Fri, 13 Oct 2017 22:03:47 +0100
[ Sorry Lele if you're getting this twice, I mistankenly created
another bug #28821, let's continue here ]

Hi Lele,

Here are some comments:

Lele Gaifax <lele <at> metapensiero.it> writes:

> +(defgroup python-flymake nil
> +  "Integration between Python and Flymake."
> +  :group 'python
> +  :link '(custom-group-link :tag "Flymake" flymake)
> +  :version "26.1")
> +
> +(defcustom python-flymake-command '("pyflakes")
> +  "The external tool that will be used to perform the syntax check.
> +This is a non empty list of strings, the checker tool possibly followed by
> +required arguments: to use `flake8' you would set this to (\"flake8\" \"-\")."
>
I wonder if you shouldn't mention here that the command produced should,
once invoked, check (a file? a chunk?) of python source code passed to
it via its standard input.

> +  :group 'python-flymake
> +  :type '(repeat string))
> +
> +;; The default regexp accomodates for older pyflakes, which did not
> +;; report the column number
> +(defcustom python-flymake-command-output-regexp
> +  "^\\(?:<stdin>\\):\\(?1:[0-9]+\\):\\(?:\\(?2:[0-9]+\\):\\)? \\(?3:.*\\)$"
> +  "The regexp used to parse the output of the specified tool.
> +It must contain two or three groups: group 1 is the line number, group 2 the
> +optional column number and the third is the actual message."

A common trick here that old flymake (and also compile.el) use is to
define the variable's value as list (REGEXP LINE COLUMN TYPE
MESSAGE). REGEXP is mandatory. LINE, COLUMN, TYPE and MESSAGE are
non-negative integer numbers designating regexp groups, or nil. In the
latter case it means the regexp cannot capture that entity.

So in your case it would become

(defcustom python-flymake-command-output-regexp
  (list
    "^\\(?:<stdin>\\):\\(?1:[0-9]+\\):\\(?:\\(?2:[0-9]+\\):\\)? \\(?3:.*\\)$"
    1 2 nil 3)
  "docstring" :group 'python-flymake
  :type '(list string (choice integer symbol)
                      (choice integer symbol)
                      (choice integer symbol)
                      (choice integer symbol)))

Perhaps TYPE does not make much sense currently. But it would match
slightly better with compilation-error-regexp-alist in the future (which
you should see).

> +  (unless (derived-mode-p 'python-mode)
> +    (error "Can only work on `python-mode' buffers"))

Stefan and I arrived at the conclusion that this is cruft and isn't
needed. 

> +(defun python-flymake-activate ()

Rename this to python--flymake-setup, because "activation" is actually
enabling flymake-mode. Also, I think you should add an autoload cookie
to python--flymake-setup and then call that function from the end of
python-mode. The

> +  "Activate the Flymake syntax check on all python-mode buffers."
> +  (add-hook 'flymake-diagnostic-functions #'python-flymake nil t))

I'd use 'python-flymake instead of #'python-flymake in add-hook, but I
can't offer a sound reason why :-)

João




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#28808; Package emacs. (Sat, 14 Oct 2017 08:17:01 GMT) Full text and rfc822 format available.

Message #11 received at 28808 <at> debbugs.gnu.org (full text, mbox):

From: Lele Gaifax <lele <at> metapensiero.it>
To: João Távora <joaotavora <at> gmail.com>
Cc: 28808 <at> debbugs.gnu.org
Subject: Re: [PATCH] Implement Python backend for Flymake
Date: Sat, 14 Oct 2017 10:15:51 +0200
Thank you João!

joaotavora <at> gmail.com (João Távora) writes:

>> +(defcustom python-flymake-command '("pyflakes")
>> +  "The external tool that will be used to perform the syntax check.
>> +This is a non empty list of strings, the checker tool possibly followed by
>> +required arguments: to use `flake8' you would set this to (\"flake8\" \"-\")."
>>
> I wonder if you shouldn't mention here that the command produced should,
> once invoked, check (a file? a chunk?) of python source code passed to
> it via its standard input.

Ok, done.

>> +(defcustom python-flymake-command-output-regexp
>> +  "^\\(?:<stdin>\\):\\(?1:[0-9]+\\):\\(?:\\(?2:[0-9]+\\):\\)? \\(?3:.*\\)$"
>> +  "The regexp used to parse the output of the specified tool.
>> +It must contain two or three groups: group 1 is the line number, group 2 the
>> +optional column number and the third is the actual message."
>
> A common trick here that old flymake (and also compile.el) use is to
> define the variable's value as list (REGEXP LINE COLUMN TYPE
> MESSAGE).

I will try to better understand this, as I failed to see the benefit of adding
that indirection... maybe the compile.el functionality is older than the
ability to use explicit group numbers in the regexp?

>> +  (unless (derived-mode-p 'python-mode)
>> +    (error "Can only work on `python-mode' buffers"))
>
> Stefan and I arrived at the conclusion that this is cruft and isn't
> needed. 

Ok, removed.

>> +(defun python-flymake-activate ()
>
> Rename this to python--flymake-setup, because "activation" is actually
> enabling flymake-mode.

Ok, done.

> Also, I think you should add an autoload cookie
> to python--flymake-setup and then call that function from the end of
> python-mode. The

I'm curious here: why the need of autoload cookie, if the (only?) caller site
lives in the very same source file? And if that's not only caller, why marking
it private with the double dash?

More importantly: if we unconditionally activate the Flymake feature, instead
of being an user's choice, then the python--flymake-setup function may go
away, and the add-hook moved inside the python-mode function, it already
contains lot of those...

>> +  "Activate the Flymake syntax check on all python-mode buffers."
>> +  (add-hook 'flymake-diagnostic-functions #'python-flymake nil t))
>
> I'd use 'python-flymake instead of #'python-flymake in add-hook, but I
> can't offer a sound reason why :-)

Well, my habit is different here, and it's also the convention used by the
rest of python.el, so I will leave that as is.

See http://endlessparentheses.com/get-in-the-habit-of-using-sharp-quote.html
for what I considered a "sound reason" :)

ciao, lele.
-- 
nickname: Lele Gaifax | Quando vivrò di quello che ho pensato ieri
real: Emanuele Gaifas | comincerò ad aver paura di chi mi copia.
lele <at> metapensiero.it  |                 -- Fortunato Depero, 1929.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#28808; Package emacs. (Sat, 14 Oct 2017 09:15:02 GMT) Full text and rfc822 format available.

Message #14 received at 28808 <at> debbugs.gnu.org (full text, mbox):

From: joaotavora <at> gmail.com (João Távora)
To: Lele Gaifax <lele <at> metapensiero.it>
Cc: 28808 <at> debbugs.gnu.org
Subject: Re: bug#28808: [PATCH] Implement Python backend for Flymake
Date: Sat, 14 Oct 2017 10:14:31 +0100
Hi Lele,

Lele Gaifax <lele <at> metapensiero.it> writes:

>> A common trick here that old flymake (and also compile.el) use is to
>> define the variable's value as list (REGEXP LINE COLUMN TYPE
>> MESSAGE).
>
> I will try to better understand this, as I failed to see the benefit of adding
> that indirection... maybe the compile.el functionality is older than the
> ability to use explicit group numbers in the regexp?

The benefit is that if I switch to a checker that doesn't provide
COLUMN, for example, I won't be locked out with your
expression. Likewise if I do switch to a checker that emits errors where
I can clearly identify a TYPE.

> I'm curious here: why the need of autoload cookie, if the (only?) caller site
> lives in the very same source file? And if that's not only caller, why marking
> it private with the double dash?

Sorry for the noise. There is no need for the autoload cookie. I thought
you were changing a different file than flymake.

Don't use the cookie, use the double dash.
>
> More importantly: if we unconditionally activate the Flymake feature, instead
> of being an user's choice, then the python--flymake-setup function may go
> away, and the add-hook moved inside the python-mode function, it already
> contains lot of those...

That makes sense. But we don't (yet) "unconditionally activate" Flymake, we
simply set up the buffer so that a later activation of Flymake will be
met with agreeable conditions.

> See http://endlessparentheses.com/get-in-the-habit-of-using-sharp-quote.html
> for what I considered a "sound reason" :)

Obviously, I use sharp quote myself, just not in add-hook, as that is
the style I am familiar with. But if that is the style of python.el,
that's a good reason. It's not in the rest of emacs.

But I can explain what it bothered me: As you know, in the specific
Flymake-case, backends are functions. You might be tempted to put a
closure, like a (lambda (report-fn) ...) in
flymake-diagnostic-functions.

If you do that everything will work, except for the interactive messages
that mention names of backends, where intead of the name of the symbol
you see something very ugly like

#f(compiled-function (report-fn) #<bytecode 0x1d84599>)

So, for now, as a good practice, I thought it better to use just ' so as
not to encourage others to put closures there. 

Eventually, once function-put starts working for non-symbol functions
and I can set a name property there, closures will probably not only be
accepted but encouraged.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#28808; Package emacs. (Tue, 17 Oct 2017 21:59:01 GMT) Full text and rfc822 format available.

Message #17 received at 28808 <at> debbugs.gnu.org (full text, mbox):

From: Lele Gaifax <lele <at> metapensiero.it>
To: João Távora <joaotavora <at> gmail.com>
Cc: 28808 <at> debbugs.gnu.org
Subject: Re: bug#28808: [PATCH] Implement Python backend for Flymake
Date: Tue, 17 Oct 2017 23:58:08 +0200
[Message part 1 (text/plain, inline)]
Hi João,

I think I fulfilled all your suggestions/requests, and thus I'm re-attaching
the current version of the backend.

Please let me know if there's something more I can do, I will happily keep
hacking!

ciao, lele.
[0001-Add-a-Flymake-backend-for-Python.patch (text/x-diff, inline)]
From 4e61fa030704a5e7bfcd537c503cef1da4409b6b Mon Sep 17 00:00:00 2001
From: Lele Gaifax <lele <at> metapensiero.it>
Date: Fri, 13 Oct 2017 10:44:02 +0200
Subject: [PATCH] Add a Flymake backend for Python

* lisp/progmodes/python.el: Implement new Flymake backend with
  related customizable settings.
  (python-flymake-command, python-flymake-command-output-regexp,
   python-flymake-msg-alist): New defcustom.
  (python-flymake): New function.
  (python-flymake-activate): New function.
---
 lisp/progmodes/python.el | 135 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 135 insertions(+)

diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 895117b9ee..831fd7e7f2 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -5142,6 +5142,141 @@ python-util-valid-regexp-p
   (ignore-errors (string-match regexp "") t))
 
 
+;;; Flymake integration
+
+(defgroup python-flymake nil
+  "Integration between Python and Flymake."
+  :group 'python
+  :link '(custom-group-link :tag "Flymake" flymake)
+  :version "26.1")
+
+(defcustom python-flymake-command '("pyflakes")
+  "The external tool that will be used to perform the syntax check.
+This is a non empty list of strings, the checker tool possibly followed by
+required arguments.  Once launched it will receive the Python source to be
+checked as its standard input.
+To use `flake8' you would set this to (\"flake8\" \"-\")."
+  :group 'python-flymake
+  :type '(repeat string))
+
+;; The default regexp accomodates for older pyflakes, which did not
+;; report the column number, and at the same time it's compatible with
+;; flake8 output, although it may be redefined to explicitly match the
+;; TYPE
+(defcustom python-flymake-command-output-regexp
+  (list
+   "^\\(?:<?stdin>?\\):\\(?1:[0-9]+\\):\\(?:\\(?2:[0-9]+\\):\\)? \\(?3:.*\\)$"
+   1 2 nil 3)
+  "Specify how to parse the output of the specified tool.
+The value has the form (REGEXP LINE COLUMN TYPE MESSAGE): if
+REGEXP matches, the LINE'th subexpression gives the line number,
+the COLUMN'th subexpression gives the column number on that line,
+the TYPE'th subexpression gives the type of the message and
+MESSAGE'th is the message text itself.
+
+If COLUMN or TYPE are nil or that index didn't match, that
+information is not present on the matched line and a default will
+be used."
+  :group 'python-flymake
+  :type '(list regexp
+               (integer :tag "Line's index")
+               (choice
+                (const :tag "No column" nil)
+                (integer :tag "Column's index"))
+               (choice
+                (const :tag "No type" nil)
+                (integer :tag "Type's index"))
+               (integer :tag "Message's index")))
+
+(defcustom python-flymake-msg-alist
+  '(("\\(^redefinition\\|.*unused.*\\|used$\\)" . :warning))
+  "Alist used to associate messages to their types.
+Each element should be a cons-cell (REGEXP . TYPE), where TYPE must be
+one defined in the variable `flymake-diagnostic-types-alist'.
+For example, when using `flake8' a possible configuration could be:
+
+  ((\"\\(^redefinition\\|.*unused.*\\|used$\\)\" . :warning)
+   (\"^E999\" . :error)
+   (\"^[EW][0-9]+\" . :note))
+
+By default messages are considered errors."
+  :group 'python-flymake
+  :type `(alist :key-type (regexp)
+                :value-type (symbol)))
+
+(defvar-local python--flymake-proc nil)
+
+(defun python--flymake-parse-output (source proc report-fn)
+  "Collect diagnostics parsing checker tool's output line by line."
+  (let ((rx (nth 0 python-flymake-command-output-regexp))
+        (lineidx (nth 1 python-flymake-command-output-regexp))
+        (colidx (nth 2 python-flymake-command-output-regexp))
+        (typeidx (nth 3 python-flymake-command-output-regexp))
+        (msgidx (nth 4 python-flymake-command-output-regexp)))
+    (with-current-buffer (process-buffer proc)
+      (goto-char (point-min))
+      (cl-loop
+       while (search-forward-regexp rx nil t)
+       for msg = (match-string msgidx)
+       for (beg . end) = (flymake-diag-region
+                          source
+                          (string-to-number
+                           (match-string lineidx))
+                          (and colidx
+                               (match-string colidx)
+                               (string-to-number
+                                (match-string colidx))))
+       for type = (or (and typeidx
+                           (match-string typeidx)
+                           (assoc-default
+                            (match-string typeidx)
+                            python-flymake-msg-alist
+                            #'string-match))
+                      (assoc-default msg
+                                     python-flymake-msg-alist
+                                     #'string-match)
+                      :error)
+       collect (flymake-make-diagnostic
+                source beg end type msg)
+       into diags
+       finally (funcall report-fn diags)))))
+
+(defun python-flymake (report-fn &rest _args)
+  "Flymake backend for Python.
+This backend uses `python-flymake-command' (which see) to launch a process
+that is passed the current buffer's content via stdin.
+REPORT-FN is Flymake's callback function."
+  (unless (executable-find (car python-flymake-command))
+    (error "Cannot find a suitable checker"))
+
+  (when (process-live-p python--flymake-proc)
+    (kill-process python--flymake-proc))
+
+  (let ((source (current-buffer)))
+    (save-restriction
+      (widen)
+      (setq python--flymake-proc
+            (make-process
+             :name "python-flymake"
+             :noquery t
+             :connection-type 'pipe
+             :buffer (generate-new-buffer " *python-flymake*")
+             :command python-flymake-command
+             :sentinel
+             (lambda (proc _event)
+               (when (eq 'exit (process-status proc))
+                 (unwind-protect
+                     (when (eq proc python--flymake-proc)
+                       (python--flymake-parse-output source proc report-fn))
+                   (kill-buffer (process-buffer proc)))))))
+      (process-send-region python--flymake-proc (point-min) (point-max))
+      (process-send-eof python--flymake-proc))))
+
+(defun python-flymake-activate ()
+  "Activate the Flymake syntax check on all python-mode buffers."
+  (add-hook 'flymake-diagnostic-functions #'python-flymake nil t))
+
+
 (defun python-electric-pair-string-delimiter ()
   (when (and electric-pair-mode
              (memq last-command-event '(?\" ?\'))
-- 
2.15.0.rc1

[Message part 3 (text/plain, inline)]
-- 
nickname: Lele Gaifax | Quando vivrò di quello che ho pensato ieri
real: Emanuele Gaifas | comincerò ad aver paura di chi mi copia.
lele <at> metapensiero.it  |                 -- Fortunato Depero, 1929.

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#28808; Package emacs. (Tue, 17 Oct 2017 22:42:01 GMT) Full text and rfc822 format available.

Message #20 received at 28808 <at> debbugs.gnu.org (full text, mbox):

From: Lele Gaifax <lele <at> metapensiero.it>
To: 28808 <at> debbugs.gnu.org
Subject: Activation of the new backend
Date: Wed, 18 Oct 2017 00:41:28 +0200
Re-reading the patch I just sent, I see that one thing is still not the way
João suggested (and I'm quite surprised, since I'm pretty sure I *did* that:
by any chance the "git stash/fetch/merge upstream/stash pop" dance fooled
me...): he asked to rename `python-flymake-activate' to `python--flymake-setup'
and automatically call the latter from `python-mode'.

I will rectify that asap.

ciao, lele.
-- 
nickname: Lele Gaifax | Quando vivrò di quello che ho pensato ieri
real: Emanuele Gaifas | comincerò ad aver paura di chi mi copia.
lele <at> metapensiero.it  |                 -- Fortunato Depero, 1929.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#28808; Package emacs. (Wed, 18 Oct 2017 06:06:02 GMT) Full text and rfc822 format available.

Message #23 received at 28808 <at> debbugs.gnu.org (full text, mbox):

From: Lele Gaifax <lele <at> metapensiero.it>
To: 28808 <at> debbugs.gnu.org
Subject: Re: Activation of the new backend
Date: Wed, 18 Oct 2017 08:05:17 +0200
[Message part 1 (text/plain, inline)]
Ok, here is the patch again, sorry for the hiccup. I rectified also the commit
message, to reflect latest changes.

[0001-Add-a-Flymake-backend-for-Python.patch (text/x-diff, inline)]
From a2a6decfeb79a5b25a7193ec964f709232f1c784 Mon Sep 17 00:00:00 2001
From: Lele Gaifax <lele <at> metapensiero.it>
Date: Fri, 13 Oct 2017 10:44:02 +0200
Subject: [PATCH] Add a Flymake backend for Python

* lisp/progmodes/python.el: Implement new Flymake backend with
  related customizable settings.
  (python-flymake-command, python-flymake-command-output-regexp,
   python-flymake-msg-alist): New defcustom.
  (python--flymake-parse-output): New function, able to parse
  python-flymake-command output accordingly to
  python-flymake-command-output-regexp.
  (python--flymake): New function implementing the backend interface
  using python--flymake-parse-output for the real work.
  (python-mode): Add python--flymake to flymake-diagnostic-functions.
---
 lisp/progmodes/python.el | 135 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 134 insertions(+), 1 deletion(-)

diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 895117b9ee..ed9065e5d6 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -5142,6 +5142,137 @@ python-util-valid-regexp-p
   (ignore-errors (string-match regexp "") t))
 
 
+;;; Flymake integration
+
+(defgroup python-flymake nil
+  "Integration between Python and Flymake."
+  :group 'python
+  :link '(custom-group-link :tag "Flymake" flymake)
+  :version "26.1")
+
+(defcustom python-flymake-command '("pyflakes")
+  "The external tool that will be used to perform the syntax check.
+This is a non empty list of strings, the checker tool possibly followed by
+required arguments.  Once launched it will receive the Python source to be
+checked as its standard input.
+To use `flake8' you would set this to (\"flake8\" \"-\")."
+  :group 'python-flymake
+  :type '(repeat string))
+
+;; The default regexp accomodates for older pyflakes, which did not
+;; report the column number, and at the same time it's compatible with
+;; flake8 output, although it may be redefined to explicitly match the
+;; TYPE
+(defcustom python-flymake-command-output-regexp
+  (list
+   "^\\(?:<?stdin>?\\):\\(?1:[0-9]+\\):\\(?:\\(?2:[0-9]+\\):\\)? \\(?3:.*\\)$"
+   1 2 nil 3)
+  "Specify how to parse the output of the specified tool.
+The value has the form (REGEXP LINE COLUMN TYPE MESSAGE): if
+REGEXP matches, the LINE'th subexpression gives the line number,
+the COLUMN'th subexpression gives the column number on that line,
+the TYPE'th subexpression gives the type of the message and
+MESSAGE'th is the message text itself.
+
+If COLUMN or TYPE are nil or that index didn't match, that
+information is not present on the matched line and a default will
+be used."
+  :group 'python-flymake
+  :type '(list regexp
+               (integer :tag "Line's index")
+               (choice
+                (const :tag "No column" nil)
+                (integer :tag "Column's index"))
+               (choice
+                (const :tag "No type" nil)
+                (integer :tag "Type's index"))
+               (integer :tag "Message's index")))
+
+(defcustom python-flymake-msg-alist
+  '(("\\(^redefinition\\|.*unused.*\\|used$\\)" . :warning))
+  "Alist used to associate messages to their types.
+Each element should be a cons-cell (REGEXP . TYPE), where TYPE must be
+one defined in the variable `flymake-diagnostic-types-alist'.
+For example, when using `flake8' a possible configuration could be:
+
+  ((\"\\(^redefinition\\|.*unused.*\\|used$\\)\" . :warning)
+   (\"^E999\" . :error)
+   (\"^[EW][0-9]+\" . :note))
+
+By default messages are considered errors."
+  :group 'python-flymake
+  :type `(alist :key-type (regexp)
+                :value-type (symbol)))
+
+(defvar-local python--flymake-proc nil)
+
+(defun python--flymake-parse-output (source proc report-fn)
+  "Collect diagnostics parsing checker tool's output line by line."
+  (let ((rx (nth 0 python-flymake-command-output-regexp))
+        (lineidx (nth 1 python-flymake-command-output-regexp))
+        (colidx (nth 2 python-flymake-command-output-regexp))
+        (typeidx (nth 3 python-flymake-command-output-regexp))
+        (msgidx (nth 4 python-flymake-command-output-regexp)))
+    (with-current-buffer (process-buffer proc)
+      (goto-char (point-min))
+      (cl-loop
+       while (search-forward-regexp rx nil t)
+       for msg = (match-string msgidx)
+       for (beg . end) = (flymake-diag-region
+                          source
+                          (string-to-number
+                           (match-string lineidx))
+                          (and colidx
+                               (match-string colidx)
+                               (string-to-number
+                                (match-string colidx))))
+       for type = (or (and typeidx
+                           (match-string typeidx)
+                           (assoc-default
+                            (match-string typeidx)
+                            python-flymake-msg-alist
+                            #'string-match))
+                      (assoc-default msg
+                                     python-flymake-msg-alist
+                                     #'string-match)
+                      :error)
+       collect (flymake-make-diagnostic
+                source beg end type msg)
+       into diags
+       finally (funcall report-fn diags)))))
+
+(defun python--flymake (report-fn &rest _args)
+  "Flymake backend for Python.
+This backend uses `python-flymake-command' (which see) to launch a process
+that is passed the current buffer's content via stdin.
+REPORT-FN is Flymake's callback function."
+  (unless (executable-find (car python-flymake-command))
+    (error "Cannot find a suitable checker"))
+
+  (when (process-live-p python--flymake-proc)
+    (kill-process python--flymake-proc))
+
+  (let ((source (current-buffer)))
+    (save-restriction
+      (widen)
+      (setq python--flymake-proc
+            (make-process
+             :name "python-flymake"
+             :noquery t
+             :connection-type 'pipe
+             :buffer (generate-new-buffer " *python-flymake*")
+             :command python-flymake-command
+             :sentinel
+             (lambda (proc _event)
+               (when (eq 'exit (process-status proc))
+                 (unwind-protect
+                     (when (eq proc python--flymake-proc)
+                       (python--flymake-parse-output source proc report-fn))
+                   (kill-buffer (process-buffer proc)))))))
+      (process-send-region python--flymake-proc (point-min) (point-max))
+      (process-send-eof python--flymake-proc))))
+
+
 (defun python-electric-pair-string-delimiter ()
   (when (and electric-pair-mode
              (memq last-command-event '(?\" ?\'))
@@ -5255,7 +5386,9 @@ python-mode
   (make-local-variable 'python-shell-internal-buffer)
 
   (when python-indent-guess-indent-offset
-    (python-indent-guess-indent-offset)))
+    (python-indent-guess-indent-offset))
+
+  (add-hook 'flymake-diagnostic-functions #'python--flymake nil t))
 
 
 (provide 'python)
-- 
2.15.0.rc1

[Message part 3 (text/plain, inline)]
-- 
nickname: Lele Gaifax | Quando vivrò di quello che ho pensato ieri
real: Emanuele Gaifas | comincerò ad aver paura di chi mi copia.
lele <at> metapensiero.it  |                 -- Fortunato Depero, 1929.

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#28808; Package emacs. (Sat, 21 Oct 2017 07:16:02 GMT) Full text and rfc822 format available.

Message #26 received at 28808 <at> debbugs.gnu.org (full text, mbox):

From: Lele Gaifax <lele <at> metapensiero.it>
To: 28808 <at> debbugs.gnu.org
Subject: Consider the right python--flymake-proc
Date: Sat, 21 Oct 2017 09:15:38 +0200
[Message part 1 (text/plain, inline)]
Hi,

I applied the fix about accessing the local python--flymake-proc in the right
buffer, in the inner lambda in python--flymake.

ciao, lele.

[0001-Add-a-Flymake-backend-for-Python.patch (text/x-diff, inline)]
From 739643bcf8cfcdbb09d43dd84ba12b0ab5d98d89 Mon Sep 17 00:00:00 2001
From: Lele Gaifax <lele <at> metapensiero.it>
Date: Fri, 13 Oct 2017 10:44:02 +0200
Subject: [PATCH] Add a Flymake backend for Python

* lisp/progmodes/python.el: Implement new Flymake backend with
  related customizable settings.
  (python-flymake-command, python-flymake-command-output-regexp,
   python-flymake-msg-alist): New defcustom.
  (python--flymake-parse-output): New function, able to parse
  python-flymake-command output accordingly to
  python-flymake-command-output-regexp.
  (python--flymake): New function implementing the backend interface
  using python--flymake-parse-output for the real work.
  (python-mode): Add python--flymake to flymake-diagnostic-functions.
---
 lisp/progmodes/python.el | 136 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 135 insertions(+), 1 deletion(-)

diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 895117b9ee..49c1ad907d 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -5142,6 +5142,138 @@ python-util-valid-regexp-p
   (ignore-errors (string-match regexp "") t))
 
 
+;;; Flymake integration
+
+(defgroup python-flymake nil
+  "Integration between Python and Flymake."
+  :group 'python
+  :link '(custom-group-link :tag "Flymake" flymake)
+  :version "26.1")
+
+(defcustom python-flymake-command '("pyflakes")
+  "The external tool that will be used to perform the syntax check.
+This is a non empty list of strings, the checker tool possibly followed by
+required arguments.  Once launched it will receive the Python source to be
+checked as its standard input.
+To use `flake8' you would set this to (\"flake8\" \"-\")."
+  :group 'python-flymake
+  :type '(repeat string))
+
+;; The default regexp accomodates for older pyflakes, which did not
+;; report the column number, and at the same time it's compatible with
+;; flake8 output, although it may be redefined to explicitly match the
+;; TYPE
+(defcustom python-flymake-command-output-regexp
+  (list
+   "^\\(?:<?stdin>?\\):\\(?1:[0-9]+\\):\\(?:\\(?2:[0-9]+\\):\\)? \\(?3:.*\\)$"
+   1 2 nil 3)
+  "Specify how to parse the output of the specified tool.
+The value has the form (REGEXP LINE COLUMN TYPE MESSAGE): if
+REGEXP matches, the LINE'th subexpression gives the line number,
+the COLUMN'th subexpression gives the column number on that line,
+the TYPE'th subexpression gives the type of the message and
+MESSAGE'th is the message text itself.
+
+If COLUMN or TYPE are nil or that index didn't match, that
+information is not present on the matched line and a default will
+be used."
+  :group 'python-flymake
+  :type '(list regexp
+               (integer :tag "Line's index")
+               (choice
+                (const :tag "No column" nil)
+                (integer :tag "Column's index"))
+               (choice
+                (const :tag "No type" nil)
+                (integer :tag "Type's index"))
+               (integer :tag "Message's index")))
+
+(defcustom python-flymake-msg-alist
+  '(("\\(^redefinition\\|.*unused.*\\|used$\\)" . :warning))
+  "Alist used to associate messages to their types.
+Each element should be a cons-cell (REGEXP . TYPE), where TYPE must be
+one defined in the variable `flymake-diagnostic-types-alist'.
+For example, when using `flake8' a possible configuration could be:
+
+  ((\"\\(^redefinition\\|.*unused.*\\|used$\\)\" . :warning)
+   (\"^E999\" . :error)
+   (\"^[EW][0-9]+\" . :note))
+
+By default messages are considered errors."
+  :group 'python-flymake
+  :type `(alist :key-type (regexp)
+                :value-type (symbol)))
+
+(defvar-local python--flymake-proc nil)
+
+(defun python--flymake-parse-output (source proc report-fn)
+  "Collect diagnostics parsing checker tool's output line by line."
+  (let ((rx (nth 0 python-flymake-command-output-regexp))
+        (lineidx (nth 1 python-flymake-command-output-regexp))
+        (colidx (nth 2 python-flymake-command-output-regexp))
+        (typeidx (nth 3 python-flymake-command-output-regexp))
+        (msgidx (nth 4 python-flymake-command-output-regexp)))
+    (with-current-buffer (process-buffer proc)
+      (goto-char (point-min))
+      (cl-loop
+       while (search-forward-regexp rx nil t)
+       for msg = (match-string msgidx)
+       for (beg . end) = (flymake-diag-region
+                          source
+                          (string-to-number
+                           (match-string lineidx))
+                          (and colidx
+                               (match-string colidx)
+                               (string-to-number
+                                (match-string colidx))))
+       for type = (or (and typeidx
+                           (match-string typeidx)
+                           (assoc-default
+                            (match-string typeidx)
+                            python-flymake-msg-alist
+                            #'string-match))
+                      (assoc-default msg
+                                     python-flymake-msg-alist
+                                     #'string-match)
+                      :error)
+       collect (flymake-make-diagnostic
+                source beg end type msg)
+       into diags
+       finally (funcall report-fn diags)))))
+
+(defun python--flymake (report-fn &rest _args)
+  "Flymake backend for Python.
+This backend uses `python-flymake-command' (which see) to launch a process
+that is passed the current buffer's content via stdin.
+REPORT-FN is Flymake's callback function."
+  (unless (executable-find (car python-flymake-command))
+    (error "Cannot find a suitable checker"))
+
+  (when (process-live-p python--flymake-proc)
+    (kill-process python--flymake-proc))
+
+  (let ((source (current-buffer)))
+    (save-restriction
+      (widen)
+      (setq python--flymake-proc
+            (make-process
+             :name "python-flymake"
+             :noquery t
+             :connection-type 'pipe
+             :buffer (generate-new-buffer " *python-flymake*")
+             :command python-flymake-command
+             :sentinel
+             (lambda (proc _event)
+               (when (eq 'exit (process-status proc))
+                 (unwind-protect
+                     (when (with-current-buffer source
+                             (eq proc python--flymake-proc))
+                       (python--flymake-parse-output source proc report-fn))
+                   (kill-buffer (process-buffer proc)))))))
+      (process-send-region python--flymake-proc (point-min) (point-max))
+      (process-send-eof python--flymake-proc))))
+
+
 (defun python-electric-pair-string-delimiter ()
   (when (and electric-pair-mode
              (memq last-command-event '(?\" ?\'))
@@ -5255,7 +5387,9 @@ python-mode
   (make-local-variable 'python-shell-internal-buffer)
 
   (when python-indent-guess-indent-offset
-    (python-indent-guess-indent-offset)))
+    (python-indent-guess-indent-offset))
+
+  (add-hook 'flymake-diagnostic-functions #'python--flymake nil t))
 
 
 (provide 'python)
-- 
2.15.0.rc1

[Message part 3 (text/plain, inline)]
-- 
nickname: Lele Gaifax | Quando vivrò di quello che ho pensato ieri
real: Emanuele Gaifas | comincerò ad aver paura di chi mi copia.
lele <at> metapensiero.it  |                 -- Fortunato Depero, 1929.

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#28808; Package emacs. (Sat, 21 Oct 2017 13:06:02 GMT) Full text and rfc822 format available.

Message #29 received at 28808 <at> debbugs.gnu.org (full text, mbox):

From: João Távora <joaotavora <at> gmail.com>
To: Lele Gaifax <lele <at> metapensiero.it>
Cc: 28808 <at> debbugs.gnu.org
Subject: Re: bug#28808: Consider the right python--flymake-proc
Date: Sat, 21 Oct 2017 14:05:25 +0100
[Message part 1 (text/plain, inline)]
Good one.

I'll have a look at all the backends, including yours of course, during the
next week.

João

On Sat, Oct 21, 2017 at 8:15 AM, Lele Gaifax <lele <at> metapensiero.it> wrote:

> Hi,
>
> I applied the fix about accessing the local python--flymake-proc in the
> right
> buffer, in the inner lambda in python--flymake.
>
> ciao, lele.
>
>
>
> --
> nickname: Lele Gaifax | Quando vivrò di quello che ho pensato ieri
> real: Emanuele Gaifas | comincerò ad aver paura di chi mi copia.
> lele <at> metapensiero.it  |                 -- Fortunato Depero, 1929.
>
>


-- 
João Távora
[Message part 2 (text/html, inline)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#28808; Package emacs. (Fri, 03 Nov 2017 12:25:02 GMT) Full text and rfc822 format available.

Message #32 received at 28808 <at> debbugs.gnu.org (full text, mbox):

From: joaotavora <at> gmail.com (João Távora)
To: Lele Gaifax <lele <at> metapensiero.it>
Cc: 28808 <at> debbugs.gnu.org
Subject: Re: bug#28808: Consider the right python--flymake-proc
Date: Fri, 03 Nov 2017 12:24:19 +0000
[Message part 1 (text/plain, inline)]
João Távora <joaotavora <at> gmail.com> writes:

> Good one. 
>
> I'll have a look at all the backends, including yours of course, during the next week.
>
> João
>

Sorry for the delay.

I am ready to commit your patch to emacs-26 with very minor changes:

1. The defcustom python-flymake-command-output-regexp is renamed to
python-flymake-command-output-pattern.

2. The docstring of that variable is slightly changed.

3. The function python--flymake is renamed python-flymake, since it is
public to python.el (there was some misunderstanding caused by me
earlier).

4. The commit message is very slightly changed so that the description
sentence starts on a line by its own.

Please verify,
João

[0001-Add-a-Flymake-backend-for-Python.patch (text/x-diff, inline)]
From fd800a9e16493872ff3c8244a2e30e2d9e61fca4 Mon Sep 17 00:00:00 2001
From: Lele Gaifax <lele <at> metapensiero.it>
Date: Fri, 3 Nov 2017 12:20:36 +0000
Subject: [PATCH] Add a Flymake backend for Python

Implement new Flymake backend with related customizable settings.

* lisp/progmodes/python.el (python-flymake-command)
(python-flymake-command-output-pattern)
(python-flymake-msg-alist): New defcustom.
(python--flymake-parse-output): New function, able to parse
python-flymake-command output accordingly to
python-flymake-command-output-pattern.
(python-flymake): New function implementing the backend
interface using python--flymake-parse-output for the real
work.
(python-mode): Add python-flymake to flymake-diagnostic-functions.
---
 lisp/progmodes/python.el | 136 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 135 insertions(+), 1 deletion(-)

diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 895117b9ee..b7902fb978 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -5142,6 +5142,138 @@ python-util-valid-regexp-p
   (ignore-errors (string-match regexp "") t))
 
 
+;;; Flymake integration
+
+(defgroup python-flymake nil
+  "Integration between Python and Flymake."
+  :group 'python
+  :link '(custom-group-link :tag "Flymake" flymake)
+  :version "26.1")
+
+(defcustom python-flymake-command '("pyflakes")
+  "The external tool that will be used to perform the syntax check.
+This is a non empty list of strings, the checker tool possibly followed by
+required arguments.  Once launched it will receive the Python source to be
+checked as its standard input.
+To use `flake8' you would set this to (\"flake8\" \"-\")."
+  :group 'python-flymake
+  :type '(repeat string))
+
+;; The default regexp accomodates for older pyflakes, which did not
+;; report the column number, and at the same time it's compatible with
+;; flake8 output, although it may be redefined to explicitly match the
+;; TYPE
+(defcustom python-flymake-command-output-pattern
+  (list
+   "^\\(?:<?stdin>?\\):\\(?1:[0-9]+\\):\\(?:\\(?2:[0-9]+\\):\\)? \\(?3:.*\\)$"
+   1 2 nil 3)
+  "Specify how to parse the output of `python-flymake-command'.
+The value has the form (REGEXP LINE COLUMN TYPE MESSAGE): if
+REGEXP matches, the LINE'th subexpression gives the line number,
+the COLUMN'th subexpression gives the column number on that line,
+the TYPE'th subexpression gives the type of the message and the
+MESSAGE'th gives the message text itself.
+
+If COLUMN or TYPE are nil or that index didn't match, that
+information is not present on the matched line and a default will
+be used."
+  :group 'python-flymake
+  :type '(list regexp
+               (integer :tag "Line's index")
+               (choice
+                (const :tag "No column" nil)
+                (integer :tag "Column's index"))
+               (choice
+                (const :tag "No type" nil)
+                (integer :tag "Type's index"))
+               (integer :tag "Message's index")))
+
+(defcustom python-flymake-msg-alist
+  '(("\\(^redefinition\\|.*unused.*\\|used$\\)" . :warning))
+  "Alist used to associate messages to their types.
+Each element should be a cons-cell (REGEXP . TYPE), where TYPE must be
+one defined in the variable `flymake-diagnostic-types-alist'.
+For example, when using `flake8' a possible configuration could be:
+
+  ((\"\\(^redefinition\\|.*unused.*\\|used$\\)\" . :warning)
+   (\"^E999\" . :error)
+   (\"^[EW][0-9]+\" . :note))
+
+By default messages are considered errors."
+  :group 'python-flymake
+  :type `(alist :key-type (regexp)
+                :value-type (symbol)))
+
+(defvar-local python--flymake-proc nil)
+
+(defun python--flymake-parse-output (source proc report-fn)
+  "Collect diagnostics parsing checker tool's output line by line."
+  (let ((rx (nth 0 python-flymake-command-output-pattern))
+        (lineidx (nth 1 python-flymake-command-output-pattern))
+        (colidx (nth 2 python-flymake-command-output-pattern))
+        (typeidx (nth 3 python-flymake-command-output-pattern))
+        (msgidx (nth 4 python-flymake-command-output-pattern)))
+    (with-current-buffer (process-buffer proc)
+      (goto-char (point-min))
+      (cl-loop
+       while (search-forward-regexp rx nil t)
+       for msg = (match-string msgidx)
+       for (beg . end) = (flymake-diag-region
+                          source
+                          (string-to-number
+                           (match-string lineidx))
+                          (and colidx
+                               (match-string colidx)
+                               (string-to-number
+                                (match-string colidx))))
+       for type = (or (and typeidx
+                           (match-string typeidx)
+                           (assoc-default
+                            (match-string typeidx)
+                            python-flymake-msg-alist
+                            #'string-match))
+                      (assoc-default msg
+                                     python-flymake-msg-alist
+                                     #'string-match)
+                      :error)
+       collect (flymake-make-diagnostic
+                source beg end type msg)
+       into diags
+       finally (funcall report-fn diags)))))
+
+(defun python-flymake (report-fn &rest _args)
+  "Flymake backend for Python.
+This backend uses `python-flymake-command' (which see) to launch a process
+that is passed the current buffer's content via stdin.
+REPORT-FN is Flymake's callback function."
+  (unless (executable-find (car python-flymake-command))
+    (error "Cannot find a suitable checker"))
+
+  (when (process-live-p python--flymake-proc)
+    (kill-process python--flymake-proc))
+
+  (let ((source (current-buffer)))
+    (save-restriction
+      (widen)
+      (setq python--flymake-proc
+            (make-process
+             :name "python-flymake"
+             :noquery t
+             :connection-type 'pipe
+             :buffer (generate-new-buffer " *python-flymake*")
+             :command python-flymake-command
+             :sentinel
+             (lambda (proc _event)
+               (when (eq 'exit (process-status proc))
+                 (unwind-protect
+                     (when (with-current-buffer source
+                             (eq proc python--flymake-proc))
+                       (python--flymake-parse-output source proc report-fn))
+                   (kill-buffer (process-buffer proc)))))))
+      (process-send-region python--flymake-proc (point-min) (point-max))
+      (process-send-eof python--flymake-proc))))
+
+
 (defun python-electric-pair-string-delimiter ()
   (when (and electric-pair-mode
              (memq last-command-event '(?\" ?\'))
@@ -5255,7 +5387,9 @@ python-mode
   (make-local-variable 'python-shell-internal-buffer)
 
   (when python-indent-guess-indent-offset
-    (python-indent-guess-indent-offset)))
+    (python-indent-guess-indent-offset))
+
+  (add-hook 'flymake-diagnostic-functions #'python-flymake nil t))
 
 
 (provide 'python)
-- 
2.14.2


Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#28808; Package emacs. (Fri, 03 Nov 2017 19:17:01 GMT) Full text and rfc822 format available.

Message #35 received at 28808 <at> debbugs.gnu.org (full text, mbox):

From: Lele Gaifax <lele <at> metapensiero.it>
To: João Távora <joaotavora <at> gmail.com>
Cc: 28808 <at> debbugs.gnu.org
Subject: Re: bug#28808: Consider the right python--flymake-proc
Date: Fri, 03 Nov 2017 20:16:42 +0100
joaotavora <at> gmail.com (João Távora) writes:

> Please verify,

Thank you João, everything seems good to me.

Ciao, lele.
-- 
nickname: Lele Gaifax | Quando vivrò di quello che ho pensato ieri
real: Emanuele Gaifas | comincerò ad aver paura di chi mi copia.
lele <at> metapensiero.it  |                 -- Fortunato Depero, 1929.




Added tag(s) fixed. Request was from joaotavora <at> gmail.com (João Távora) to control <at> debbugs.gnu.org. (Sun, 05 Nov 2017 21:54:02 GMT) Full text and rfc822 format available.

bug marked as fixed in version 26.1, send any further explanations to 28808 <at> debbugs.gnu.org and Lele Gaifax <lele <at> metapensiero.it> Request was from joaotavora <at> gmail.com (João Távora) to control <at> debbugs.gnu.org. (Sun, 05 Nov 2017 21:54:02 GMT) Full text and rfc822 format available.

bug archived. Request was from Debbugs Internal Request <help-debbugs <at> gnu.org> to internal_control <at> debbugs.gnu.org. (Mon, 04 Dec 2017 12:24:05 GMT) Full text and rfc822 format available.

This bug report was last modified 7 years and 200 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.