-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathinputchooser.py
More file actions
111 lines (98 loc) · 3.95 KB
/
inputchooser.py
File metadata and controls
111 lines (98 loc) · 3.95 KB
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
import sys
# Taken from https://bitbucket.org/maddagaska/maddautils/src/411cf3811f995de0ee6de000aed069f409afc719/__init__.py?at=master # noqa
# Offered under BSD license.
#phillip.kent@interoute.com: Added option 'include_none' (2014-11-07)
#By default, include_none=False, so a selection is required
#For an optional selection, use include_none = True
def choose_item_from_list(items,
source=sys.stdin,
dest=sys.stdout,
default='-',
include_none = False,
prompt='Please select an item:'):
# No item can be selected if there are no items
if len(items) == 0:
return -1
# Use the default if we can- otherwise, make sure it's safe
if default != '-' and (default in items or default == 'None'):
if default == 'None':
default = -1
else:
default = items.index(default)
elif isinstance(default, int) and default in range(-1, len(items)):
# The default is already an index in the list, or it is none
# We don't need to do anything
pass
else:
# If the default has been incorrectly set, or if it has not been set,
# set it to nothing
default = None
# Ask the user to make a selection
selection = None
while selection is None:
selection = default
# Output the header
dest.write('%s\n' % prompt)
if include_none:
dest.write('0. None')
if default == -1:
# This is the default option
dest.write(' (default)\n')
else:
dest.write('\n')
# Output all of the items
for item in range(0, len(items)):
dest.write('%s. %s' % (item + 1, items[item],))
if int(item) == default:
# This is the default option
dest.write(' (default)\n')
else:
dest.write('\n')
dest.flush()
response = source.readline().rstrip()
if len(response) == 0:
# No response given, prompt again
# Otherwise it causes a problem with 'startswith' later
continue
try:
# If the input is an integer we treat it as a selection
# We don't try to match it to the text of a list item
response = int(response)
response -= 1
if response in range(-1, len(items)):
selection = response
else:
# Give helpful feedback
response += 1
dest.write('\n')
dest.write('I do not have an item number %s.\n' % response)
dest.write('\n')
dest.flush()
except ValueError:
# It wasn't an integer. Did it match any items in the list?
candidates = []
for item in ['None'] + items:
if item.startswith(response):
candidates.append(item)
# If the selection is unambiguous, accept it as the choice
if len(candidates) == 1:
if 'None'.startswith(response):
selection = -1
else:
for item in items:
if item.startswith(response):
selection = items.index(item)
elif len(candidates) > 1:
# The response was ambiguous, it could match multiple items
dest.write('\n')
dest.write('%s matches multiple items. ' % response)
dest.write('Please be more specific.\n')
dest.write('\n')
dest.flush()
else:
# The named item wasn't in our list, give useful feedback
dest.write('\n')
dest.write('%s is not an option.\n' % response)
dest.write('\n')
dest.flush()
return selection