Skip to content

Commit

Permalink
Add Ignore Patterns (#182)
Browse files Browse the repository at this point in the history
* Update packages

* Add Ignore Patterns and Include stdlib

* Remove include std lib
  • Loading branch information
karthiknadig authored Oct 20, 2023
1 parent ffbb102 commit 96d4197
Show file tree
Hide file tree
Showing 22 changed files with 945 additions and 557 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Mypy extension for Visual Studio Code

A Visual Studio Code extension with support for the `mypy` linter. The extension ships with `mypy=1.5.1`.
A Visual Studio Code extension with support for the `mypy` linter. The extension ships with `mypy=1.6.1`.

For more information on `mypy`, see https://www.mypy-lang.org/.

Expand All @@ -20,13 +20,15 @@ If you want to disable mypy, you can [disable this extension](https://code.visua
| Settings | Default | Description |
| ----------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| mypy-type-checker.args | `[]` | Custom arguments passed to `mypy`. E.g `"mypy-type-checker.args" = ["--config-file=<file>"]` |
| mypy-type-checker.cwd | `${workspaceFolder}` | This setting specifies the working directory for `mypy`. By default, it uses the root directory of the workspace `${workspaceFolder}`. If you want `mypy` to operate within the directory of the file currently being linted, you can set this to `${fileDirname}`. |
| mypy-type-checker.severity | `{ "error": "Error", "note": "Information" }` | Controls mapping of severity from `mypy` to VS Code severity when displaying in the problems window. You can override specific `mypy` error codes `{ "error": "Error", "note": "Information", "name-defined": "Warning" }` |
| mypy-type-checker.path | `[]` | Setting to provide custom `mypy` executable. This will slow down linting, since we will have to run `mypy` executable every time or file save or open. Example 1: `["~/global_env/mypy"]` Example 2: `["conda", "run", "-n", "lint_env", "python", "-m", "mypy"]` |
| mypy-type-checker.interpreter | `[]` | Path to a Python interpreter to use to run the linter server. When set to `[]`, the interpreter for the workspace is obtained from `ms-python.python` extension. If set to some path, that path takes precedence, and the Python extension is not queried for the interpreter. |
| mypy-type-checker.importStrategy | `useBundled` | Setting to choose where to load `mypy` from. `useBundled` picks mypy bundled with the extension. `fromEnvironment` uses `mypy` available in the environment. |
| mypy-type-checker.showNotifications | `off` | Setting to control when a notification is shown. |
| mypy-type-checker.reportingScope | `file` | (experimental) Setting to control if problems are reported for files open in the editor (`file`) or for the entire workspace (`workspace`). |
| mypy-type-checker.preferDaemon | true | (experimental) Setting to control how to invoke mypy. If true, `dmypy` is preferred over mypy; otherwise, mypy is preferred. Be aware, that the latter may slow down linting since it requires the `mypy` executable to be run whenever a file is saved or opened. Note that this setting will be overridden if `mypy-type-checker.path` is set. |
| mypy-type-checker.preferDaemon | `true` | (experimental) Setting to control how to invoke mypy. If true, `dmypy` is preferred over mypy; otherwise, mypy is preferred. Be aware, that the latter may slow down linting since it requires the `mypy` executable to be run whenever a file is saved or opened. Note that this setting will be overridden if `mypy-type-checker.path` is set. |
| mypy-type-checker.ignorePatterns | `[]` | Glob patterns used to exclude files and directories from being linted. |

## Commands

Expand Down
88 changes: 73 additions & 15 deletions bundled/tool/lsp_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import pathlib
import re
import sys
import sysconfig
import tempfile
import traceback
import uuid
Expand All @@ -28,6 +29,26 @@ def update_sys_path(path_to_add: str, strategy: str) -> None:
sys.path.append(path_to_add)


# **********************************************************
# Update PATH before running anything.
# **********************************************************
def update_environ_path() -> None:
"""Update PATH environment variable with the 'scripts' directory.
Windows: .venv/Scripts
Linux/MacOS: .venv/bin
"""
scripts = sysconfig.get_path("scripts")
paths_variants = ["Path", "PATH"]

for var_name in paths_variants:
if var_name in os.environ:
paths = os.environ[var_name].split(os.pathsep)
if scripts not in paths:
paths.insert(0, scripts)
os.environ[var_name] = os.pathsep.join(paths)
break


# Ensure that we can import LSP libraries, and other bundled libraries.
BUNDLE_DIR = pathlib.Path(__file__).parent.parent
BUNDLED_LIBS = os.fspath(BUNDLE_DIR / "libs")
Expand All @@ -37,6 +58,7 @@ def update_sys_path(path_to_add: str, strategy: str) -> None:
BUNDLED_LIBS,
os.getenv("LS_IMPORT_STRATEGY", "useBundled"),
)
update_environ_path()

# **********************************************************
# Imports needed for the language server goes below this.
Expand Down Expand Up @@ -117,7 +139,7 @@ def _run_unidentified_tool(
This is supposed to be called only in `get_mypy_info`.
"""
cwd = settings["cwd"]
cwd = get_cwd(settings, None)

if settings["path"]:
argv = settings["path"]
Expand Down Expand Up @@ -158,7 +180,7 @@ def did_close(params: lsp.DidCloseTextDocumentParams) -> None:
settings = _get_settings_by_document(document)
if settings["reportingScope"] == "file":
# Publishing empty diagnostics to clear the entries for this file.
LSP_SERVER.publish_diagnostics(document.uri, [])
_clear_diagnostics(document)


def _is_empty_diagnostics(
Expand All @@ -175,6 +197,10 @@ def _is_empty_diagnostics(
_reported_file_paths = set()


def _clear_diagnostics(document: workspace.Document) -> None:
LSP_SERVER.publish_diagnostics(document.uri, [])


def _linting_helper(document: workspace.Document) -> None:
global _reported_file_paths
try:
Expand All @@ -183,6 +209,28 @@ def _linting_helper(document: workspace.Document) -> None:
# deep copy here to prevent accidentally updating global settings.
settings = copy.deepcopy(_get_settings_by_document(document))

if str(document.uri).startswith("vscode-notebook-cell"):
# We don't support running mypy on notebook cells.
log_warning(f"Skipping notebook cells [Not Supported]: {str(document.uri)}")
_clear_diagnostics(document)
return None

if settings["reportingScope"] == "file" and utils.is_stdlib_file(document.path):
log_warning(
f"Skipping standard library file (stdlib excluded): {document.path}"
)
_clear_diagnostics(document)
return None

if settings["reportingScope"] == "file" and utils.is_match(
settings["ignorePatterns"], document.path
):
log_warning(
f"Skipping file due to `mypy-type-checker.ignorePatterns` match: {document.path}"
)
_clear_diagnostics(document)
return None

version = get_mypy_info(settings).version
if (version.major, version.minor) >= (0, 991) and sys.version_info >= (3, 8):
extra_args += ["--show-error-end"]
Expand Down Expand Up @@ -210,15 +258,15 @@ def _linting_helper(document: workspace.Document) -> None:
if _is_empty_diagnostics(document.path, parse_results):
# Ensure that if nothing is returned for this document, at least
# an empty diagnostic is returned to clear any old errors out.
LSP_SERVER.publish_diagnostics(document.uri, [])
_clear_diagnostics(document)

if reportingScope == "workspace":
for file_path in _reported_file_paths:
if file_path not in parse_results:
uri = uris.from_fs_path(file_path)
LSP_SERVER.publish_diagnostics(uri, [])
else:
LSP_SERVER.publish_diagnostics(document.uri, [])
_clear_diagnostics(document)
except Exception:
LSP_SERVER.show_message_log(
f"Linting failed with error:\r\n{traceback.format_exc()}",
Expand Down Expand Up @@ -447,10 +495,12 @@ def _get_global_defaults():
"note": "Information",
},
),
"ignorePatterns": [],
"importStrategy": GLOBAL_SETTINGS.get("importStrategy", "useBundled"),
"showNotifications": GLOBAL_SETTINGS.get("showNotifications", "off"),
"extraPaths": GLOBAL_SETTINGS.get("extraPaths", []),
"reportingScope": GLOBAL_SETTINGS.get("reportingScope", "file"),
"preferDaemon": GLOBAL_SETTINGS.get("preferDaemon", True),
}


Expand Down Expand Up @@ -590,27 +640,35 @@ def _get_env_vars(settings: Dict[str, Any]) -> Dict[str, str]:
return new_env


def get_cwd(settings: Dict[str, Any], document: Optional[workspace.Document]) -> str:
"""Returns cwd for the given settings and document."""
if settings["cwd"] == "${workspaceFolder}":
return settings["workspaceFS"]

if settings["cwd"] == "${fileDirname}":
if document is not None:
return os.fspath(pathlib.Path(document.path).parent)
return settings["workspaceFS"]

return settings["cwd"]


def _run_tool_on_document(
document: workspace.Document,
extra_args: Sequence[str] = [],
extra_args: Sequence[str] = None,
) -> utils.RunResult | None:
"""Runs tool on the given document.
if use_stdin is true then contents of the document is passed to the
tool via stdin.
"""
if str(document.uri).startswith("vscode-notebook-cell"):
# We don't support running mypy on notebook cells.
log_to_output("Skipping mypy on notebook cells.")
return None

if utils.is_stdlib_file(document.path):
log_to_output("Skipping mypy on stdlib file: " + document.path)
return None
if extra_args is None:
extra_args = []

# deep copy here to prevent accidentally updating global settings.
settings = copy.deepcopy(_get_settings_by_document(document))
cwd = settings["cwd"]

cwd = get_cwd(settings, document)

if settings["path"]:
argv = settings["path"]
Expand Down Expand Up @@ -646,7 +704,7 @@ def _run_dmypy_command(
log_error(f"dmypy command called in non-daemon context: {command}")
raise ValueError(f"dmypy command called in non-daemon context: {command}")

cwd = settings["cwd"]
cwd = get_cwd(settings, None)

if settings["path"]:
argv = settings["path"]
Expand Down
7 changes: 7 additions & 0 deletions bundled/tool/lsp_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ def is_stdlib_file(file_path: str) -> bool:
return any(normalized_path.startswith(path) for path in _stdlib_paths)


def is_match(patterns: List[str], file_path: str) -> bool:
"""Returns true if the file matches one of the glob patterns."""
if not patterns:
return False
return any(pathlib.Path(file_path).match(pattern) for pattern in patterns)


# pylint: disable-next=too-few-public-methods
class RunResult:
"""Object to hold result from running tool."""
Expand Down
Loading

0 comments on commit 96d4197

Please sign in to comment.