Make import/export tests pass
This commit is contained in:
@@ -61,7 +61,7 @@ class CapaModule(XModule):
|
||||
max_attempts = StringyInt(help="Maximum number of attempts that a student is allowed", scope=Scope.settings)
|
||||
due = String(help="Date that this problem is due by", scope=Scope.settings)
|
||||
graceperiod = Timedelta(help="Amount of time after the due date that submissions will be accepted", scope=Scope.settings)
|
||||
show_answer = String(help="When to show the problem answer to the student", scope=Scope.settings, default="closed")
|
||||
showanswer = String(help="When to show the problem answer to the student", scope=Scope.settings, default="closed")
|
||||
force_save_button = Boolean(help="Whether to force the save button to appear on the page", scope=Scope.settings, default=False)
|
||||
rerandomize = Randomization(help="When to rerandomize the problem", default="always", scope=Scope.settings)
|
||||
data = String(help="XML data for the problem", scope=Scope.content)
|
||||
@@ -359,26 +359,26 @@ class CapaModule(XModule):
|
||||
def answer_available(self):
|
||||
''' Is the user allowed to see an answer?
|
||||
'''
|
||||
if self.show_answer == '':
|
||||
if self.showanswer == '':
|
||||
return False
|
||||
|
||||
if self.show_answer == "never":
|
||||
if self.showanswer == "never":
|
||||
return False
|
||||
|
||||
# Admins can see the answer, unless the problem explicitly prevents it
|
||||
if self.system.user_is_staff:
|
||||
return True
|
||||
|
||||
if self.show_answer == 'attempted':
|
||||
if self.showanswer == 'attempted':
|
||||
return self.attempts > 0
|
||||
|
||||
if self.show_answer == 'answered':
|
||||
if self.showanswer == 'answered':
|
||||
return self.done
|
||||
|
||||
if self.show_answer == 'closed':
|
||||
if self.showanswer == 'closed':
|
||||
return self.closed()
|
||||
|
||||
if self.show_answer == 'always':
|
||||
if self.showanswer == 'always':
|
||||
return True
|
||||
|
||||
return False
|
||||
@@ -409,7 +409,7 @@ class CapaModule(XModule):
|
||||
'''
|
||||
event_info = dict()
|
||||
event_info['problem_id'] = self.location.url()
|
||||
self.system.track_function('show_answer', event_info)
|
||||
self.system.track_function('showanswer', event_info)
|
||||
if not self.answer_available():
|
||||
raise NotFoundError('Answer is not available')
|
||||
else:
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
from xmodule.model import Scope
|
||||
|
||||
# A list of metadata that this module can inherit from its parent module
|
||||
INHERITABLE_METADATA = (
|
||||
'graded', 'start', 'due', 'graceperiod', 'showanswer', 'rerandomize',
|
||||
# TODO (ichuang): used for Fall 2012 xqa server access
|
||||
'xqa_key',
|
||||
# TODO: This is used by the XMLModuleStore to provide for locations for
|
||||
# static files, and will need to be removed when that code is removed
|
||||
'data_dir'
|
||||
)
|
||||
|
||||
def compute_inherited_metadata(descriptor):
|
||||
"""Given a descriptor, traverse all of its descendants and do metadata
|
||||
@@ -24,7 +33,7 @@ def inherit_metadata(descriptor, model_data):
|
||||
|
||||
# Set all inheritable metadata from kwargs that are
|
||||
# in self.inheritable_metadata and aren't already set in metadata
|
||||
for attr in descriptor.inheritable_metadata:
|
||||
for attr in INHERITABLE_METADATA:
|
||||
if attr not in descriptor._model_data and attr in model_data:
|
||||
descriptor._inherited_metadata.add(attr)
|
||||
descriptor._model_data[attr] = model_data[attr]
|
||||
|
||||
@@ -73,8 +73,8 @@ class SelfAssessmentModule(XModule):
|
||||
max_attempts = Int(scope=Scope.settings, default=MAX_ATTEMPTS)
|
||||
rubric = String(scope=Scope.content)
|
||||
prompt = String(scope=Scope.content)
|
||||
submit_message = String(scope=Scope.content)
|
||||
hint_prompt = String(scope=Scope.content)
|
||||
submitmessage = String(scope=Scope.content)
|
||||
hintprompt = String(scope=Scope.content)
|
||||
|
||||
def _allow_reset(self):
|
||||
"""Can the module be reset?"""
|
||||
@@ -209,7 +209,7 @@ class SelfAssessmentModule(XModule):
|
||||
else:
|
||||
hint = ''
|
||||
|
||||
context = {'hint_prompt': self.hint_prompt,
|
||||
context = {'hint_prompt': self.hintprompt,
|
||||
'hint': hint}
|
||||
|
||||
if self.state == self.REQUEST_HINT:
|
||||
@@ -228,7 +228,7 @@ class SelfAssessmentModule(XModule):
|
||||
if self.state != self.DONE:
|
||||
return ""
|
||||
|
||||
return """<div class="save_message">{0}</div>""".format(self.submit_message)
|
||||
return """<div class="save_message">{0}</div>""".format(self.submitmessage)
|
||||
|
||||
|
||||
def save_answer(self, get):
|
||||
@@ -397,8 +397,8 @@ class SelfAssessmentDescriptor(XmlDescriptor, EditingDescriptor):
|
||||
max_attempts = Int(scope=Scope.settings, default=MAX_ATTEMPTS)
|
||||
rubric = String(scope=Scope.content)
|
||||
prompt = String(scope=Scope.content)
|
||||
submit_message = String(scope=Scope.content)
|
||||
hint_prompt = String(scope=Scope.content)
|
||||
submitmessage = String(scope=Scope.content)
|
||||
hintprompt = String(scope=Scope.content)
|
||||
|
||||
@classmethod
|
||||
def definition_from_xml(cls, xml_object, system):
|
||||
|
||||
@@ -12,6 +12,7 @@ from xmodule.errortracker import make_error_tracker
|
||||
from xmodule.modulestore import Location
|
||||
from xmodule.modulestore.xml import ImportSystem, XMLModuleStore
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError
|
||||
from xmodule.modulestore.inheritance import compute_inherited_metadata
|
||||
|
||||
from .test_export import DATA_DIR
|
||||
|
||||
@@ -134,6 +135,7 @@ class ImportTestCase(unittest.TestCase):
|
||||
</chapter>
|
||||
</course>'''.format(due=v, org=ORG, course=COURSE, url_name=url_name)
|
||||
descriptor = system.process_xml(start_xml)
|
||||
compute_inherited_metadata(descriptor)
|
||||
|
||||
print descriptor, descriptor._model_data
|
||||
self.assertEqual(descriptor.lms.due, v)
|
||||
|
||||
@@ -281,21 +281,15 @@ class XModuleDescriptor(Plugin, HTMLSnippet, ResourceTemplates):
|
||||
__metaclass__ = XModuleMetaclass
|
||||
|
||||
# Attributes for inspection of the descriptor
|
||||
stores_state = False # Indicates whether the xmodule state should be
|
||||
|
||||
# Indicates whether the xmodule state should be
|
||||
# stored in a database (independent of shared state)
|
||||
has_score = False # This indicates whether the xmodule is a problem-type.
|
||||
stores_state = False
|
||||
|
||||
# This indicates whether the xmodule is a problem-type.
|
||||
# It should respond to max_score() and grade(). It can be graded or ungraded
|
||||
# (like a practice problem).
|
||||
|
||||
# A list of metadata that this module can inherit from its parent module
|
||||
inheritable_metadata = (
|
||||
'graded', 'start', 'due', 'graceperiod', 'showanswer', 'rerandomize',
|
||||
# TODO (ichuang): used for Fall 2012 xqa server access
|
||||
'xqa_key',
|
||||
# TODO: This is used by the XMLModuleStore to provide for locations for
|
||||
# static files, and will need to be removed when that code is removed
|
||||
'data_dir'
|
||||
)
|
||||
has_score = False
|
||||
|
||||
# cdodge: this is a list of metadata names which are 'system' metadata
|
||||
# and should not be edited by an end-user
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from xmodule.x_module import (XModuleDescriptor, policy_key)
|
||||
from xmodule.modulestore import Location
|
||||
from xmodule.modulestore.inheritance import own_metadata
|
||||
from xmodule.model import Object, Scope
|
||||
from lxml import etree
|
||||
import json
|
||||
import copy
|
||||
@@ -78,6 +79,8 @@ class XmlDescriptor(XModuleDescriptor):
|
||||
Mixin class for standardized parsing of from xml
|
||||
"""
|
||||
|
||||
xml_attributes = Object(help="Map of unhandled xml attributes, used only for storage between import and export", default={}, scope=Scope.settings)
|
||||
|
||||
# Extension to append to filename paths
|
||||
filename_extension = 'xml'
|
||||
|
||||
@@ -102,7 +105,9 @@ class XmlDescriptor(XModuleDescriptor):
|
||||
'tabs', 'grading_policy', 'is_draft', 'published_by', 'published_date',
|
||||
'discussion_blackouts',
|
||||
# VS[compat] -- remove the below attrs once everything is in the CMS
|
||||
'course', 'org', 'url_name', 'filename')
|
||||
'course', 'org', 'url_name', 'filename',
|
||||
# Used for storing xml attributes between import and export, for roundtrips
|
||||
'xml_attributes')
|
||||
|
||||
metadata_to_export_to_policy = ('discussion_topics')
|
||||
|
||||
@@ -319,6 +324,11 @@ class XmlDescriptor(XModuleDescriptor):
|
||||
model_data.update(definition)
|
||||
model_data['children'] = children
|
||||
|
||||
model_data['xml_attributes'] = {}
|
||||
for key, value in metadata.items():
|
||||
if key not in set(f.name for f in cls.fields + cls.lms.fields):
|
||||
model_data['xml_attributes'][key] = value
|
||||
|
||||
return cls(
|
||||
system,
|
||||
location,
|
||||
@@ -343,7 +353,7 @@ class XmlDescriptor(XModuleDescriptor):
|
||||
|
||||
def export_to_xml(self, resource_fs):
|
||||
"""
|
||||
Returns an xml string representing this module, and all modules
|
||||
Returns an xml string representign this module, and all modules
|
||||
underneath it. May also write required resources out to resource_fs
|
||||
|
||||
Assumes that modules have single parentage (that no module appears twice
|
||||
@@ -379,6 +389,10 @@ class XmlDescriptor(XModuleDescriptor):
|
||||
#logging.debug('location.category = {0}, attr = {1}'.format(self.location.category, attr))
|
||||
xml_object.set(attr, val)
|
||||
|
||||
for key, value in self.xml_attributes.items():
|
||||
if key not in self.metadata_to_strip:
|
||||
xml_object.set(key, value)
|
||||
|
||||
if self.export_to_file():
|
||||
# Write the definition to a file
|
||||
url_path = name_to_pathname(self.url_name)
|
||||
|
||||
@@ -40,3 +40,6 @@ class LmsNamespace(Namespace):
|
||||
xqa_key = String(help="DO NOT USE", scope=Scope.settings)
|
||||
ispublic = Boolean(help="Whether this course is open to the public, or only to admins", scope=Scope.settings)
|
||||
graceperiod = Timedelta(help="Amount of time after the due date that submissions will be accepted", scope=Scope.settings)
|
||||
showanswer = String(help="When to show the problem answer to the student", scope=Scope.settings, default="closed")
|
||||
rerandomize = String(help="When to rerandomize the problem", default="always", scope=Scope.settings)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user