summaryrefslogtreecommitdiff
path: root/pylint/config
diff options
context:
space:
mode:
authorDaniƫl van Noord <13665637+DanielNoord@users.noreply.github.com>2022-05-22 17:46:16 +0200
committerGitHub <noreply@github.com>2022-05-22 17:46:16 +0200
commite5e4b213f163f7a55474db5dcb83bd8d5304fbba (patch)
tree742595b0725cd21525dfcc7eac686dc276254399 /pylint/config
parent055c1920140ebf36501d30307d5ab86965ae185f (diff)
downloadpylint-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.py15
-rw-r--r--pylint/config/_pylint_config/utils.py47
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