diff options
author | Daniƫl van Noord <13665637+DanielNoord@users.noreply.github.com> | 2022-04-16 21:02:34 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-16 21:02:34 +0200 |
commit | 86ed7fa47b501bfbab46a3fe84e02aea5a51376d (patch) | |
tree | 0c7b9584c5be97c2b31e0058d9f89dde0d704f00 /doc/exts | |
parent | 1de6da157c260c5a1398bc59c5f2b57abc4912a6 (diff) | |
download | pylint-git-86ed7fa47b501bfbab46a3fe84e02aea5a51376d.tar.gz |
Create a documentation page with all options (#6346)
Diffstat (limited to 'doc/exts')
-rw-r--r-- | doc/exts/pylint_options.py | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/doc/exts/pylint_options.py b/doc/exts/pylint_options.py new file mode 100644 index 000000000..4a6e743ef --- /dev/null +++ b/doc/exts/pylint_options.py @@ -0,0 +1,186 @@ +# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html +# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt + +"""Script used to generate the options page.""" + +from __future__ import annotations + +import re +from collections import defaultdict +from inspect import getmodule +from pathlib import Path +from typing import Dict, List, NamedTuple + +import tomlkit +from sphinx.application import Sphinx + +from pylint.checkers import initialize as initialize_checkers +from pylint.checkers.base_checker import BaseChecker +from pylint.extensions import initialize as initialize_extensions +from pylint.lint import PyLinter +from pylint.typing import OptionDict +from pylint.utils import get_rst_title + + +class OptionsData(NamedTuple): + name: str + optdict: OptionDict + checker: BaseChecker + extension: bool + + +OptionsDataDict = Dict[str, List[OptionsData]] + +PYLINT_BASE_PATH = Path(__file__).resolve().parent.parent.parent +"""Base path to the project folder.""" + +PYLINT_USERGUIDE_PATH = PYLINT_BASE_PATH / "doc" / "user_guide" +"""Path to the messages documentation folder.""" + + +def _register_all_checkers_and_extensions(linter: PyLinter) -> None: + """Registers all checkers and extensions found in the default folders.""" + initialize_checkers(linter) + initialize_extensions(linter) + + +def _get_all_options(linter: PyLinter) -> OptionsDataDict: + """Get all options registered to a linter and return the data.""" + all_options: OptionsDataDict = defaultdict(list) + for checker in sorted(linter.get_checkers()): + ch_name = checker.name + for option in checker.options: + all_options[ch_name].append( + OptionsData( + option[0], + option[1], + checker, + getmodule(checker).__name__.startswith("pylint.extensions."), # type: ignore[union-attr] + ) + ) + + return all_options + + +def _create_checker_section( + checker: str, options: list[OptionsData], linter: PyLinter +) -> str: + checker_string = get_rst_title(f"``{checker.capitalize()}`` Checker", "^") + + toml_doc = tomlkit.document() + pylint_tool_table = tomlkit.table(is_super_table=True) + toml_doc.add(tomlkit.key(["tool", "pylint"]), pylint_tool_table) + + checker_table = tomlkit.table() + + for option in sorted(options, key=lambda x: x.name): + checker_string += get_rst_title(f"--{option.name}", '"') + checker_string += f"\nDescription:\n *{option.optdict.get('help')}*\n\n" + if option.optdict.get("default") == "": + checker_string += 'Default:\n ``""``\n\n\n' + else: + checker_string += f"Default:\n ``{option.optdict.get('default')}``\n\n\n" + + # Start adding the option to the toml example + if option.optdict.get("hide_from_config_file"): + continue + + # Get current value of option + value = getattr(linter.config, option.name.replace("-", "_")) + + # Create a comment if the option has no value + if value is None: + checker_table.add(tomlkit.comment(f"{option.name} =")) + checker_table.add(tomlkit.nl()) + continue + + # Tomlkit doesn't support regular expressions + if isinstance(value, re.Pattern): + value = value.pattern + elif ( + isinstance(value, (list, tuple)) + and value + and isinstance(value[0], re.Pattern) + ): + value = [i.pattern for i in value] + + # Add to table + checker_table.add(option.name, value) + checker_table.add(tomlkit.nl()) + + pylint_tool_table.add(options[0].checker.name.lower(), checker_table) + toml_string = "\n".join(f" {i}" for i in tomlkit.dumps(toml_doc).split("\n")) + checker_string += f""" +.. raw:: html + + <details> + <summary><a>Example configuration section</a></summary> + +**Note:** Only ``pylint.tool`` is required, the section title is not. These are the default values. + +.. code-block:: toml + +{toml_string} + +.. raw:: html + + </details> +""" + + return checker_string + + +def _write_options_page(options: OptionsDataDict, linter: PyLinter) -> None: + """Create or overwrite the options page.""" + sections: list[str] = [get_rst_title("Standard Checkers:", "^")] + found_extensions = False + + for checker, checker_options in options.items(): + if not found_extensions and checker_options[0].extension: + sections.append(get_rst_title("Extensions:", "^")) + found_extensions = True + sections.append(_create_checker_section(checker, checker_options, linter)) + + sections_string = "\n\n".join(sections) + with open( + PYLINT_USERGUIDE_PATH / "configuration" / "all-options.rst", + "w", + encoding="utf-8", + ) as stream: + stream.write( + f""" +{get_rst_title("All pylint options", "=")} + +{sections_string} +""" + ) + + +# pylint: disable-next=unused-argument +def build_options_page(app: Sphinx | None) -> None: + """Overwrite messages files by printing the documentation to a stream. + + Documentation is written in ReST format. + """ + # Create linter, register all checkers and extensions and get all options + linter = PyLinter() + _register_all_checkers_and_extensions(linter) + + options = _get_all_options(linter) + + # Write options page + _write_options_page(options, linter) + + +def setup(app: Sphinx) -> None: + """Connects the extension to the Sphinx process.""" + # Register callback at the builder-inited Sphinx event + # See https://www.sphinx-doc.org/en/master/extdev/appapi.html + app.connect("builder-inited", build_options_page) + + +if __name__ == "__main__": + pass + # Uncomment to allow running this script by your local python interpreter + # build_options_page(None) |