"""Module contains the class to create a confirm prompt.""" from typing import TYPE_CHECKING, Any, Callable, List, Optional, Tuple from prompt_toolkit.buffer import ValidationState from prompt_toolkit.keys import Keys from prompt_toolkit.shortcuts import PromptSession from prompt_toolkit.validation import ValidationError from InquirerPy.base import BaseSimplePrompt from InquirerPy.exceptions import InvalidArgument from InquirerPy.utils import ( InquirerPyDefault, InquirerPyKeybindings, InquirerPyMessage, InquirerPySessionResult, InquirerPyStyle, ) if TYPE_CHECKING: from prompt_toolkit.input.base import Input from prompt_toolkit.key_binding.key_processor import KeyPressEvent from prompt_toolkit.output.base import Output __all__ = ["ConfirmPrompt"] class ConfirmPrompt(BaseSimplePrompt): """Create a prompt that provides 2 options (confirm/deny) and controlled via single keypress. A wrapper class around :class:`~prompt_toolkit.shortcuts.PromptSession`. Args: message: The question to ask the user. Refer to :ref:`pages/dynamic:message` documentation for more details. style: An :class:`InquirerPyStyle` instance. Refer to :ref:`Style ` documentation for more details. vi_mode: Used for compatibility . default: Set the default value of the prompt, should be either `True` or `False`. This affects the value returned when user directly hit `enter` key. Refer to :ref:`pages/dynamic:default` documentation for more details. qmark: Question mark symbol. Custom symbol that will be displayed infront of the question before its answered. amark: Answer mark symbol. Custom symbol that will be displayed infront of the question after its answered. instruction: Short instruction to display next to the question. long_instruction: Long instructions to display at the bottom of the prompt. transformer: A function which performs additional transformation on the value that gets printed to the terminal. Different than `filter` parameter, this is only visual effect and won’t affect the actual value returned by :meth:`~InquirerPy.base.simple.BaseSimplePrompt.execute`. Refer to :ref:`pages/dynamic:transformer` documentation for more details. filter: A function which performs additional transformation on the result. This affects the actual value returned by :meth:`~InquirerPy.base.simple.BaseSimplePrompt.execute`. Refer to :ref:`pages/dynamic:filter` documentation for more details. keybindings: Customise the builtin keybindings. Refer to :ref:`pages/kb:Keybindings` for more details. wrap_lines: Soft wrap question lines when question exceeds the terminal width. confirm_letter: Letter used to confirm the prompt. A keybinding will be created for this letter. Default is `y` and pressing `y` will answer the prompt with value `True`. reject_letter: Letter used to reject the prompt. A keybinding will be created for this letter. Default is `n` and pressing `n` will answer the prompt with value `False`. raise_keyboard_interrupt: Raise the :class:`KeyboardInterrupt` exception when `ctrl-c` is pressed. If false, the result will be `None` and the question is skiped. mandatory: Indicate if the prompt is mandatory. If True, then the question cannot be skipped. mandatory_message: Error message to show when user attempts to skip mandatory prompt. session_result: Used internally for :ref:`index:Classic Syntax (PyInquirer)`. input: Used internally and will be removed in future updates. output: Used internally and will be removed in future updates. Examples: >>> from InquirerPy import inquirer >>> result = inquirer.confirm(message="Confirm?").execute() >>> print(result) True """ def __init__( self, message: InquirerPyMessage, style: Optional[InquirerPyStyle] = None, default: InquirerPyDefault = False, vi_mode: bool = False, qmark: str = "?", amark: str = "?", instruction: str = "", long_instruction: str = "", transformer: Optional[Callable[[bool], Any]] = None, filter: Optional[Callable[[bool], Any]] = None, keybindings: Optional[InquirerPyKeybindings] = None, wrap_lines: bool = True, confirm_letter: str = "y", reject_letter: str = "n", raise_keyboard_interrupt: bool = True, mandatory: bool = True, mandatory_message: str = "Mandatory prompt", session_result: Optional[InquirerPySessionResult] = None, input: Optional["Input"] = None, output: Optional["Output"] = None, ) -> None: vi_mode = False super().__init__( message=message, style=style, vi_mode=vi_mode, qmark=qmark, amark=amark, instruction=instruction, transformer=transformer, filter=filter, default=default, wrap_lines=wrap_lines, raise_keyboard_interrupt=raise_keyboard_interrupt, mandatory=mandatory, mandatory_message=mandatory_message, session_result=session_result, ) if not isinstance(self._default, bool): raise InvalidArgument( f"{type(self).__name__} argument default should be type of bool" ) self._confirm_letter = confirm_letter self._reject_letter = reject_letter if not keybindings: keybindings = {} self.kb_maps = { "confirm": [ {"key": self._confirm_letter}, {"key": self._confirm_letter.upper()}, ], "reject": [ {"key": self._reject_letter}, {"key": self._reject_letter.upper()}, ], "any": [{"key": Keys.Any}], **keybindings, } self.kb_func_lookup = { "confirm": [{"func": self._handle_confirm}], "reject": [{"func": self._handle_reject}], "any": [{"func": lambda _: None}], } self._keybinding_factory() self._session = PromptSession( message=self._get_prompt_message, key_bindings=self._kb, style=self._style, wrap_lines=self._wrap_lines, bottom_toolbar=[("class:long_instruction", long_instruction)] if long_instruction else None, input=input, output=output, ) def _set_error(self, message: str) -> None: self._session.default_buffer.validation_state = ValidationState.INVALID self._session.default_buffer.validation_error = ValidationError(message=message) def _handle_reject(self, event) -> None: self._session.default_buffer.text = "" self.status["answered"] = True self.status["result"] = False event.app.exit(result=False) def _handle_confirm(self, event) -> None: self._session.default_buffer.text = "" self.status["answered"] = True self.status["result"] = True event.app.exit(result=True) def _handle_enter(self, event: "KeyPressEvent") -> None: self.status["answered"] = True self.status["result"] = self._default event.app.exit(result=self._default) def _get_prompt_message(self) -> List[Tuple[str, str]]: """Get message to display infront of the input buffer. Returns: Formatted text in list of tuple format. """ if not self.instruction: pre_answer = ( "class:instruction", " (%s/%s) " % (self._confirm_letter.upper(), self._reject_letter) if self._default else " (%s/%s) " % (self._confirm_letter, self._reject_letter.upper()), ) else: pre_answer = ("class:instruction", " %s " % self.instruction) post_answer = ("class:answer", " Yes" if self.status["result"] else " No") return super()._get_prompt_message(pre_answer, post_answer) def _run(self) -> bool: return self._session.prompt() async def _run_async(self) -> Any: return await self._session.prompt_async()