File: confirm.py

package info (click to toggle)
python-questionary 2.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 960 kB
  • sloc: python: 3,917; makefile: 66
file content (133 lines) | stat: -rw-r--r-- 4,085 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
from typing import Any
from typing import Optional

from prompt_toolkit import PromptSession
from prompt_toolkit.formatted_text import to_formatted_text
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.keys import Keys
from prompt_toolkit.styles import Style

from questionary.constants import DEFAULT_QUESTION_PREFIX
from questionary.constants import NO
from questionary.constants import NO_OR_YES
from questionary.constants import YES
from questionary.constants import YES_OR_NO
from questionary.question import Question
from questionary.styles import merge_styles_default


def confirm(
    message: str,
    default: bool = True,
    qmark: str = DEFAULT_QUESTION_PREFIX,
    style: Optional[Style] = None,
    auto_enter: bool = True,
    instruction: Optional[str] = None,
    **kwargs: Any,
) -> Question:
    """A yes or no question. The user can either confirm or deny.

    This question type can be used to prompt the user for a confirmation
    of a yes-or-no question. If the user just hits enter, the default
    value will be returned.

    Example:
        >>> import questionary
        >>> questionary.confirm("Are you amazed?").ask()
        ? Are you amazed? Yes
        True

    .. image:: ../images/confirm.gif

    This is just a really basic example, the prompt can be customised using the
    parameters.


    Args:
        message: Question text.

        default: Default value will be returned if the user just hits
                 enter.

        qmark: Question prefix displayed in front of the question.
               By default this is a ``?``.

        style: A custom color and style for the question parts. You can
               configure colors as well as font types for different elements.

        auto_enter: If set to `False`, the user needs to press the 'enter' key to
            accept their answer. If set to `True`, a valid input will be
            accepted without the need to press 'Enter'.

        instruction: A message describing how to proceed through the
                     confirmation prompt.
    Returns:
        :class:`Question`: Question instance, ready to be prompted (using `.ask()`).
    """
    merged_style = merge_styles_default([style])

    status = {"answer": None, "complete": False}

    def get_prompt_tokens():
        tokens = []

        tokens.append(("class:qmark", qmark))
        tokens.append(("class:question", " {} ".format(message)))

        if instruction is not None:
            tokens.append(("class:instruction", instruction))
        elif not status["complete"]:
            _instruction = YES_OR_NO if default else NO_OR_YES
            tokens.append(("class:instruction", "{} ".format(_instruction)))

        if status["answer"] is not None:
            answer = YES if status["answer"] else NO
            tokens.append(("class:answer", answer))

        return to_formatted_text(tokens)

    def exit_with_result(event):
        status["complete"] = True
        event.app.exit(result=status["answer"])

    bindings = KeyBindings()

    @bindings.add(Keys.ControlQ, eager=True)
    @bindings.add(Keys.ControlC, eager=True)
    def _(event):
        event.app.exit(exception=KeyboardInterrupt, style="class:aborting")

    @bindings.add("n")
    @bindings.add("N")
    def key_n(event):
        status["answer"] = False
        if auto_enter:
            exit_with_result(event)

    @bindings.add("y")
    @bindings.add("Y")
    def key_y(event):
        status["answer"] = True
        if auto_enter:
            exit_with_result(event)

    @bindings.add(Keys.ControlH)
    def key_backspace(event):
        status["answer"] = None

    @bindings.add(Keys.ControlM, eager=True)
    def set_answer(event):
        if status["answer"] is None:
            status["answer"] = default

        exit_with_result(event)

    @bindings.add(Keys.Any)
    def other(event):
        """Disallow inserting other text."""

    return Question(
        PromptSession(
            get_prompt_tokens, key_bindings=bindings, style=merged_style, **kwargs
        ).app
    )