一个关于 flycheck-define-checker 的问题

这两天用着 Google 的 pytype

看了看,好像还没有 flycheck 的 checker,于是就自己写了个还不够完美的。用是能用了,只是少了点东西 (两行) 很不开心。

我写的是这样的:

(flycheck-def-args-var flycheck-python-pytype-args python-pytype)

(flycheck-define-checker python-pytype
  "Pytype syntax checker.

See url `https://github.com/google/pytype`."
  :command ("pytype"
            (eval flycheck-python-pytype-args)
            source-original)
  :error-patterns
  ((warning line-start "File \"" (file-name) "\", line " line ", " (message (one-or-more (not (any "[")))) "[" (id (one-or-more not-newline)) "]"))
  :modes python-mode
  :predicate flycheck-buffer-saved-p
  :next-checkers (python-flake8))

pytype 的输出是这样的:

λ≻ pytype temp.py
Computing dependencies
Analyzing 1 sources with 0 local dependencies
ninja: Entering directory `/Users/Nasy/temp/python/.pytype'
[1/1] check temp
FAILED: /Users/Nasy/temp/python/.pytype/pyi/temp.pyi
/Users/Nasy/.pyenv/versions/3.7.4/bin/python3.7 -m pytype.single --imports_info /Users/Nasy/temp/python/.pytype/imports/temp.imports --module-name temp -V 3.7 -o /Users/Nasy/temp/python/.pytype/pyi/temp.pyi --analyze-annotated --nofail --quick /Users/Nasy/temp/python/temp.py
File "/Users/Nasy/temp/python/temp.py", line 46, in unannotated: Missing parameter 'iterable' in call to function str.join [missing-parameter]
  Expected: (self, iterable)
  Actually passed: (self)
File "/Users/Nasy/temp/python/temp.py", line 50, in unannotated2: Function str.join expects 2 arg(s), got 3 [wrong-arg-count]
  Expected: (self, iterable)
  Actually passed: (self, iterable, _)

For more details, see https://google.github.io/pytype/errors.html.
ninja: build stopped: subcommand failed.

很显然,错误的信息应该在

File "/xxx/", line xx, message [id]
  Expected:
  Actually

这三行,我现在能匹配 第一行的那些了 但是该怎么一次性匹配这三行 message 呢?

顺便(这东西比 mypy 好用呢!)

(with-temp-buffer
  (insert "File \"/Users/Nasy/temp/python/temp.py\", line 46, in unannotated: Missing parameter 'iterable' in call to function str.join [missing-parameter]
  Expected: (self, iterable)
  Actually passed: (self)")
  (goto-char (point-min))
  (when (re-search-forward
         "^File \"\\([^\"]+\\)\", line \\([0-9]+\\), in \\([^:]+\\): \\([^\\[]*\\)\\[\\([^]]*\\)]\n[\s\t]+Expected: \\(.*\\)\n[\s\t]+Actually passed: \\(.*\\)"
         nil
         t)
    (list :file     (match-string 1)
          :line     (match-string 2)
          :function (match-string 3)
          :message  (match-string 4)
          :id       (match-string 5)
          :expected (match-string 6)
          :actual   (match-string 7))))
;; =>
;; (:file      "/Users/Nasy/temp/python/temp.py"
;;  :line      "46"
;;  :function  "unannotated"
;;  :message   "Missing parameter 'iterable' in call to function str.join "
;;  :id        "missing-parameter"
;;  :expected  "(self, iterable)"
;;  :actual    "(self)")

感谢! 这串 regex 真是可怕(

试试 rx:

(rx line-start
    "File \""           (group (+ (not (any "\"")))) "\", "
    "line "             (group (+ digit)) ", "
    "in "               (group (+ (not (any ":"))))
    ": "                (group (+ (not (any "["))))
    "["                 (group (+ (not (any "]")))) "]\n" (+ space)
    "Expected: "        (group (* not-newline)) "\n" (+ space)
    "Actually passed: " (group (* not-newline)))

这个包我用不太熟。