@@ -207,6 +207,7 @@ def pylsp_lint(
207207 args .append ("--strict" )
208208
209209 overrides = settings .get ("overrides" , [True ])
210+ exit_status = 0
210211
211212 if not dmypy :
212213 args .extend (["--incremental" , "--follow-imports" , "silent" ])
@@ -221,11 +222,12 @@ def pylsp_lint(
221222 )
222223 report = completed_process .stdout .decode ()
223224 errors = completed_process .stderr .decode ()
225+ exit_status = completed_process .returncode
224226 else :
225227 # mypy does not exist on path, but must exist in the env pylsp-mypy is installed in
226228 # -> use mypy via api
227229 log .info ("executing mypy args = %s via api" , args )
228- report , errors , _ = mypy_api .run (args )
230+ report , errors , exit_status = mypy_api .run (args )
229231 else :
230232 # If dmypy daemon is non-responsive calls to run will block.
231233 # Check daemon status, if non-zero daemon is dead or hung.
@@ -239,20 +241,24 @@ def pylsp_lint(
239241 completed_process = subprocess .run (
240242 ["dmypy" , * apply_overrides (args , overrides )], stderr = subprocess .PIPE , ** windows_flag
241243 )
242- _err = completed_process .stderr .decode ()
243- _status = completed_process .returncode
244- if _status != 0 :
244+ errors = completed_process .stderr .decode ()
245+ exit_status = completed_process .returncode
246+ if exit_status != 0 :
245247 log .info (
246- "restarting dmypy from status: %s message: %s via path" , _status , _err .strip ()
248+ "restarting dmypy from status: %s message: %s via path" ,
249+ exit_status ,
250+ errors .strip (),
247251 )
248252 subprocess .run (["dmypy" , "kill" ], ** windows_flag )
249253 else :
250254 # dmypy does not exist on path, but must exist in the env pylsp-mypy is installed in
251255 # -> use dmypy via api
252- _ , _err , _status = mypy_api .run_dmypy (["status" ])
253- if _status != 0 :
256+ _ , errors , exit_status = mypy_api .run_dmypy (["status" ])
257+ if exit_status != 0 :
254258 log .info (
255- "restarting dmypy from status: %s message: %s via api" , _status , _err .strip ()
259+ "restarting dmypy from status: %s message: %s via api" ,
260+ exit_status ,
261+ errors .strip (),
256262 )
257263 mypy_api .run_dmypy (["kill" ])
258264
@@ -268,16 +274,33 @@ def pylsp_lint(
268274 )
269275 report = completed_process .stdout .decode ()
270276 errors = completed_process .stderr .decode ()
277+ exit_status = completed_process .returncode
271278 else :
272279 # dmypy does not exist on path, but must exist in the env pylsp-mypy is installed in
273280 # -> use dmypy via api
274281 log .info ("dmypy run args = %s via api" , args )
275- report , errors , _ = mypy_api .run_dmypy (args )
282+ report , errors , exit_status = mypy_api .run_dmypy (args )
276283
277284 log .debug ("report:\n %s" , report )
278285 log .debug ("errors:\n %s" , errors )
279286
280287 diagnostics = []
288+
289+ # Expose generic mypy error on the first line.
290+ if errors :
291+ diagnostics .append (
292+ {
293+ "source" : "mypy" ,
294+ "range" : {
295+ "start" : {"line" : 0 , "character" : 0 },
296+ # Client is supposed to clip end column to line length.
297+ "end" : {"line" : 0 , "character" : 1000 },
298+ },
299+ "message" : errors ,
300+ "severity" : 1 if exit_status != 0 else 2 , # Error if exited with error or warning.
301+ }
302+ )
303+
281304 for line in report .splitlines ():
282305 log .debug ("parsing: line = %r" , line )
283306 diag = parse_line (line , document )
0 commit comments