radubulimac's picture
fix import issue
2d876d1
"""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 <pages/style:Alternate Syntax>` 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()