From 608a8dc4fabb4f3cc5513df743942644e4b0bf16 Mon Sep 17 00:00:00 2001 From: backwardspy Date: Wed, 2 Oct 2024 11:00:11 +0000 Subject: [PATCH 1/2] feat: support custom roots --- README.md | 2 ++ package.json | 12 +++++++++++- src/extension.ts | 23 ++++++++++++++++------- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 2f1162e..c80130e 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,8 @@ To configure the mypy-vscode extension, use the following VS Code settings: * `mypy.targets`: specify a list of target files or folders for mypy to analyze. By default the entire workspace folder is checked. You may prefer to use the `files` option in `mypy.ini` to specify which files mypy should analyze. In that case, you should set `mypy.targets` to an empty array (`[]`). +* `mypy.roots`: Specify a list of root folders. Each root is checked by its own mypy daemon. If not set, the workspace folders are used. This is useful for monorepos when you are not using a normal multi-root workspace. This setting is ignored in multi-root workspaces. + * `mypy.dmypyExecutable`: Path to `dmypy` (the mypy daemon). Either a full path or just a name (which must exist in your PATH). You can use substitutions: `${workspaceFolder}` and `~` (home directory). * `mypy.runUsingActiveInterpreter`: Use the active Python interpreter (selected in the Python extension) to run dmypy itself, instead of the `mypy.dmypyExecutable` setting. Note: your code is always checked against the active interpreter – this setting only controls the interpreter used to run dmypy itself. diff --git a/package.json b/package.json index c567ede..a09cd06 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,16 @@ "uniqueItems": true, "description": "List of paths to analyze, relative to the workspace folder. By default, check the entire workspace folder." }, + "mypy.roots": { + "type": "array", + "default": [], + "scope": "resource", + "items": { + "type": "string" + }, + "uniqueItems": true, + "description": "List of paths to consider as roots, relative to the workspace folder. Each root is checked by its own mypy daemon. If not set, use the workspace folders. This is useful for monorepos when not in a normal multi-root workspace. This setting is ignored in multi-root workspaces." + }, "mypy.checkNotebooks": { "type": "boolean", "default": false, @@ -149,4 +159,4 @@ "shlex": "^2.0.2", "untildify": "^4.0.0" } -} +} \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index 9b6cc69..b763919 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -298,7 +298,7 @@ async function runDmypy( if (ex.stderr) { output(`stderr:\n${ex.stderr}`, currentCheck); if (ex.stderr.indexOf('Daemon crashed!') != -1) { - error = 'the mypy daemon crashed. This is probably a bug in mypy itself, ' + + error = 'the mypy daemon crashed. This is probably a bug in mypy itself, ' + 'see Output panel for details. The daemon will be restarted automatically.' showDetailsButton = true; } else if (ex.stderr.indexOf('There are no .py[i] files in directory') != -1) { @@ -330,7 +330,7 @@ async function runDmypy( output("Retrying command", currentCheck); return await runDmypy(folder, dmypyCommand, mypyArgs, warnIfFailed, successfulExitCodes, addPythonExecutableArgument, currentCheck, false); } else { - error = 'the mypy daemon is stuck. An attempt to kill it and retry failed. ' + + error = 'the mypy daemon is stuck. An attempt to kill it and retry failed. ' + 'This is probably a bug in mypy itself, see Output panel for details.'; showDetailsButton = true; } @@ -387,7 +387,16 @@ async function killDaemon(folder: vscode.Uri, currentCheck: number | undefined, async function recheckWorkspace() { output("Rechecking workspace"); - await forEachFolder(vscode.workspace.workspaceFolders, folder => checkWorkspace(folder.uri)); + // if the user has chosen custom roots with `mypy.roots`, and there is only one workspace folder, check those roots. + const mypyConfig = vscode.workspace.getConfiguration('mypy'); + const roots = mypyConfig.get("roots", []); + if (roots.length > 0 && vscode.workspace.workspaceFolders?.length === 1) { + const base = vscode.workspace.workspaceFolders[0]; + const folders = roots.map(root => vscode.Uri.file(path.join(base.uri.fsPath, root))); + await forEachFolder(folders, folder => checkWorkspace(folder)); + } else { + await forEachFolder(vscode.workspace.workspaceFolders, folder => checkWorkspace(folder.uri)); + } output("Recheck complete"); } @@ -765,7 +774,7 @@ function parseMypyOutput(stdout: string, folder: vscode.Uri) { } } }); - + let fileDiagnostics = new Map(); for (const line of outputLines) { const diagnostic = createDiagnostic(line); @@ -795,7 +804,7 @@ function getLinkUrl(line: MypyOutputLine) { function getFileUri(filePath: string, folder: vscode.Uri) { // By default mypy outputs paths relative to the checked folder. If the user specifies - // `show_absolute_path = True` in the config file, mypy outputs absolute paths. + // `show_absolute_path = True` in the config file, mypy outputs absolute paths. if (!path.isAbsolute(filePath)) { filePath = path.join(folder.fsPath, filePath); } @@ -823,7 +832,7 @@ function createDiagnostic(line: MypyOutputLine) { } } const range = new vscode.Range(lineNo, column, endLineNo, endColumn); - + const diagnostic = new vscode.Diagnostic( range, line.message, @@ -979,7 +988,7 @@ async function filesChanged(files: readonly vscode.Uri[], created = false) { const folder = vscode.workspace.getWorkspaceFolder(file); if (folder === undefined) continue; - + const path = file.fsPath; if (path.endsWith(".py") || path.endsWith(".pyi") || path.endsWith(".ipynb")) { folders.add(folder.uri); From a12675bba489fd5e74925ea259fb2f1671c79553 Mon Sep 17 00:00:00 2001 From: backwardspy Date: Wed, 2 Oct 2024 11:58:26 +0000 Subject: [PATCH 2/2] feat: show recheck type in logs --- src/extension.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/extension.ts b/src/extension.ts index b763919..9c52918 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -386,15 +386,16 @@ async function killDaemon(folder: vscode.Uri, currentCheck: number | undefined, } async function recheckWorkspace() { - output("Rechecking workspace"); // if the user has chosen custom roots with `mypy.roots`, and there is only one workspace folder, check those roots. const mypyConfig = vscode.workspace.getConfiguration('mypy'); const roots = mypyConfig.get("roots", []); if (roots.length > 0 && vscode.workspace.workspaceFolders?.length === 1) { + output("Rechecking custom roots"); const base = vscode.workspace.workspaceFolders[0]; const folders = roots.map(root => vscode.Uri.file(path.join(base.uri.fsPath, root))); await forEachFolder(folders, folder => checkWorkspace(folder)); } else { + output("Rechecking workspace"); await forEachFolder(vscode.workspace.workspaceFolders, folder => checkWorkspace(folder.uri)); } output("Recheck complete");