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(
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):
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 = [
- ('<input type="radio" name="answer" value="{0}"/>{0}<br/>'
- ).format(answer)
+ ('<input type="{0}" name="answer" value="{1}"/>{1}<br/>'
+ ).format(itype, answer)
for answer in question.answer]
if question.accept_all:
choices.extend([
- '<input type="radio" name="answer" value="answer-other"/>',
+ ('<input type="{}" name="answer" value="answer-other"/>'
+ ).format(itype),
'<input type="text" size="60" name="answer-other"/>'])
answer_element = '\n'.join(choices)
elif question.multiline:
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