Source code for hal.streams.user

# -*- coding: utf-8 -*-

"""Deal with user on standard output/input """

from hal.strings.utils import get_max_similar


[docs]class UserInput: """Chat with user and ask questions""" YES_INPUT = ["yes", "ok", "fine"] NO_INPUT = ["no", "not ok", "none"] THRESHOLD_INPUT = 0.9 def __init__(self, yes_choices=None, no_choices=None, threshold=None, interactive=True): """ :param threshold: Match user answer with the one provided with at least this rate :param yes_choices: List of answer considered a "yes" :param no_choices: List of answer considered a "no" :param interactive: True iff program should deal with user not answering properly """ if not yes_choices: yes_choices = self.YES_INPUT if not no_choices: no_choices = self.NO_INPUT if not threshold: threshold = self.THRESHOLD_INPUT self.threshold = threshold self.yes_input = yes_choices self.no_input = no_choices self.last_question = None self.interactive = bool(interactive)
[docs] def is_yes(self, answer): """ :param answer: User: answer :return: True iff considered a "yes" answer """ yes_sim, _ = get_max_similar(answer, self.yes_input) no_sim, _ = get_max_similar(answer, self.no_input) return yes_sim > no_sim and yes_sim > self.threshold
[docs] def is_no(self, answer): """Checks if considered a "yes" answer :param answer: User answer :return: True iff considered a "yes" answer """ yes_sim, _ = get_max_similar(answer, self.yes_input) no_sim, _ = get_max_similar(answer, self.no_input) return no_sim > yes_sim and no_sim > self.threshold
[docs] def show_help(self): """Prints to stdout help on how to answer properly""" print("Sorry, not well understood.") print("- use", str(self.yes_input), "to answer 'YES'") print("- use", str(self.no_input), "to answer 'NO'")
[docs] def re_ask(self, with_help=True): """Re-asks user the last question :param with_help: True iff you want to show help on how to answer questions :return: user answer """ if with_help: self.show_help() return self.get_answer(self.last_question)
[docs] def get_answer(self, question): """Asks user a question, then gets user answer :param question: Question: to ask user :return: User answer """ self.last_question = str(question).strip() user_answer = input(self.last_question) return user_answer.strip()
[docs] def get_yes_no(self, question): """Checks if question is yes (True) or no (False) :param question: Question to ask user :return: User answer """ user_answer = self.get_answer(question).lower() if user_answer in self.yes_input: return True if user_answer in self.no_input: return False is_yes = self.is_yes(user_answer) # check if similar to yes/no choices is_no = self.is_no(user_answer) if is_yes and not is_no: return True if is_no and not is_yes: return False if self.interactive: self.show_help() return self.get_yes_no(self.last_question) return False
[docs] def get_number(self, question, min_i=float("-inf"), max_i=float("inf"), just_these=None): """Parses answer and gets number :param question: Question: to ask user :param min_i: min acceptable number :param max_i: max acceptable number :param just_these: Accept only these numbers :return: User answer """ try: user_answer = self.get_answer(question) user_answer = float(user_answer) if min_i < user_answer < max_i: if just_these: if user_answer in just_these: return user_answer exc = "Number cannot be accepted. Just these: " exc += str(just_these) raise Exception(exc) return user_answer exc = "Number is not within limits. " exc += "Min is " + str(min_i) + ". Max is " + str(max_i) + "" raise Exception(exc) except Exception as exc: print(str(exc)) return self.get_number( self.last_question, min_i=min_i, max_i=max_i, just_these=just_these )
[docs] def get_list(self, question, splitter=",", at_least=0, at_most=float("inf")): """Parses answer and gets list :param question: Question: to ask user :param splitter: Split list elements with this char :param at_least: List must have at least this amount of elements :param at_most: List must have at most this amount of elements :return: User answer """ try: user_answer = self.get_answer(question) # ask question user_answer = user_answer.split(splitter) # split items user_answer = [str(item).strip() for item in user_answer] # strip if at_least < len(user_answer) < at_most: return user_answer exc = "List is not correct. " exc += "There must be at least " + str(at_least) + " items, " exc += "and at most " + str(at_most) + ". " exc += "Use '" + str(splitter) + "' to separate items" raise Exception(exc) except Exception as exc: print(str(exc)) return self.get_list( self.last_question, at_least=at_least, at_most=at_most )