|
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