Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1"""LICENSE 

2Copyright 2019 Hermann Krumrey <hermann@krumreyh.com> 

3 

4This file is part of puffotter. 

5 

6puffotter is free software: you can redistribute it and/or modify 

7it under the terms of the GNU General Public License as published by 

8the Free Software Foundation, either version 3 of the License, or 

9(at your option) any later version. 

10 

11puffotter is distributed in the hope that it will be useful, 

12but WITHOUT ANY WARRANTY; without even the implied warranty of 

13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

14GNU General Public License for more details. 

15 

16You should have received a copy of the GNU General Public License 

17along with puffotter. If not, see <http://www.gnu.org/licenses/>. 

18LICENSE""" 

19 

20from typing import List, Any, Callable, Optional, Set 

21from colorama import Fore, Style 

22 

23 

24def yn_prompt( 

25 message: str, 

26 make_sure: bool = True, 

27 case_sensitive: bool = False 

28) -> bool: 

29 """ 

30 Creates a yes/no prompt 

31 :param message: The message to display 

32 :param make_sure: Continuously prompts if the response is neither 

33 'y' or 'n' until it is. 

34 If false, every input besides 'y' will result in the 

35 return value being False 

36 :param case_sensitive: Whether or not the prompt should be case-sensitive 

37 :return: True if the user specified 'y', else False 

38 """ 

39 resp = input("{} {}(y|n){}: ".format( 

40 message, Fore.LIGHTYELLOW_EX, Style.RESET_ALL 

41 )).strip() 

42 if not case_sensitive: 

43 resp = resp.lower() 

44 

45 if resp == "y": 

46 return True 

47 elif resp == "n" or not make_sure: 

48 return False 

49 else: 

50 return yn_prompt(message, make_sure, case_sensitive) 

51 

52 

53def selection_prompt(objects: List[object]) -> List[object]: 

54 """ 

55 Prompts the user for a selection from a list of objects 

56 :param objects: The objects to show 

57 :return: The selection of objects 

58 """ 

59 fill = len(str(len(objects))) 

60 for i, obj in enumerate(objects): 

61 print("[{}] {}".format(str(i + 1).zfill(fill), str(obj))) 

62 

63 while True: 

64 

65 selection = input("Selection: ").split(",") 

66 valid = True 

67 selected_objects = [] 

68 

69 for item in selection: 

70 

71 try: 

72 start_index = int(item) 

73 end_index = start_index 

74 except ValueError: 

75 try: 

76 start, end = item.split("-", 1) 

77 start_index = int(start) 

78 end_index = int(end) 

79 except (IndexError, ValueError): 

80 valid = False 

81 break 

82 

83 for i in range(start_index, end_index + 1): 

84 try: 

85 selected_objects.append(objects[i - 1]) 

86 except IndexError: 

87 valid = False 

88 break 

89 

90 if not valid: 

91 print("Invalid selection") 

92 else: 

93 return selected_objects 

94 

95 

96def prompt_comma_list( 

97 message: str, 

98 primitive_type: Callable[[str], Any] = str, 

99 min_count: int = 0, 

100 no_empty: bool = True, 

101 default: Optional[List[Any]] = None 

102) -> List[Any]: 

103 """ 

104 Prompts the user for a comma-separated list 

105 :param message: The message to display 

106 :param primitive_type: The primitive type of the elements in the list 

107 :param min_count: The minimum amount of elements to be provided by the user 

108 :param no_empty: Removes any empty strings 

109 :param default: A default value 

110 :return: The result of the prompt 

111 """ 

112 while True: 

113 try: 

114 prompt_message = message 

115 if default is not None: 

116 prompt_message = "{} {}{}{}".format( 

117 prompt_message, 

118 Fore.LIGHTGREEN_EX, 

119 default, 

120 Style.RESET_ALL 

121 ) 

122 prompt_message += ": " 

123 

124 response = input(prompt_message).strip() 

125 

126 if default is not None and response == "": 

127 return default 

128 

129 if default is not None and response == "[]": 

130 result = [] # type: List[str] 

131 else: 

132 result = list(map(lambda x: x.strip(), response.split(","))) 

133 

134 if "" in result and no_empty: 

135 result.remove("") 

136 result = list(map(lambda x: primitive_type(x), result)) 

137 

138 if len(result) < min_count: 

139 print("Not enough values") 

140 raise ValueError() 

141 else: 

142 return result 

143 

144 except (ValueError, TypeError): 

145 print("Invalid input") 

146 

147 

148def prompt( 

149 prompt_text: str = "", 

150 default: Optional[Any] = None, 

151 _type: Callable[[str], Any] = str, 

152 required: bool = True, 

153 choices: Optional[Set[str]] = None 

154) -> Optional[Any]: 

155 """ 

156 Generic prompt with configuration options 

157 :param prompt_text: The text to display before the prompt 

158 :param default: A default value to use if the user responds with '' 

159 :param _type: The type of the object prompted. Must take a single string 

160 as a parameter 

161 :param required: Whether or not a response is required 

162 :param choices: Valid choices for the prompt 

163 :return: The prompt result. May be None if required is False 

164 """ 

165 prompt_message = prompt_text 

166 

167 if choices is not None: 

168 prompt_message = "{} {}{}{}".format( 

169 prompt_message, 

170 Fore.LIGHTYELLOW_EX, 

171 choices, 

172 Style.RESET_ALL 

173 ) 

174 

175 if default is not None: 

176 prompt_message = "{} {}{}{}".format( 

177 prompt_message, 

178 Fore.LIGHTGREEN_EX, 

179 default, 

180 Style.RESET_ALL 

181 ) 

182 

183 prompt_message += ": " 

184 

185 response = input(prompt_message).strip() 

186 

187 while \ 

188 response == "" and default is None \ 

189 or ( 

190 choices is not None 

191 and response not in choices 

192 and default is None 

193 ): 

194 response = input(prompt_message).strip() 

195 

196 if response == "" and default is not None: 

197 return default 

198 elif response == "": 

199 if required: 

200 return prompt(prompt_text, default, _type, required) 

201 else: 

202 return None 

203 else: 

204 try: 

205 return _type(response) 

206 except (TypeError, ValueError): 

207 return prompt(prompt_text, default, _type, required)