diff options
author | Daniƫl van Noord <13665637+DanielNoord@users.noreply.github.com> | 2022-05-22 17:46:16 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-22 17:46:16 +0200 |
commit | e5e4b213f163f7a55474db5dcb83bd8d5304fbba (patch) | |
tree | 742595b0725cd21525dfcc7eac686dc276254399 /pylint/config | |
parent | 055c1920140ebf36501d30307d5ab86965ae185f (diff) | |
download | pylint-git-e5e4b213f163f7a55474db5dcb83bd8d5304fbba.tar.gz |
Allow specifying an output file when generating a configuration file (#6662)
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
Diffstat (limited to 'pylint/config')
-rw-r--r-- | pylint/config/_pylint_config/generate_command.py | 15 | ||||
-rw-r--r-- | pylint/config/_pylint_config/utils.py | 47 |
2 files changed, 58 insertions, 4 deletions
diff --git a/pylint/config/_pylint_config/generate_command.py b/pylint/config/_pylint_config/generate_command.py index 5dc2a10dc..325c71333 100644 --- a/pylint/config/_pylint_config/generate_command.py +++ b/pylint/config/_pylint_config/generate_command.py @@ -8,6 +8,7 @@ from __future__ import annotations import warnings +from io import StringIO from typing import TYPE_CHECKING from pylint.config._pylint_config import utils @@ -21,13 +22,23 @@ def generate_interactive_config(linter: PyLinter) -> None: print("Starting interactive pylint configuration generation") format_type = utils.get_and_validate_format() + to_file, output_file_name = utils.get_and_validate_output_file() if format_type == "toml": - print(linter._generate_config_file()) + config_string = linter._generate_config_file() else: + output_stream = StringIO() with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) - linter.generate_config(skipsections=("Commands",)) + linter.generate_config(stream=output_stream, skipsections=("Commands",)) + config_string = output_stream.getvalue() + + if to_file: + with open(output_file_name, "w", encoding="utf-8") as f: + print(config_string, file=f) + print(f"Wrote configuration file to {output_file_name.resolve()}") + else: + print(config_string) def handle_generate_command(linter: PyLinter) -> int: diff --git a/pylint/config/_pylint_config/utils.py b/pylint/config/_pylint_config/utils.py index 77b5491c0..0534340b1 100644 --- a/pylint/config/_pylint_config/utils.py +++ b/pylint/config/_pylint_config/utils.py @@ -8,6 +8,7 @@ from __future__ import annotations import sys from collections.abc import Callable +from pathlib import Path if sys.version_info >= (3, 8): from typing import Literal @@ -22,6 +23,7 @@ else: _P = ParamSpec("_P") SUPPORTED_FORMATS = {"t", "toml", "i", "ini"} +YES_NO_ANSWERS = {"y", "yes", "n", "no"} class InvalidUserInput(Exception): @@ -33,10 +35,12 @@ class InvalidUserInput(Exception): super().__init__(*args) -def should_retry_after_invalid_input(func: Callable[_P, str]) -> Callable[_P, str]: +def should_retry_after_invalid_input( + func: Callable[_P, str | bool] +) -> Callable[_P, str | bool]: """Decorator that handles InvalidUserInput exceptions and retries.""" - def inner_function(*args: _P.args, **kwargs: _P.kwargs) -> str: + def inner_function(*args: _P.args, **kwargs: _P.kwargs) -> str | bool: called_once = False while True: try: @@ -66,3 +70,42 @@ def get_and_validate_format() -> Literal["toml", "ini"]: if format_type.startswith("t"): return "toml" return "ini" + + +@should_retry_after_invalid_input +def validate_yes_no(question: str, default: Literal["yes", "no"] | None) -> bool: + """Validate that a yes or no answer is correct.""" + question = f"{question} (y)es or (n)o " + if default: + question += f" (default={default}) " + # pylint: disable-next=bad-builtin + answer = input(question).lower() + + if answer == "" and default: + answer = default + + if answer not in YES_NO_ANSWERS: + raise InvalidUserInput(", ".join(sorted(YES_NO_ANSWERS)), answer) + + return answer.startswith("y") + + +def get_and_validate_output_file() -> tuple[bool, Path]: + """Make sure that the output file is correct.""" + to_file = validate_yes_no("Do you want to write the output to a file?", "no") + + if not to_file: + return False, Path() + + # pylint: disable-next=bad-builtin + file_name = Path(input("What should the file be called: ")) + if file_name.exists(): + overwrite = validate_yes_no( + f"{file_name} already exists. Are you sure you want to overwrite?", "no" + ) + + if not overwrite: + return False, file_name + return True, file_name + + return True, file_name |