-
Notifications
You must be signed in to change notification settings - Fork 1
/
UserInput.py
279 lines (250 loc) · 12.7 KB
/
UserInput.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
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
__author__ = 'Justin Scholz'
__copyright__ = "Copyright 2015 - 2017, Justin Scholz"
def recognize_user_input_yes_or_no(user_choice: str, default: bool):
user_input_understood = False
yes = str
no = str
user_choice_answer = "x"
if default:
yes = ""
no = "no"
elif not default:
yes = "yes"
no = ""
if user_choice == yes or user_choice == "y" or user_choice == "yes":
user_choice_answer = True
user_input_understood = True
elif user_choice == no or user_choice == "n" or user_choice == "no":
user_choice_answer = False
user_input_understood = True
return user_choice_answer, user_input_understood
def recognize_user_input_multi_choice(user_choice: str, user_options):
user_input_understood = False
user_choice_answer = int
for answer_index in range(user_options):
try:
if int(user_choice) == answer_index:
user_choice_answer = answer_index
user_input_understood = True
except ValueError:
user_input_understood = False
return user_choice_answer, user_input_understood
def parse_user_input_lower_upper_limit_with_interval(user_choice: float, lower_limit: float, upper_limit: float,
steplength: float):
user_input_understood = False
# First we check that the entered value is in the expected boundaries
if not (user_choice > upper_limit or user_choice < lower_limit):
# then we use mathematics to look whether it matches with our desired step length
reduced = ((user_choice - lower_limit) * steplength)
reduced = round(reduced, 4)
# And do stupid things because computers calculate in base 2 and not base 10
if reduced.is_integer():
user_input_understood = True
return user_choice, user_input_understood
def recognize_user_input(user_choice: str, possibilities: [], default_answer=None):
"""
:param default_answer: the default answer that is returned if user just hits enter
:param user_choice: what the user entered
:param possibilities: a list containing all valid answers, make sure to include "" if you want default answers
with "enter" key pressing
:return: user_chosen_answer: one value of the possibilities passed to this function; user_input_understood: Whether
there was an error parsing the answer or not. Returns true if the input was matched.
"""
user_input_understood = False
user_chosen_answer = str
for answer in possibilities:
try:
if int(user_choice) == answer:
user_chosen_answer = user_choice
user_input_understood = True
except ValueError:
user_input_understood = False
if user_choice == "":
user_chosen_answer = default_answer
user_input_understood = True
return user_chosen_answer, user_input_understood
def ask_user_for_input(question: dict):
"""
:param question: a dictionary as it comes from elsewhere, meaning that it has the keys: "question_title", "question_text",
"default_answer", "option_type" (can be "yes_no", "multi_choice", "free_choice"),
"valid_options" (only needed for multi_choice), "valid_options_lower_limit" and "valid_options_upper_limit" and
"valid_options_steplength" in case of the free_choice. The "default answer" key is in case of a yes/no question
either True or False, in case of free choice, it's a float and in case of multi_choice, it's the index of the answer
out of the valid_options.
:type question: dict
- a sample dictionary for multi_choice is:
question = {"question_title": "Measurement Mode",
"question_text": "Please choose which measurement mode to use",
"default_answer": 2,
"optiontype": "multi_choice",
"valid_options": ["2-point", "3-point", "4-point"]}
- a sample dictionary for yes/no is:
question = {"question_title": "Connection check",
"question_text": "Connection check wasn't performed but is optional. Do you want to check the "
"connections?",
"default_answer": True,
"optiontype": "yes_no"}
- a sample dictionary for interval is:
question = {"question_title": "Excitation voltage",
"question_text": "Please enter an excitation voltage between 0 and 3 V. Maximum accuracy is 0.1 V.",
"default_answer": 1.0,
"optiontype": "free_choice",
"valid_options_lower_limit": 0.0,
"valid_options_upper_limit": 3.0,
"valid_options_steplength": 1e1}
Note: Steplength is the inverse steplength. If 0.05 is the allowed steplength, enter 20 as steplength here
- a sample dictionary to ask for free text:
question = {"question_title": "Working directory",
"question_text": "Please choose a working directory for the following session with this program",
"default_answer": "C:\Data\DiBaMePro",
"optiontype": "free_text"}
- a sample dictionary to ask for two indeces:
question = {"question_title": "Same-level-merge selection",
"question_text": "Please enter the two indeces, (you will get two input prompts) for the "
"two which are to be merged.",
"default_answer": "0",
"optiontype": "2_indeces"}
- a sample dictionary to ask for multiple indeces:
question = {"question_title": "Same-level-merge selection",
"question_text": "Please enter one or more indeces separated only by a comma",
"default_answer": "0,4,8,12",
"optiontype": "multi_indeces"}
"""
result = question.copy()
# first we get the dictionarie's values into local variables to ease the handling
question_title = question["question_title"] # type: str
question_title = "-------------" + question_title + "-------------"
question_text = question["question_text"] # type: str
default_answer = question["default_answer"] # can be int or True or str
optiontype = question["optiontype"] # type: str
valid_options = None
valid_options_lower_limit = None
valid_options_upper_limit = None
valid_options_steplength = None
print(question_title)
print(question_text)
# valid_options and option specifics only exist if it's not a yes/no question
if optiontype != "yes_no":
# in case of multi_choice, key "valid_options" exist and we need to match it
if optiontype == "multi_choice":
valid_options = question["valid_options"] # type: []
elif optiontype == "free_choice":
valid_options_lower_limit = question["valid_options_lower_limit"]
valid_options_upper_limit = question["valid_options_upper_limit"]
valid_options_steplength = question["valid_options_steplength"]
# Now let's make different parsing for the (currently) three question types:
# Yes/No questions are mapped to Bool True or False
if optiontype == "yes_no":
# here we can easily centrally exchange this to some logic to talk to a potential GUI
answer_understood = False
user_chosen_answer = None # type: bool
default_literal_answer = ""
if default_answer:
default_literal_answer = "yes"
elif not default_answer:
default_literal_answer = "no"
while not answer_understood:
user_entered_response = input(
"Default answer is: " + default_literal_answer + ". What do you want? Type y, n or confirm default: ")
user_chosen_answer, answer_understood = recognize_user_input_yes_or_no(user_entered_response,
default_answer)
result['answer'] = user_chosen_answer
# Code Block for handling multi-option question type
elif optiontype == "multi_choice":
# we will later need a list of valid responses from the user
valid_answers = []
# enumerate yields the index AND the value, so we can use both then
for index, item in enumerate(valid_options):
print(str(index) + ": " + item)
valid_answers.append(index)
answer_understood = False
user_chosen_answer = None # type: str
while not answer_understood:
print("The default is option #" + str(default_answer))
user_entered_response = input("Confirm with enter or put in your own choice and confirm: ")
user_chosen_answer, answer_understood = recognize_user_input(user_entered_response, valid_answers,
default_answer)
result['answer'] = int(user_chosen_answer)
elif optiontype == "free_choice":
answer_understood = False
user_chosen_answer = None
while not answer_understood:
print("Default answer is: " + str(default_answer))
user_entered_response = input("Please enter your desired value with '.' as decimal separator: ")
try:
user_entered_response = float(user_entered_response)
user_chosen_answer, answer_understood = parse_user_input_lower_upper_limit_with_interval(
user_entered_response, valid_options_lower_limit, valid_options_upper_limit,
valid_options_steplength)
except ValueError:
try:
if user_entered_response == "":
user_chosen_answer = default_answer
answer_understood = True
except ValueError:
answer_understood = False
result['answer'] = user_chosen_answer
elif optiontype == "free_text":
answer_understood = False
user_chosen_answer = None
while not answer_understood:
print("Default answer is: " + str(default_answer))
user_chosen_answer = input("Type your own now or confirm default with enter: ")
if user_chosen_answer == "":
user_chosen_answer = default_answer
answer_understood = True
result['answer'] = user_chosen_answer
elif optiontype == "2_indeces":
answer1_understood = False
answer2_understood = False
index1 = None
index2 = None
print("Default answer is: " + str(default_answer))
while not answer1_understood:
user_chosen_answer = input("Index 1: ")
try:
index1 = int(user_chosen_answer)
answer1_understood = True
except ValueError:
print("Please make sure to only enter a number!")
while not answer2_understood:
user_chosen_answer = input("Index 2: ")
try:
index2 = int(user_chosen_answer)
answer2_understood = True
except ValueError:
print("Please make sure to only enter a number!")
result["answer"] = [index1, index2]
elif optiontype == "multi_indeces":
answer_understood = False
user_chosen_answer = default_answer
indeces = None
while not answer_understood:
indeces = []
print("Default answer is: " + str(default_answer))
user_chosen_answer = input("Type your own now or confirm default with enter: ") # type: str
user_chosen_answer_list = user_chosen_answer.split(",")
error_happened = False
for item in user_chosen_answer_list:
try:
indeces.append(int(item))
except ValueError:
error_happened = True
print("Please make sure to only enter integer numbers separated by commas.")
if not error_happened:
answer_understood = True
result["answer"] = indeces
else:
print("You are trying to use a question type that is not supported or have a typoo in your code.+")
return result # type: dict
def confirm_warning(warning_text: str,custom:bool=True):
# GUI code to make a window that just has an OK button
if custom:
print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
print(warning_text)
print("")
print("Confirm with Enter!")
input("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
def post_status(new_status: str):
# GUI code to show log messages that don't need confirmation!
print(str(new_status))