-
Notifications
You must be signed in to change notification settings - Fork 7
/
console.py
96 lines (82 loc) · 2.9 KB
/
console.py
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
"""Functions for user interaction at the terminal/console."""
from typing import Any, Callable, Optional, Sequence, TypeVar
TItem = TypeVar("TItem")
def ask(prompt: str = "", default: str = "") -> str:
"""Print the ``prompt``, get user's answer, return it -- or a default."""
if prompt:
if default:
prompt = prompt + " [" + default + "]"
prompt = prompt + " "
answer = None
while not answer:
answer = input(prompt)
if default and not answer:
return default
return answer
def bool_input(prompt: str, default: Optional[bool] = None) -> bool:
"""Print ``prompt``; return True or False based on the user's choice."""
if default is None:
choices = " (y/n) "
elif default:
choices = " (Y/n) "
else:
choices = " (y/N) "
opt = input(prompt + choices).lower()
if opt == "y":
return True
elif opt == "n":
return False
elif not opt and default is not None:
return default
else: # Invalid answer, let's ask again
return bool_input(prompt)
def int_input(prompt: str) -> Optional[int]:
"""Print ``prompt``; ensure the user enters an integer and return it."""
text = input(prompt + " ")
if not text:
return None
try:
number = int(text)
except ValueError:
print("No, you must type an integer.")
return int_input(prompt)
return number
def pick_one_of(
options: Sequence[TItem],
prompt: str = "Pick one: ",
to_str: Optional[Callable] = None,
) -> TItem:
"""Let the user choose an item (from a sequence of options) by number.
``to_str()`` is a callback that must take an item as argument and must
return a corresponding string to be displayed.
"""
alist = options if isinstance(options, list) else list(options)
for ndx, item in enumerate(alist, 1):
print(str(ndx).rjust(2) + ". " + (to_str(item) if to_str else str(item)))
while True:
try:
opt = int(input(prompt))
except ValueError:
continue
assert opt > 0 and opt <= len(alist), "Number outside list bounds."
return alist[opt - 1]
def screen_header(text: str, decor: str = "=", max: int = 79) -> str:
"""Return a header to be displayed on screen, by decorating ``text``."""
text = str(text)
available = max - len(text)
if available > 3:
text = " " + text + " "
available -= 4
else:
return text
req_space = len(decor) * 2
while available >= req_space:
text = decor + text + decor
available -= req_space
if len(text) == available - len(decor): # Add just one more =
text += decor # in order to fill the whole screen
available -= len(decor)
return text
def announce(*a: str) -> None:
"""Make this message stand out from all the noise in the console."""
print("******** ", *a)