|
13 | 13 | import subprocess
|
14 | 14 | from pathlib import Path
|
15 | 15 | import logging
|
| 16 | +from mypy import api as mypy_api |
16 | 17 | from pylsp import hookimpl
|
17 | 18 | from pylsp.workspace import Document, Workspace
|
18 | 19 | from pylsp.config.config import Config
|
19 | 20 | from typing import Optional, Dict, Any, IO, List
|
20 | 21 | import atexit
|
21 | 22 | import collections
|
22 | 23 | import warnings
|
| 24 | +import shutil |
| 25 | +import ast |
23 | 26 |
|
24 | 27 | line_pattern: str = r"((?:^[a-z]:)?[^:]+):(?:(\d+):)?(?:(\d+):)? (\w+): (.*)"
|
25 | 28 |
|
@@ -204,35 +207,65 @@ def pylsp_lint(
|
204 | 207 | args.extend(["--incremental", "--follow-imports", "silent"])
|
205 | 208 | args = apply_overrides(args, overrides)
|
206 | 209 |
|
207 |
| - log.info("executing mypy args = %s", args) |
208 |
| - completed_process = subprocess.run( |
209 |
| - ["mypy", *args], stdout=subprocess.PIPE, stderr=subprocess.PIPE |
210 |
| - ) |
211 |
| - report = completed_process.stdout.decode() |
212 |
| - errors = completed_process.stderr.decode() |
| 210 | + if shutil.which("mypy"): |
| 211 | + # mypy exists on path |
| 212 | + # -> use mypy on path |
| 213 | + log.info("executing mypy args = %s on path", args) |
| 214 | + completed_process = subprocess.run( |
| 215 | + ["mypy", *args], stdout=subprocess.PIPE, stderr=subprocess.PIPE |
| 216 | + ) |
| 217 | + report = completed_process.stdout.decode() |
| 218 | + errors = completed_process.stderr.decode() |
| 219 | + else: |
| 220 | + # mypy does not exist on path, but must exist in the env pylsp-mypy is installed in |
| 221 | + # -> use mypy via api |
| 222 | + log.info("executing mypy args = %s via api", args) |
| 223 | + report, errors, _ = mypy_api.run(args) |
213 | 224 | else:
|
214 | 225 | # If dmypy daemon is non-responsive calls to run will block.
|
215 | 226 | # Check daemon status, if non-zero daemon is dead or hung.
|
216 | 227 | # If daemon is hung, kill will reset
|
217 | 228 | # If daemon is dead/absent, kill will no-op.
|
218 | 229 | # In either case, reset to fresh state
|
219 |
| - completed_process = subprocess.run( |
220 |
| - ["dmypy", *apply_overrides(args, overrides)], stderr=subprocess.PIPE |
221 |
| - ) |
222 |
| - _err = completed_process.stderr.decode() |
223 |
| - _status = completed_process.returncode |
224 |
| - if _status != 0: |
225 |
| - log.info("restarting dmypy from status: %s message: %s", _status, _err.strip()) |
226 |
| - subprocess.run(["dmypy", "kill"]) |
| 230 | + |
| 231 | + if shutil.which("dmypy"): |
| 232 | + # dmypy exists on path |
| 233 | + # -> use mypy on path |
| 234 | + completed_process = subprocess.run(["dmypy", *apply_overrides(args, overrides)], stderr=subprocess.PIPE) |
| 235 | + _err = completed_process.stderr.decode() |
| 236 | + _status = completed_process.returncode |
| 237 | + if _status != 0: |
| 238 | + log.info( |
| 239 | + "restarting dmypy from status: %s message: %s via path", _status, _err.strip() |
| 240 | + ) |
| 241 | + subprocess.run(["dmypy", "kill"]) |
| 242 | + else: |
| 243 | + # dmypy does not exist on path, but must exist in the env pylsp-mypy is installed in |
| 244 | + # -> use dmypy via api |
| 245 | + _, _err, _status = mypy_api.run_dmypy(["status"]) |
| 246 | + if _status != 0: |
| 247 | + log.info( |
| 248 | + "restarting dmypy from status: %s message: %s via api", _status, _err.strip() |
| 249 | + ) |
| 250 | + mypy_api.run_dmypy(["kill"]) |
227 | 251 |
|
228 | 252 | # run to use existing daemon or restart if required
|
229 | 253 | args = ["run", "--"] + apply_overrides(args, overrides)
|
230 |
| - log.info("dmypy run args = %s", args) |
231 |
| - completed_process = subprocess.run( |
232 |
| - ["dmypy", *args], stdout=subprocess.PIPE, stderr=subprocess.PIPE |
233 |
| - ) |
234 |
| - report = completed_process.stdout.decode() |
235 |
| - errors = completed_process.stderr.decode() |
| 254 | + |
| 255 | + if shutil.which("dmypy"): |
| 256 | + # dmypy exists on path |
| 257 | + # -> use mypy on path |
| 258 | + log.info("dmypy run args = %s via path", args) |
| 259 | + completed_process = subprocess.run( |
| 260 | + ["dmypy", *args], stdout=subprocess.PIPE, stderr=subprocess.PIPE |
| 261 | + ) |
| 262 | + report = completed_process.stdout.decode() |
| 263 | + errors = completed_process.stderr.decode() |
| 264 | + else: |
| 265 | + # dmypy does not exist on path, but must exist in the env pylsp-mypy is installed in |
| 266 | + # -> use dmypy via api |
| 267 | + log.info("dmypy run args = %s via api", args) |
| 268 | + report, errors, _ = mypy_api.run_dmypy(args) |
236 | 269 |
|
237 | 270 | log.debug("report:\n%s", report)
|
238 | 271 | log.debug("errors:\n%s", errors)
|
@@ -291,7 +324,7 @@ def init(workspace: str) -> Dict[str, str]:
|
291 | 324 | path = findConfigFile(workspace, ["pylsp-mypy.cfg", "mypy-ls.cfg", "mypy_ls.cfg"])
|
292 | 325 | if path:
|
293 | 326 | with open(path) as file:
|
294 |
| - configuration = eval(file.read()) |
| 327 | + configuration = ast.literal_eval(file.read()) |
295 | 328 |
|
296 | 329 | mypyConfigFile = findConfigFile(workspace, ["mypy.ini", ".mypy.ini"])
|
297 | 330 | mypyConfigFileMap[workspace] = mypyConfigFile
|
|
0 commit comments