[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/flymake-collection 74e2f3fb4b 54/89: Set the working dir a
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/flymake-collection 74e2f3fb4b 54/89: Set the working dir and shadow file flag for mypy (#9) |
Date: |
Mon, 6 Jan 2025 19:00:10 -0500 (EST) |
branch: elpa/flymake-collection
commit 74e2f3fb4b9b4944f1c90377d7d2f16e57d6d5cd
Author: dmitrig <34632025+dmitrig@users.noreply.github.com>
Commit: GitHub <noreply@github.com>
Set the working dir and shadow file flag for mypy (#9)
* Run mypy from inferred python project root
* Remove leading dot from temp file name
This appears to break relative imports in files checked by mypy. Maybe
make the temp file pattern configurable per checker?
* Use mypy --shadow-file for buffers with a file
Fall back to the buffer name when `buffer-file-name' is nil. Necessary
for checking temp files since python module names are based on the
file name.
* Parse mypy diagnostic ids
* Make the mypy working dir configurable
* Add basic tests for mypy
* Add require for project
* Move required mypy flags out of custom variable
* Fix parsing of mypy error ids with hyphens
* Add temp-file-prefix paramter
* Update src/checkers/flymake-collection-mypy.el
Co-authored-by: dmitrig <34632025+dgarbuzov@users.noreply.github.com>
Co-authored-by: Mohsin Kaleem <mohkale@kisara.moe>
---
src/checkers/flymake-collection-mypy.el | 93 ++++++++++++++++++++++++++++-----
src/flymake-collection-define.el | 24 ++++++---
tests/checkers/installers/mypy.bash | 1 +
tests/checkers/test-cases/mypy.yml | 47 +++++++++++++++++
4 files changed, 144 insertions(+), 21 deletions(-)
diff --git a/src/checkers/flymake-collection-mypy.el
b/src/checkers/flymake-collection-mypy.el
index 1fa8f27444..616d5659b1 100644
--- a/src/checkers/flymake-collection-mypy.el
+++ b/src/checkers/flymake-collection-mypy.el
@@ -26,34 +26,101 @@
;;; Code:
+(require 'project)
(require 'flymake)
(require 'flymake-collection)
(eval-when-compile
(require 'flymake-collection-define))
+(defcustom flymake-collection-mypy-args
+ '("--show-error-codes")
+ "Command line arguments always passed to `flymake-collection-mypy'."
+ :type '(repeat (string :tag "Arg"))
+ :group 'flymake-collection)
+
+(defcustom flymake-collection-mypy-project-root
+ '(("mypy.ini" "project.toml" "setup.cfg") project-root default-directory)
+ "Method to set project root."
+ :type '(repeat :tag "Run mypy from the first choice that succeeds"
+ (choice (const :tag "The buffer default-directory"
default-directory)
+ (const :tag "The current project root" project-root)
+ (directory :tag "A specific directory")
+ (repeat :tag "The first ancestor directory containing"
+ :value ("mypy.ini" "pyproject.toml"
"setup.cfg")
+ (string :tag "File name"))))
+ :group 'flymake-collection
+ :safe 'listp)
+
+(defun flymake-collection-mypy--locate-dominating-files (buffer files)
+ "Find ancestor directory of `BUFFER' containing any of `FILES'."
+ (let* ((start (if-let ((file (buffer-file-name buffer)))
+ (file-name-directory file)
+ (buffer-local-value 'default-directory buffer)))
+ (regex (mapconcat 'regexp-quote files "\\|"))
+ (root (locate-dominating-file
+ start (lambda (dir) (directory-files dir nil regex t)))))
+ root))
+
+(defun flymake-collection-mypy--default-directory (buffer)
+ "Find a directory from which to run mypy to check `BUFFER'.
+Try each method specified in `flymake-collection-mypy-project-root' in
+order and returns the first non-nil result."
+ (cl-dolist (spec flymake-collection-mypy-project-root)
+ (when-let
+ ((res (cond
+ ((eq spec 'default-directory)
+ (buffer-local-value 'default-directory buffer))
+ ((eq spec 'project-root)
+ (when-let ((proj (project-current)))
+ (project-root proj)))
+ ((listp spec)
+ (flymake-collection-mypy--locate-dominating-files
+ buffer spec))
+ ((stringp spec) spec))))
+ (cl-return res))))
+
+
;;;###autoload (autoload 'flymake-collection-mypy "flymake-collection-mypy")
(flymake-collection-define-rx flymake-collection-mypy
"Mypy syntax and type checker. Requires mypy>=0.580.
See URL `http://mypy-lang.org/'."
:title "mypy"
- :pre-let ((mypy-exec (executable-find "mypy")))
- :pre-check (unless mypy-exec
- (error "Cannot find mypy executable"))
+ :pre-let ((mypy-exec (executable-find "mypy"))
+ (default-directory (flymake-collection-mypy--default-directory
+ flymake-collection-source)))
+ :pre-check (progn
+ (flymake-log :debug "Working dir is %s" default-directory)
+ (unless mypy-exec
+ (error "Cannot find mypy executable"))
+ (unless default-directory
+ (error "Default dir is nil: check
`flymake-collection-mypy-project-root'")))
:write-type 'file
:source-inplace t
- :command (list mypy-exec
- "--show-column-numbers"
- "--no-error-summary"
- "--no-color-output"
- "--show-absolute-path"
- "--show-error-codes"
- flymake-collection-temp-file)
+ :command `(,mypy-exec
+ "--show-column-numbers"
+ "--show-absolute-path"
+ "--no-error-summary"
+ "--no-color-output"
+ ,@flymake-collection-mypy-args
+ ,@(if-let ((source-file (buffer-file-name
+ flymake-collection-source))
+ ((file-exists-p source-file)))
+ (list
+ "--shadow-file" source-file flymake-collection-temp-file
+ source-file)
+ (list flymake-collection-temp-file)))
+ ;; Temporary file cannot start with a dot for mypy, see
+ ;; https://github.com/mohkale/flymake-collection/pull/9
+ :temp-file-prefix "flymake_mypy_"
:regexps
- ((error bol (file-name) ":" line ":" column ": error: " (message) eol)
- (warning bol (file-name) ":" line ":" column ": warning: " (message) eol)
- (note bol (file-name) ":" line ":" column ": note: " (message) eol)))
+ ((error bol (file-name) ":" line ":" column ": error: "
+ (message) (opt " [" (id (* graph)) "]") eol)
+ (warning bol (file-name) ":" line ":" column ": warning: "
+ (message) (opt " [" (id (* graph)) "]") eol)
+ (note bol (file-name) ":" line ":" column ": note: "
+ (message) (opt " [" (id (* graph)) "]") eol)))
(provide 'flymake-collection-mypy)
diff --git a/src/flymake-collection-define.el b/src/flymake-collection-define.el
index fe7c706e67..7c32039034 100644
--- a/src/flymake-collection-define.el
+++ b/src/flymake-collection-define.el
@@ -60,11 +60,13 @@ killed and replaced with the new check.")
(define-obsolete-function-alias 'flymake-rest-define
'flymake-collection-define "2.0.0")
-(defun flymake-collection-define--temp-file (temp-dir temp-file source-inplace)
+(defun flymake-collection-define--temp-file
+ (temp-dir temp-file source-inplace temp-file-prefix)
"Let forms for defining a temporary directory and file.
TEMP-DIR and TEMP-FILE are the symbols used for the corresponding variables.
SOURCE-INPLACE specifies whether the TEMP-DIR should be in the same working
-directory as the current buffer."
+directory as the current buffer. Temporary files are named by concatenating
+TEMP-FILE-PREFIX with the current buffer file name."
`((,temp-dir
,@(let ((forms
(append
@@ -84,7 +86,7 @@ doesn't exist: %s" dir))
(let ((temporary-file-directory ,temp-dir)
(basename (file-name-nondirectory (or (buffer-file-name)
(buffer-name)))))
- (make-temp-file ".flymake_" nil (concat "_" basename))))))
+ (make-temp-file ,temp-file-prefix nil (concat "_" basename))))))
(defmacro flymake-collection-define--parse-diags
(title proc-symb diags-symb current-diag-symb source-symb error-parser)
@@ -132,7 +134,7 @@ CURRENT-DIAGS-SYMB, SOURCE-SYMB, ERROR-PARSER are all
described in
(cl-defmacro flymake-collection-define
(name docstring
&optional &key title command error-parser write-type
- source-inplace pre-let pre-check)
+ source-inplace pre-let pre-check (temp-file-prefix ".flymake_"))
"Quickly define a backend function for use with Flymake.
Define a function NAME which is suitable for use with the variable
`flymake-diagnostic-functions'. DOCSTRING if given will become the
@@ -192,7 +194,11 @@ used to start the checker process. It should be suitable
for use as the
ERROR-PARSER is a lisp-form that should, each time it is evaluated,
return the next diagnostic from the checker output. The result should be
a value that can be passed to the `flymake-make-diagnostic' function. Once
-there are no more diagnostics to parse this form should evaluate to nil."
+there are no more diagnostics to parse this form should evaluate to nil.
+
+TEMP-FILE-PREFIX overrides the prefix of temporary file names created by
+the checker. This is useful for checker programs that have issues running
+on hidden files."
(declare (indent defun) (doc-string 2))
(unless lexical-binding
(error "Need lexical-binding for flymake-collection-define (%s)" name))
@@ -228,7 +234,7 @@ there are no more diagnostics to parse this form should
evaluate to nil."
(let* ((,source-symb (current-buffer))
,@(when (eq write-type 'file)
(flymake-collection-define--temp-file
- temp-dir-symb temp-file-symb source-inplace))
+ temp-dir-symb temp-file-symb source-inplace
temp-file-prefix))
,@pre-let)
;; With vars defined, do pre-check.
,@(when pre-check
@@ -441,13 +447,14 @@ For an example of this macro in action, see
`flymake-collection-pycodestyle'."
(cl-defmacro flymake-collection-define-rx
(name docstring
- &optional &key title command write-type source-inplace pre-let
pre-check regexps)
+ &optional &key title command write-type
+ source-inplace pre-let pre-check temp-file-prefix regexps)
"`flymake-collection-define' helper using `rx' syntax to parse diagnostics.
This helper macro adapts `flymake-collection-define' to use an error-parser
built from a collections of REGEXPS (see
`flymake-collection-define--parse-rx').
See `flymake-collection-define' for a description of NAME, DOCSTRING, TITLE,
-COMMAND,WRITE-TYPE, SOURCE-INPLACE, PRE-LET, and PRE-CHECK."
+COMMAND,WRITE-TYPE, SOURCE-INPLACE, PRE-LET, PRE-CHECK, and TEMP-FILE-PREFIX."
(declare (indent defun) (doc-string 2))
`(flymake-collection-define ,name
,docstring
@@ -457,6 +464,7 @@ COMMAND,WRITE-TYPE, SOURCE-INPLACE, PRE-LET, and PRE-CHECK."
:source-inplace ,source-inplace
:pre-let ,pre-let
:pre-check ,pre-check
+ :temp-file-prefix ,temp-file-prefix
:error-parser
(flymake-collection-define--parse-rx ,regexps)))
diff --git a/tests/checkers/installers/mypy.bash
b/tests/checkers/installers/mypy.bash
new file mode 100755
index 0000000000..507e8e903a
--- /dev/null
+++ b/tests/checkers/installers/mypy.bash
@@ -0,0 +1 @@
+python3.8 -m pip install mypy
diff --git a/tests/checkers/test-cases/mypy.yml
b/tests/checkers/test-cases/mypy.yml
new file mode 100644
index 0000000000..6f3fe27229
--- /dev/null
+++ b/tests/checkers/test-cases/mypy.yml
@@ -0,0 +1,47 @@
+---
+checker: flymake-collection-mypy
+tests:
+ - name: no-lints
+ file: |
+ """A test case with no output from mypy."""
+
+ print("hello world")
+ lints: []
+ - name: error-operator
+ file: |
+ """Test parsing an error."""
+
+ "x" + 1
+ lints:
+ - point: [3, 6]
+ level: error
+ message: operator Unsupported operand types for + ("str" and "int")
(mypy)
+ - name: error-attr-defined
+ file: |
+ """Test parsing an error with a hyphen in the id."""
+
+ x = 1
+ x.foo
+ lints:
+ - point: [4, 0]
+ level: error
+ message: attr-defined "int" has no attribute "foo" (mypy)
+ - name: note-reveal
+ file: |
+ """Test parsing a note."""
+
+ foo = "bar"
+ reveal_type(foo)
+ lints:
+ - point: [4, 12]
+ level: note
+ message: Revealed type is "builtins.str" (mypy)
+ - name: error-syntax
+ file: |
+ """Test syntax error."""
+
+ class Foo:
+ lints:
+ - point: [3, 0]
+ level: error
+ message: syntax unexpected EOF while parsing (mypy)
- [nongnu] elpa/flymake-collection 0c87b8ff48 56/89: checkers: Add statix checker (#12), (continued)
- [nongnu] elpa/flymake-collection 0c87b8ff48 56/89: checkers: Add statix checker (#12), ELPA Syncer, 2025/01/06
- [nongnu] elpa/flymake-collection 3e1f44739d 66/89: define: Reorient save-match-data and save-excursion, ELPA Syncer, 2025/01/06
- [nongnu] elpa/flymake-collection 93f3dec01a 75/89: build: Remove pylint syntax-error check test, ELPA Syncer, 2025/01/06
- [nongnu] elpa/flymake-collection ebaae4d236 82/89: build: Fix ruff regression with code not set for SyntaxError, ELPA Syncer, 2025/01/06
- [nongnu] elpa/flymake-collection 37dafaeb99 83/89: README: Correct links to GitHub actions, ELPA Syncer, 2025/01/06
- [nongnu] elpa/flymake-collection 297406f601 45/89: Revert "install: Add stopgap symlinks to fix MELPA installs", ELPA Syncer, 2025/01/06
- [nongnu] elpa/flymake-collection 1b62fd9b58 87/89: Additional checkers (#38), ELPA Syncer, 2025/01/06
- [nongnu] elpa/flymake-collection eb8a7eb96e 40/89: tests: Add test harness, ELPA Syncer, 2025/01/06
- [nongnu] elpa/flymake-collection e5446886b4 44/89: install: Add stopgap symlinks to fix MELPA installs, ELPA Syncer, 2025/01/06
- [nongnu] elpa/flymake-collection 274e5ec3e6 53/89: checkers: Fix error codes in ruff (#15), ELPA Syncer, 2025/01/06
- [nongnu] elpa/flymake-collection 74e2f3fb4b 54/89: Set the working dir and shadow file flag for mypy (#9),
ELPA Syncer <=
- [nongnu] elpa/flymake-collection 023227cdcb 61/89: define: Only send region to process if its alive, ELPA Syncer, 2025/01/06
- [nongnu] elpa/flymake-collection 0dc266c443 62/89: define: Auto suppress errors when sending data to process, ELPA Syncer, 2025/01/06
- [nongnu] elpa/flymake-collection 7ea9fb2ea1 70/89: checkers: Fix ruff command interface has changed, ELPA Syncer, 2025/01/06
- [nongnu] elpa/flymake-collection 9d9e5937b5 74/89: build: Make jq test installer executable, ELPA Syncer, 2025/01/06
- [nongnu] elpa/flymake-collection f1d889f166 76/89: checkers: Add checker for vale, ELPA Syncer, 2025/01/06
- [nongnu] elpa/flymake-collection 5d46b52aaa 81/89: build: Fix regression in ruff report, ELPA Syncer, 2025/01/06
- [nongnu] elpa/flymake-collection 29d593cdfb 88/89: chore: Add workflow dispatch to ci, ELPA Syncer, 2025/01/06
- [nongnu] elpa/flymake-collection 5de95adb4c 89/89: Allow users to override the extension passed to vale checker (#43), ELPA Syncer, 2025/01/06
- [nongnu] elpa/flymake-collection 2ce9e8a6d8 10/89: (flymake-rest-commands): Move commands into here, ELPA Syncer, 2025/01/06
- [nongnu] elpa/flymake-collection 6ca15100d1 28/89: (commands): Refactor flymake-rest-change-checker, ELPA Syncer, 2025/01/06