| Viewing file:  utils.py (3.67 KB)      -rw-r--r-- Select action/file-type:
 
  (+) |  (+) |  (+) | Code (+) | Session (+) |  (+) | SDB (+) |  (+) |  (+) |  (+) |  (+) |  (+) | 
 
# 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
 
 """Utils for the 'pylint-config' command."""
 
 from __future__ import annotations
 
 import sys
 from collections.abc import Callable
 from pathlib import Path
 from typing import TypeVar
 
 if sys.version_info >= (3, 8):
 from typing import Literal
 else:
 from typing_extensions import Literal
 
 if sys.version_info >= (3, 10):
 from typing import ParamSpec
 else:
 from typing_extensions import ParamSpec
 
 _P = ParamSpec("_P")
 _ReturnValueT = TypeVar("_ReturnValueT", bool, str)
 
 SUPPORTED_FORMATS = {"t", "toml", "i", "ini"}
 YES_NO_ANSWERS = {"y", "yes", "n", "no"}
 
 
 class InvalidUserInput(Exception):
 """Raised whenever a user input is invalid."""
 
 def __init__(self, valid_input: str, input_value: str, *args: object) -> None:
 self.valid = valid_input
 self.input = input_value
 super().__init__(*args)
 
 
 def should_retry_after_invalid_input(
 func: Callable[_P, _ReturnValueT]
 ) -> Callable[_P, _ReturnValueT]:
 """Decorator that handles InvalidUserInput exceptions and retries."""
 
 def inner_function(*args: _P.args, **kwargs: _P.kwargs) -> _ReturnValueT:
 called_once = False
 while True:
 try:
 return func(*args, **kwargs)
 except InvalidUserInput as exc:
 if called_once and exc.input == "exit()":
 print("Stopping 'pylint-config'.")
 sys.exit()
 print(f"Answer should be one of {exc.valid}.")
 print("Type 'exit()' if you want to exit the program.")
 called_once = True
 
 return inner_function
 
 
 @should_retry_after_invalid_input
 def get_and_validate_format() -> Literal["toml", "ini"]:
 """Make sure that the output format is either .toml or .ini."""
 # pylint: disable-next=bad-builtin
 format_type = input(
 "Please choose the format of configuration, (T)oml or (I)ni (.cfg): "
 ).lower()
 
 if format_type not in SUPPORTED_FORMATS:
 raise InvalidUserInput(", ".join(sorted(SUPPORTED_FORMATS)), format_type)
 
 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 not 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_minimal_setting() -> bool:
 """Ask the user if they want to use the minimal setting."""
 return validate_yes_no(
 "Do you want a minimal configuration without comments or default values?", "no"
 )
 
 
 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
 
 |