def __init__(self, question, value, validator=None, multiple=False, printable_name=None): """ Basic Question class. Supports simple question and answer or question and multiple answers (note: list/hash validators have caveats). Also support for one or more Validator classes to ensure the answer given meets the question criteria. """ self.question = question self.value = value self.multiple = multiple if printable_name: self.printable_name = printable_name else: self.printable_name = value if validator is None: self.validator = Validator() else: self.validator = validator self._questions = []
def _ask(self, answers: Dict) -> Union[Dict, None]: """ Really ask the question. We may need to populate multiple validators with answers here. Then ask the question and insert the default value if appropriate. Finally call the validate function to check all validators for this question and returning the answer. """ if isinstance(self.validator, list): for v in self.validator: v.answers = answers else: self.validator.answers = answers while(True): q = self.question % answers if not self.choices(): logger.warning('No choices were supplied for "%s"' % q) return None if self.value in answers: default = Validator.stringify(answers[self.value]) answer = self._get_input("%s [%s]: " % (q, default)) if answer == '': answer = answers[self.value] else: answer = self._get_input("%s: " % q) # if we are in multiple mode and the answer is just the empty # string (enter/return pressed) then we will just answer None # to indicate we are done if answer == '.' and self.multiple: return None if self.validate(answer): return self.answer() else: if isinstance(self.validator, list): for v in self.validator: if v.error() != '': print(v.error()) else: print(self.validator.error())
def _ask(self, answers): """ Really ask the question. We may need to populate multiple validators with answers here. Then ask the question and insert the default value if appropriate. Finally call the validate function to check all validators for this question and returning the answer. """ if isinstance(self.validator, list): for v in self.validator: v.answers = answers else: self.validator.answers = answers while(True): q = self.question % answers if not self.choices(): return None if self.value in answers: default = Validator.stringify(answers[self.value]) answer = raw_input("%s [%s]: " % (q, default)) if answer == '': answer = answers[self.value] else: answer = raw_input("%s: " % q) # if we are in multiple mode and the answer is just the empty # string (enter/return pressed) then we will just answer None # to indicate we are done if answer == '.' and self.multiple: return None if self.validate(answer): return self.answer() else: if isinstance(self.validator, list): for v in self.validator: if v.error() != '': print v.error() else: print self.validator.error()
def test_stringify(self): assert Validator.stringify(5) == '5' assert Validator.stringify('5') == '5'
def test_error(self): v = Validator() v.validate('') assert v.error() == 'ERROR: Can not be empty. Please provide a value.'
def test_blank(self): v = Validator(blank=True) assert v.validate('') is True assert v.choice() == ''
def test_validate(self): v = Validator() assert v.validate('') is False assert v.error_message is not None
class Question(object): _answers: Dict _questions: List def __init__(self, question: str, value: str, validator: 'Validator' = None, multiple=False, printable_name=None) -> None: """ Basic Question class. Supports simple question and answer or question and multiple answers (note: list/hash validators have caveats). Also support for one or more Validator classes to ensure the answer given meets the question criteria. """ self.question = question self.value = value self.multiple = multiple if printable_name: self.printable_name = printable_name else: self.printable_name = value if validator is None: self.validator = Validator() else: self.validator = validator self._questions = [] def __eq__(self, other: 'Question') -> bool: # type: ignore if self.question == other.question and self.value == other.value: return True else: return False def __repr__(self) -> str: return self.value def _get_input(self, text) -> str: return input(text) def _ask(self, answers: Dict) -> Union[Dict, None]: """ Really ask the question. We may need to populate multiple validators with answers here. Then ask the question and insert the default value if appropriate. Finally call the validate function to check all validators for this question and returning the answer. """ if isinstance(self.validator, list): for v in self.validator: v.answers = answers else: self.validator.answers = answers while(True): q = self.question % answers if not self.choices(): logger.warning('No choices were supplied for "%s"' % q) return None if self.value in answers: default = Validator.stringify(answers[self.value]) answer = self._get_input("%s [%s]: " % (q, default)) if answer == '': answer = answers[self.value] else: answer = self._get_input("%s: " % q) # if we are in multiple mode and the answer is just the empty # string (enter/return pressed) then we will just answer None # to indicate we are done if answer == '.' and self.multiple: return None if self.validate(answer): return self.answer() else: if isinstance(self.validator, list): for v in self.validator: if v.error() != '': print(v.error()) else: print(self.validator.error()) def ask(self, answers: Dict = None) -> Dict: """ Ask the question, then ask any sub-questions. This returns a dict with the {value: answer} pairs for the current question plus all descendant questions. """ if answers is None: answers = {} _answers: Dict = {} if self.multiple: print((bold('Multiple answers are supported for this question. ' + 'Please enter a "." character to finish.'))) _answers[self.value] = [] answer = self._ask(answers) while answer is not None: _answers[self.value].append(answer) answer = self._ask(answers) else: _answers[self.value] = self._ask(answers) if isinstance(self.validator, list): for v in self.validator: _answers = dict(_answers, **v.hints()) else: _answers = dict(_answers, **self.validator.hints()) for q in self._questions: answers = dict(answers, **_answers) _answers = dict(_answers, **q.ask(answers)) return _answers def validate(self, answer: str) -> bool: """ Validate the answer with our Validator(s) This will support one or more validator classes being applied to this question. If there are multiple, all validators must return True for the answer to be valid. """ if answer is None: return False else: if isinstance(self.validator, list): for v in self.validator: if not v.validate(answer): return False return True else: return self.validator.validate(answer) def answer(self) -> Dict: """ Return the answer for the question from the validator. This will ultimately only be called on the first validator if multiple validators have been added. """ if isinstance(self.validator, list): return self.validator[0].choice() return self.validator.choice() def choices(self) -> bool: """ Print the choices for this question. This may be a empty string and in the case of a list of validators we will only show the first validator's choices. """ if isinstance(self.validator, list): return self.validator[0].print_choices() return self.validator.print_choices() def add(self, question: 'Question') -> None: if isinstance(question, Question): self._questions.append(question) else: # TODO this should raise a less generic exception raise Exception def remove(self, question: 'Question') -> None: if isinstance(question, Question): self._questions.remove(question) else: raise Exception
class Question(object): def __init__(self, question, value, validator=None, multiple=False, printable_name=None): """ Basic Question class. Supports simple question and answer or question and multiple answers (note: list/hash validators have caveats). Also support for one or more Validator classes to ensure the answer given meets the question criteria. """ self.question = question self.value = value self.multiple = multiple if printable_name: self.printable_name = printable_name else: self.printable_name = value if validator is None: self.validator = Validator() else: self.validator = validator self._questions = [] def __eq__(self, other): if self.question == other.question and self.value == other.value: return True else: return False def __repr__(self): return self.value def _ask(self, answers): """ Really ask the question. We may need to populate multiple validators with answers here. Then ask the question and insert the default value if appropriate. Finally call the validate function to check all validators for this question and returning the answer. """ if isinstance(self.validator, list): for v in self.validator: v.answers = answers else: self.validator.answers = answers while(True): q = self.question % answers if not self.choices(): return None if self.value in answers: default = Validator.stringify(answers[self.value]) answer = raw_input("%s [%s]: " % (q, default)) if answer == '': answer = answers[self.value] else: answer = raw_input("%s: " % q) # if we are in multiple mode and the answer is just the empty # string (enter/return pressed) then we will just answer None # to indicate we are done if answer == '.' and self.multiple: return None if self.validate(answer): return self.answer() else: if isinstance(self.validator, list): for v in self.validator: if v.error() != '': print v.error() else: print self.validator.error() def ask(self, answers=None): """ Ask the question, then ask any sub-questions. This returns a dict with the {value: answer} pairs for the current question plus all decendent questions. """ if answers is None: answers = {} _answers = {} if self.multiple: print(bold('Multiple answers are supported for this question. ' + 'Please enter a "." character to finish.')) _answers[self.value] = [] answer = self._ask(answers) while answer is not None: _answers[self.value].append(answer) answer = self._ask(answers) else: _answers[self.value] = self._ask(answers) if isinstance(self.validator, list): for v in self.validator: _answers = dict(_answers, **v.hints()) else: _answers = dict(_answers, **self.validator.hints()) for q in self._questions: answers = dict(answers, **_answers) _answers = dict(_answers, **q.ask(answers)) return _answers def validate(self, answer): """ Validate the answer with our Validator(s) This will support one or more validator classes being applied to this question. If there are multiple, all validators must return True for the answer to be valid. """ if answer is None: return False else: if isinstance(self.validator, list): for v in self.validator: if not v.validate(answer): return False return True else: return self.validator.validate(answer) def answer(self): """ Return the answer for the question from the validator. This will ultimately only be called on the first validator if multiple validators have been added. Since we ultimately we and all the validators this should not cause any issues. """ if isinstance(self.validator, list): return self.validator[0].choice() return self.validator.choice() def choices(self): """ Print the choices for this question. This may be a empty string and in the case of a list of validators we will only show the first validator's choices. """ if isinstance(self.validator, list): return self.validator[0].print_choices() return self.validator.print_choices() def add(self, question): if isinstance(question, Question): self._questions.append(question) else: raise Exception def remove(self, question): if isinstance(question, Question): self._questions.remove(question) else: raise Exception