Skip to content

Commit 8e9c28d

Browse files
committed
add simple progress reporting
1 parent 1c5a336 commit 8e9c28d

File tree

1 file changed

+151
-149
lines changed

1 file changed

+151
-149
lines changed

pylsp_mypy/plugin.py

Lines changed: 151 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -143,174 +143,176 @@ def pylsp_lint(
143143
List of the linting data.
144144
145145
"""
146-
settings = config.plugin_settings("pylsp_mypy")
147-
oldSettings1 = config.plugin_settings("mypy-ls")
148-
if oldSettings1 != {}:
149-
raise DeprecationWarning(
150-
"Your configuration uses the namespace mypy-ls, this should be changed to pylsp_mypy"
151-
)
152-
oldSettings2 = config.plugin_settings("mypy_ls")
153-
if oldSettings2 != {}:
154-
raise DeprecationWarning(
155-
"Your configuration uses the namespace mypy_ls, this should be changed to pylsp_mypy"
156-
)
157-
if settings == {}:
158-
settings = oldSettings1
146+
with workspace.report_progress("lint: mypy"):
147+
settings = config.plugin_settings("pylsp_mypy")
148+
oldSettings1 = config.plugin_settings("mypy-ls")
149+
if oldSettings1 != {}:
150+
raise DeprecationWarning(
151+
"Your configuration uses the namespace mypy-ls, this should be changed to pylsp_mypy"
152+
)
153+
oldSettings2 = config.plugin_settings("mypy_ls")
154+
if oldSettings2 != {}:
155+
raise DeprecationWarning(
156+
"Your configuration uses the namespace mypy_ls, this should be changed to pylsp_mypy"
157+
)
159158
if settings == {}:
160-
settings = oldSettings2
161-
162-
log.info(
163-
"lint settings = %s document.path = %s is_saved = %s",
164-
settings,
165-
document.path,
166-
is_saved,
167-
)
168-
169-
live_mode = settings.get("live_mode", True)
170-
dmypy = settings.get("dmypy", False)
171-
172-
if dmypy and live_mode:
173-
# dmypy can only be efficiently run on files that have been saved, see:
174-
# https://github.com/python/mypy/issues/9309
175-
log.warning("live_mode is not supported with dmypy, disabling")
176-
live_mode = False
159+
settings = oldSettings1
160+
if settings == {}:
161+
settings = oldSettings2
177162

178-
args = ["--show-column-numbers"]
179-
180-
global tmpFile
181-
if live_mode and not is_saved:
182-
if tmpFile:
183-
tmpFile = open(tmpFile.name, "w")
184-
else:
185-
tmpFile = tempfile.NamedTemporaryFile("w", delete=False)
186-
log.info("live_mode tmpFile = %s", tmpFile.name)
187-
tmpFile.write(document.source)
188-
tmpFile.close()
189-
args.extend(["--shadow-file", document.path, tmpFile.name])
190-
elif not is_saved and document.path in last_diagnostics:
191-
# On-launch the document isn't marked as saved, so fall through and run
192-
# the diagnostics anyway even if the file contents may be out of date.
193163
log.info(
194-
"non-live, returning cached diagnostics len(cached) = %s",
195-
last_diagnostics[document.path],
164+
"lint settings = %s document.path = %s is_saved = %s",
165+
settings,
166+
document.path,
167+
is_saved,
196168
)
197-
return last_diagnostics[document.path]
198169

199-
mypyConfigFile = mypyConfigFileMap.get(workspace.root_path)
200-
if mypyConfigFile:
201-
args.append("--config-file")
202-
args.append(mypyConfigFile)
170+
live_mode = settings.get("live_mode", True)
171+
dmypy = settings.get("dmypy", False)
172+
173+
if dmypy and live_mode:
174+
# dmypy can only be efficiently run on files that have been saved, see:
175+
# https://github.com/python/mypy/issues/9309
176+
log.warning("live_mode is not supported with dmypy, disabling")
177+
live_mode = False
178+
179+
args = ["--show-column-numbers"]
180+
181+
global tmpFile
182+
if live_mode and not is_saved:
183+
if tmpFile:
184+
tmpFile = open(tmpFile.name, "w")
185+
else:
186+
tmpFile = tempfile.NamedTemporaryFile("w", delete=False)
187+
log.info("live_mode tmpFile = %s", tmpFile.name)
188+
tmpFile.write(document.source)
189+
tmpFile.close()
190+
args.extend(["--shadow-file", document.path, tmpFile.name])
191+
elif not is_saved and document.path in last_diagnostics:
192+
# On-launch the document isn't marked as saved, so fall through and run
193+
# the diagnostics anyway even if the file contents may be out of date.
194+
log.info(
195+
"non-live, returning cached diagnostics len(cached) = %s",
196+
last_diagnostics[document.path],
197+
)
198+
return last_diagnostics[document.path]
203199

204-
args.append(document.path)
200+
mypyConfigFile = mypyConfigFileMap.get(workspace.root_path)
201+
if mypyConfigFile:
202+
args.append("--config-file")
203+
args.append(mypyConfigFile)
205204

206-
if settings.get("strict", False):
207-
args.append("--strict")
205+
args.append(document.path)
208206

209-
overrides = settings.get("overrides", [True])
210-
exit_status = 0
207+
if settings.get("strict", False):
208+
args.append("--strict")
211209

212-
if not dmypy:
213-
args.extend(["--incremental", "--follow-imports", "silent"])
214-
args = apply_overrides(args, overrides)
210+
overrides = settings.get("overrides", [True])
211+
exit_status = 0
215212

216-
if shutil.which("mypy"):
217-
# mypy exists on path
218-
# -> use mypy on path
219-
log.info("executing mypy args = %s on path", args)
220-
completed_process = subprocess.run(
221-
["mypy", *args], stdout=subprocess.PIPE, stderr=subprocess.PIPE, **windows_flag
222-
)
223-
report = completed_process.stdout.decode()
224-
errors = completed_process.stderr.decode()
225-
exit_status = completed_process.returncode
226-
else:
227-
# mypy does not exist on path, but must exist in the env pylsp-mypy is installed in
228-
# -> use mypy via api
229-
log.info("executing mypy args = %s via api", args)
230-
report, errors, exit_status = mypy_api.run(args)
231-
else:
232-
# If dmypy daemon is non-responsive calls to run will block.
233-
# Check daemon status, if non-zero daemon is dead or hung.
234-
# If daemon is hung, kill will reset
235-
# If daemon is dead/absent, kill will no-op.
236-
# In either case, reset to fresh state
237-
238-
if shutil.which("dmypy"):
239-
# dmypy exists on path
240-
# -> use mypy on path
241-
completed_process = subprocess.run(
242-
["dmypy", "status"], stderr=subprocess.PIPE, **windows_flag
243-
)
244-
errors = completed_process.stderr.decode()
245-
exit_status = completed_process.returncode
246-
if exit_status != 0:
247-
log.info(
248-
"restarting dmypy from status: %s message: %s via path",
249-
exit_status,
250-
errors.strip(),
213+
if not dmypy:
214+
args.extend(["--incremental", "--follow-imports", "silent"])
215+
args = apply_overrides(args, overrides)
216+
217+
if shutil.which("mypy"):
218+
# mypy exists on path
219+
# -> use mypy on path
220+
log.info("executing mypy args = %s on path", args)
221+
completed_process = subprocess.run(
222+
["mypy", *args], stdout=subprocess.PIPE, stderr=subprocess.PIPE, **windows_flag
251223
)
252-
subprocess.run(["dmypy", "restart"], **windows_flag)
224+
report = completed_process.stdout.decode()
225+
errors = completed_process.stderr.decode()
226+
exit_status = completed_process.returncode
227+
else:
228+
# mypy does not exist on path, but must exist in the env pylsp-mypy is installed in
229+
# -> use mypy via api
230+
log.info("executing mypy args = %s via api", args)
231+
report, errors, exit_status = mypy_api.run(args)
253232
else:
254-
# dmypy does not exist on path, but must exist in the env pylsp-mypy is installed in
255-
# -> use dmypy via api
256-
_, errors, exit_status = mypy_api.run_dmypy(["status"])
257-
if exit_status != 0:
258-
log.info(
259-
"restarting dmypy from status: %s message: %s via api",
260-
exit_status,
261-
errors.strip(),
233+
# If dmypy daemon is non-responsive calls to run will block.
234+
# Check daemon status, if non-zero daemon is dead or hung.
235+
# If daemon is hung, kill will reset
236+
# If daemon is dead/absent, kill will no-op.
237+
# In either case, reset to fresh state
238+
239+
if shutil.which("dmypy"):
240+
# dmypy exists on path
241+
# -> use mypy on path
242+
completed_process = subprocess.run(
243+
["dmypy", "status"], stderr=subprocess.PIPE, **windows_flag
262244
)
263-
mypy_api.run_dmypy(["restart"])
245+
errors = completed_process.stderr.decode()
246+
exit_status = completed_process.returncode
247+
if exit_status != 0:
248+
log.info(
249+
"restarting dmypy from status: %s message: %s via path",
250+
exit_status,
251+
errors.strip(),
252+
)
253+
subprocess.run(["dmypy", "restart"], **windows_flag)
254+
else:
255+
# dmypy does not exist on path, but must exist in the env pylsp-mypy is installed in
256+
# -> use dmypy via api
257+
_, errors, exit_status = mypy_api.run_dmypy(["status"])
258+
if exit_status != 0:
259+
log.info(
260+
"restarting dmypy from status: %s message: %s via api",
261+
exit_status,
262+
errors.strip(),
263+
)
264+
mypy_api.run_dmypy(["restart"])
264265

265-
# run to use existing daemon or restart if required
266-
args = ["run", "--"] + apply_overrides(args, overrides)
266+
# run to use existing daemon or restart if required
267+
args = ["run", "--"] + apply_overrides(args, overrides)
267268

268-
if shutil.which("dmypy"):
269-
# dmypy exists on path
270-
# -> use mypy on path
271-
log.info("dmypy run args = %s via path", args)
272-
completed_process = subprocess.run(
273-
["dmypy", *args], stdout=subprocess.PIPE, stderr=subprocess.PIPE, **windows_flag
269+
if shutil.which("dmypy"):
270+
# dmypy exists on path
271+
# -> use mypy on path
272+
log.info("dmypy run args = %s via path", args)
273+
completed_process = subprocess.run(
274+
["dmypy", *args], stdout=subprocess.PIPE, stderr=subprocess.PIPE, **windows_flag
275+
)
276+
report = completed_process.stdout.decode()
277+
errors = completed_process.stderr.decode()
278+
exit_status = completed_process.returncode
279+
else:
280+
# dmypy does not exist on path, but must exist in the env pylsp-mypy is installed in
281+
# -> use dmypy via api
282+
log.info("dmypy run args = %s via api", args)
283+
report, errors, exit_status = mypy_api.run_dmypy(args)
284+
285+
log.debug("report:\n%s", report)
286+
log.debug("errors:\n%s", errors)
287+
288+
diagnostics = []
289+
290+
# Expose generic mypy error on the first line.
291+
if errors:
292+
diagnostics.append(
293+
{
294+
"source": "mypy",
295+
"range": {
296+
"start": {"line": 0, "character": 0},
297+
# Client is supposed to clip end column to line length.
298+
"end": {"line": 0, "character": 1000},
299+
},
300+
"message": errors,
301+
# Error if exited with error or warning.
302+
"severity": 1 if exit_status != 0 else 2,
303+
}
274304
)
275-
report = completed_process.stdout.decode()
276-
errors = completed_process.stderr.decode()
277-
exit_status = completed_process.returncode
278-
else:
279-
# dmypy does not exist on path, but must exist in the env pylsp-mypy is installed in
280-
# -> use dmypy via api
281-
log.info("dmypy run args = %s via api", args)
282-
report, errors, exit_status = mypy_api.run_dmypy(args)
283-
284-
log.debug("report:\n%s", report)
285-
log.debug("errors:\n%s", errors)
286-
287-
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-
)
303305

304-
for line in report.splitlines():
305-
log.debug("parsing: line = %r", line)
306-
diag = parse_line(line, document)
307-
if diag:
308-
diagnostics.append(diag)
306+
for line in report.splitlines():
307+
log.debug("parsing: line = %r", line)
308+
diag = parse_line(line, document)
309+
if diag:
310+
diagnostics.append(diag)
309311

310-
log.info("pylsp-mypy len(diagnostics) = %s", len(diagnostics))
312+
log.info("pylsp-mypy len(diagnostics) = %s", len(diagnostics))
311313

312-
last_diagnostics[document.path] = diagnostics
313-
return diagnostics
314+
last_diagnostics[document.path] = diagnostics
315+
return diagnostics
314316

315317

316318
@hookimpl

0 commit comments

Comments
 (0)