diff --git a/docs/source/config_file.rst b/docs/source/config_file.rst index 7abd1f02db68..a1aae90508ba 100644 --- a/docs/source/config_file.rst +++ b/docs/source/config_file.rst @@ -802,11 +802,11 @@ section of the command line docs. .. confval:: extra_checks - :type: boolean - :default: False + :type: boolean + :default: False - This flag enables additional checks that are technically correct but may be impractical. - See :option:`mypy --extra-checks` for more info. + This flag enables additional checks that are technically correct but may be impractical. + See :option:`mypy --extra-checks` for more info. .. confval:: implicit_reexport @@ -830,39 +830,39 @@ section of the command line docs. .. confval:: strict_equality - :type: boolean - :default: False + :type: boolean + :default: False - Prohibit equality checks, identity checks, and container checks between - non-overlapping types (except ``None``). + Prohibit equality checks, identity checks, and container checks between + non-overlapping types (except ``None``). .. confval:: strict_equality_for_none - :type: boolean - :default: False + :type: boolean + :default: False - Include ``None`` in strict equality checks (requires :confval:`strict_equality` - to be activated). + Include ``None`` in strict equality checks (requires :confval:`strict_equality` + to be activated). .. confval:: strict_bytes - :type: boolean - :default: False + :type: boolean + :default: False - Disable treating ``bytearray`` and ``memoryview`` as subtypes of ``bytes``. - This will be enabled by default in *mypy 2.0*. + Disable treating ``bytearray`` and ``memoryview`` as subtypes of ``bytes``. + This will be enabled by default in *mypy 2.0*. .. confval:: strict - :type: boolean - :default: False + :type: boolean + :default: False - Enable all optional error checking flags. You can see the list of - flags enabled by strict mode in the full :option:`mypy --help` - output. + Enable all optional error checking flags. You can see the list of + flags enabled by strict mode in the full :option:`mypy --help` + output. - Note: the exact list of flags enabled by :confval:`strict` may - change over time. + Note: the exact list of flags enabled by :confval:`strict` may + change over time. Configuring error messages diff --git a/misc/make_schema.py b/misc/make_schema.py new file mode 100644 index 000000000000..176023df39f0 --- /dev/null +++ b/misc/make_schema.py @@ -0,0 +1,119 @@ +from __future__ import annotations + +import dataclasses +import json +import re +import sys +import textwrap +from collections.abc import Generator, Sequence +from pathlib import Path +from typing import Any + +DIR = Path(__file__).parent.resolve() + +assert sys.version_info > (3, 9) + + +@dataclasses.dataclass(frozen=True) +class ConfigOpt: + name: str + type_str: str + is_global: bool + description: str + default: str | None + + def define(self) -> dict[str, str]: + retval: dict[str, Any] = {"description": self.description} + if self.default is not None: + match self.type_str: + case "boolean": + retval["default"] = {"true": True, "false": False}[self.default.lower()] + case "integer": + retval["default"] = int(self.default) + case "string": + retval["default"] = self.default.strip("`") + case _: + msg = f"Default not supported for {self.type_str}" + raise RuntimeError(msg) + match self.type_str: + case "boolean" | "integer" | "string": + retval["type"] = self.type_str + case "comma-separated list of strings" | "regular expression": + retval["oneOf"] = [ + {"type": "string"}, + {"type": "array", "items": {"type": "string"}}, + ] + case _: + msg = f"{self.type_str} not supported for type" + raise RuntimeError(msg) + + return retval + + +def parse_rst_docs(txt: str) -> Generator[ConfigOpt, None, None]: + for match in re.finditer(r".. confval:: ([^\s]*)\n\n((?: .*\n|\n)*)", txt): + name, body = match.groups() + body = textwrap.dedent(body) + body_match = re.match(r":type: (.*?)\n(?::default: (.*?)\n)?(.*)$", body, re.DOTALL) + assert body_match is not None, f"{name} missing type and default!\n{body!r}" + type_str, default, inner = body_match.groups() + is_global = "only be set in the global section" in body + description = inner.strip().split("\n\n")[0].replace("\n", " ") + # Patches + if name == "mypy_path": + type_str = "comma-separated list of strings" + yield ConfigOpt( + name=name, + type_str=type_str, + is_global=is_global, + description=description, + default=default, + ) + + +def make_schema(opts: Sequence[ConfigOpt]) -> dict[str, Any]: + definitions = {s.name: s.define() for s in opts} + overrides = {s.name: {"$ref": f"#/properties/{s.name}"} for s in opts if not s.is_global} + module = { + "oneOf": [ + {"type": "string"}, + {"type": "array", "items": {"type": "string"}, "minItems": 1}, + ] + } + + # Improve some fields + definitions["follow_imports"]["enum"] = ["normal", "silent", "skip", "error"] + + # Undocumented fields + definitions["show_error_codes"] = { + "type": "boolean", + "default": True, + "description": "DEPRECATED and UNDOCUMENTED: Now defaults to true, use `hide_error_codes` if you need to disable error codes instead.", + "deprecated": True, + } + + return { + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://json.schemastore.org/partial-mypy.json", + "additionalProperties": False, + "type": "object", + "properties": { + **definitions, + "overrides": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": False, + "required": ["module"], + "minProperties": 2, + "properties": {"module": module, **overrides}, + }, + }, + }, + } + + +if __name__ == "__main__": + filepath = DIR.parent / "docs/source/config_file.rst" + opts = parse_rst_docs(filepath.read_text()) + print(json.dumps(make_schema(list(opts)), indent=2))