Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,8 @@ description.
* `One question at a time` — Only show one question at a time.
* `Can't go back` — Don't allow going back to the previous question when in
`One question at a time` mode.

* `Number of attempts` — Set number of quiz attempts allowed. Setting this
overrides the default of 1 attempt. Set to 0 for unlimited attempts.



Expand Down
3 changes: 2 additions & 1 deletion text2qti/qti.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ def __init__(self, quiz: Quiz):
shuffle_answers=quiz.shuffle_answers_xml,
show_correct_answers=quiz.show_correct_answers_xml,
one_question_at_a_time=quiz.one_question_at_a_time_xml,
cant_go_back=quiz.cant_go_back_xml)
cant_go_back=quiz.cant_go_back_xml,
allowed_attempts=quiz.allowed_attempts_xml)
self.assessment = assessment(quiz=quiz,
assessment_identifier=self.assessment_identifier,
title_xml=quiz.title_xml)
Expand Down
24 changes: 21 additions & 3 deletions text2qti/quiz.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
'quiz_show_correct_answers': r'[Ss]how correct answers:',
'quiz_one_question_at_a_time': r'[Oo]ne question at a time:',
'quiz_cant_go_back': r'''[Cc]an't go back:''',
'quiz_allowed_attempts': r'[Nn]umber of attempts:',
}
# comments are currently handled separately from content
comment_patterns = {
Expand All @@ -74,7 +75,8 @@
single_line = set(['question_points', 'group_pick', 'group_points_per_question',
'numerical', 'shortans_correct_choice',
'quiz_shuffle_answers', 'quiz_show_correct_answers',
'quiz_one_question_at_a_time', 'quiz_cant_go_back'])
'quiz_one_question_at_a_time', 'quiz_cant_go_back',
'quiz_allowed_attempts'])
multi_line = set([x for x in start_patterns
if x not in no_content and x not in single_line])
# whether parser needs to check for multi-paragraph content
Expand Down Expand Up @@ -557,6 +559,8 @@ def __init__(self, string: str, *, config: Config,
self.one_question_at_a_time_xml = 'false'
self.cant_go_back_raw = None
self.cant_go_back_xml = 'false'
self.allowed_attempts_raw = None
self.allowed_attempts_xml = 1
self.questions_and_delims: List[Union[Question, GroupStart, GroupEnd, TextRegion]] = []
self._current_group: Optional[Group] = None
# The set for detecting duplicate questions uses the XML version of
Expand Down Expand Up @@ -737,7 +741,8 @@ def _run_code(self, executable: str, code: str) -> str:

def append_quiz_title(self, text: str):
if any(x is not None for x in (self.shuffle_answers_raw, self.show_correct_answers_raw,
self.one_question_at_a_time_raw, self.cant_go_back_raw)):
self.one_question_at_a_time_raw, self.cant_go_back_raw,
self.allowed_attempts_raw)):
raise Text2qtiError('Must give quiz title before quiz options')
if self._next_question_attr:
raise Text2qtiError('Expected question; question title and/or points were set but not used')
Expand All @@ -752,7 +757,8 @@ def append_quiz_title(self, text: str):

def append_quiz_description(self, text: str):
if any(x is not None for x in (self.shuffle_answers_raw, self.show_correct_answers_raw,
self.one_question_at_a_time_raw, self.cant_go_back_raw)):
self.one_question_at_a_time_raw, self.cant_go_back_raw,
self.allowed_attempts_raw)):
raise Text2qtiError('Must give quiz description before quiz options')
if self._next_question_attr:
raise Text2qtiError('Expected question; question title and/or points were set but not used')
Expand Down Expand Up @@ -813,6 +819,18 @@ def append_quiz_cant_go_back(self, text: str):
self.cant_go_back_raw = text
self.cant_go_back_xml = text.lower()

def append_quiz_allowed_attempts(self, text: int):
if self._next_question_attr:
raise Text2qtiError('Expected question; question title and/or points were set but not used')
if self.questions_and_delims:
raise Text2qtiError('Must give quiz options before questions')
if self.allowed_attempts_raw is not None:
raise Text2qtiError('Quiz option "Number of attempts" has already been set')
if int(text) < 0:
raise Text2qtiError('Expected option value cannot be less than 0')
self.allowed_attempts_raw = text
self.allowed_attempts_xml = text

def append_text_title(self, text: str):
if self._next_question_attr:
raise Text2qtiError('Expected question; question title and/or points were set but not used')
Expand Down
8 changes: 5 additions & 3 deletions text2qti/xml_assessment_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<show_correct_answers>{show_correct_answers}</show_correct_answers>
<anonymous_submissions>false</anonymous_submissions>
<could_be_locked>false</could_be_locked>
<allowed_attempts>1</allowed_attempts>
<allowed_attempts>{allowed_attempts}</allowed_attempts>
<one_question_at_a_time>{one_question_at_a_time}</one_question_at_a_time>
<cant_go_back>{cant_go_back}</cant_go_back>
<available>false</available>
Expand Down Expand Up @@ -93,7 +93,8 @@ def assessment_meta(*,
shuffle_answers: str,
show_correct_answers: str,
one_question_at_a_time: str,
cant_go_back: str) -> str:
cant_go_back: str,
allowed_attempts: str) -> str:
'''
Generate `assessment_meta.xml`.
'''
Expand All @@ -107,4 +108,5 @@ def assessment_meta(*,
show_correct_answers=show_correct_answers,
hide_results='always' if show_correct_answers == 'false' else '',
one_question_at_a_time=one_question_at_a_time,
cant_go_back=cant_go_back)
cant_go_back=cant_go_back,
allowed_attempts=allowed_attempts)