From: W. Trevor King Date: Fri, 22 Mar 2013 21:29:44 +0000 (-0400) Subject: question: Add the ChoiceQuestion.multiple_answer attribute X-Git-Tag: v0.4~2 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=82d6f1687df19164e5775bfb7177059d885d8f16;p=quizzer.git question: Add the ChoiceQuestion.multiple_answer attribute This adds support for multiple choice questions where you are allowed to select one or more of the possible choices. In web forms, this is usually done via checkboxes. --- diff --git a/quizzer/question.py b/quizzer/question.py index 95d9022..3933795 100644 --- a/quizzer/question.py +++ b/quizzer/question.py @@ -115,16 +115,20 @@ class NormalizedStringQuestion (Question): class ChoiceQuestion (Question): _state_attributes = Question._state_attributes + [ 'display_choices', + 'multiple_answers', ] def __setstate__(self, state): - for key in ['display_choices']: + for key in ['display_choices', 'multiple_answers']: if key not in state: state[key] = False super(ChoiceQuestion, self).__setstate__(state) def _check(self, answer): - correct = answer in self.answer + if self.multiple_answers and not isinstance(answer, str): + correct = min([a in self.answer for a in answer]) + else: + correct = answer in self.answer details = None if not correct: details = 'answer ({}) is not in list of expected values'.format( diff --git a/quizzer/ui/cli.py b/quizzer/ui/cli.py index 14ae67f..ba26b32 100644 --- a/quizzer/ui/cli.py +++ b/quizzer/ui/cli.py @@ -90,19 +90,37 @@ class QuestionCommandLine (_cmd.Cmd): self.question.display_choices): for i,choice in enumerate(self.question.answer): yield '{}) {}'.format(i, choice) + yield 'Answer with the index of your choice' if self.question.accept_all: - yield 'or fill in something else' + conj = 'or' + if self.question.multiple_answers: + conj = 'and/or' + yield '{} fill in an alternative answer'.format(conj) + if self.question.multiple_answers: + self._separator = ',' + yield ("Separate multiple answers with the '{}' character" + ).format(self._separator) return [] def _process_answer(self, answer): "Back out any mappings suggested by _extra_ps1_lines()" if (isinstance(self.question, _question.ChoiceQuestion) and self.question.display_choices): - try: - a = int(answer) - return self.question.answer[a] - except (ValueError, IndexError): - pass + if self.question.multiple_answers: + answers = [] + for a in answer.split(self._separator): + try: + i = int(a) + answers.append(self.question.answer[i]) + except (ValueError, IndexError): + answers.append(a) + return answers + else: + try: + i = int(answer) + return self.question.answer[i] + except (ValueError, IndexError): + pass return answer def default(self, line): diff --git a/quizzer/ui/wsgi.py b/quizzer/ui/wsgi.py index 91f4321..4c7af2d 100644 --- a/quizzer/ui/wsgi.py +++ b/quizzer/ui/wsgi.py @@ -244,13 +244,18 @@ class QuestionApp (WSGI_DataObject): 307, 'Temporary Redirect', headers=[('Location', '/results/')]) if (isinstance(question, _question.ChoiceQuestion) and question.display_choices): + if question.multiple_answers: + itype = 'checkbox' + else: + itype = 'radio' choices = [ - ('{0}
' - ).format(answer) + ('{1}
' + ).format(itype, answer) for answer in question.answer] if question.accept_all: choices.extend([ - '', + ('' + ).format(itype), '']) answer_element = '\n'.join(choices) elif question.multiline: @@ -300,9 +305,15 @@ class QuestionApp (WSGI_DataObject): raise HandlerError(404, 'Not Found') from e if (isinstance(question, _question.ChoiceQuestion) and question.display_choices and - question.accept_all and - raw_answer == 'answer-other'): - answer = print_answer = data.get('answer-other', None) + question.accept_all): + if raw_answer == 'answer-other': + answer = print_answer = data.get('answer-other', None) + elif 'answer-other' in raw_answer: + i = raw_answer.index('answer-other') + raw_answer[i] = data.get('answer-other', None) + answer = print_answer = raw_answer + else: + answer = print_answer = raw_answer elif question.multiline: answer = raw_answer.splitlines() print_answer = raw_answer