Skip to content
Closed
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
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ LMS: Support adding students to a cohort via the instructor dashboard. TNL-163

LMS: Show cohorts on the new instructor dashboard. TNL-161

LMS: Extended hints feature

LMS: Mobile API available for courses that opt in using the Course Advanced
Setting "Mobile Course Available" (only used in limited closed beta).

Expand Down
44 changes: 44 additions & 0 deletions common/lib/capa/capa/capa_problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ def __init__(self, problem_text, id, capa_system, state=None, seed=None):
# parse problem XML file into an element tree
self.tree = etree.XML(problem_text)

self.make_xml_compatible(self.tree)

# handle any <include file="foo"> tags
self._process_includes()

Expand Down Expand Up @@ -191,6 +193,48 @@ def __init__(self, problem_text, id, capa_system, state=None, seed=None):

self.extracted_tree = self._extract_html(self.tree)

def make_xml_compatible(self, tree):
"""
Adjust tree xml in-place for compatibility, such as
supporting an old xml format by translating it to a new format.
"""
# <additional_answer> compatibility translation:
# old: <additional_answer>ANSWER</additional_answer>
# convert to
# new: <additional_answer answer="ANSWER">OPTIONAL-HINT</addional_answer>
# the new format is the form used at runtime and by this conversion we support
# the old format
additionals = tree.xpath('//stringresponse/additional_answer')
for additional in additionals:
answer = additional.get('answer')
text = additional.text
if not answer and text: # trigger of old->new conversion
additional.set('answer', text)
additional.text = ''

# <optioninput> compatibility translation:
# optioninput uses option= like this:
# <optioninput options="('yellow','blue','green')" correct="blue" />
# With extended hints there is a new <option> tag, like this
# <option correct="True">blue <optionhint>sky color</optionhint> </option>
# This translation takes in the new format and synthesizes the old option= attribute
# so all downstream logic works unchanged with the new <option> tag format.
for optioninput in tree.xpath('//optioninput'):
correct_option = None
child_options = []
for option_element in optioninput.findall('./option'):
option_name = option_element.text.strip()
if option_element.get('correct').upper() == 'TRUE':
correct_option = option_name
child_options.append("'" + option_name + "'")

if len(child_options) > 0:
options_string = '(' + ','.join(child_options) + ')'
optioninput.attrib.update({'options': options_string})
if correct_option:
optioninput.attrib.update({'correct': correct_option})


def do_reset(self):
"""
Reset internal state to unfinished, with no answers
Expand Down
18 changes: 10 additions & 8 deletions common/lib/capa/capa/inputtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -483,15 +483,17 @@ def extract_choices(element, i18n):
_ = i18n.ugettext

for choice in element:
if choice.tag != 'choice':
msg = u"[capa.inputtypes.extract_choices] {error_message}".format(
# Translators: '<choice>' is a tag name and should not be translated.
error_message=_("Expected a <choice> tag; got {given_tag} instead").format(
given_tag=choice.tag
if choice.tag == 'choice':
choices.append((choice.get("name"), stringify_children(choice)))
else:
if choice.tag != 'compoundhint':
msg = u'[capa.inputtypes.extract_choices] {error_message}'.format(
# Translators: '<choice>' and '<compoundhint>' are tag names and should not be translated.
error_message=_('Expected a <choice> or <compoundhint> tag; got {given_tag} instead').format(
given_tag=choice.tag
)
)
)
raise Exception(msg)
choices.append((choice.get("name"), stringify_children(choice)))
raise Exception(msg)
return choices

def get_user_visible_answer(self, internal_answer):
Expand Down
Loading