Commit 344cb133 by Calen Pennington

Make import/export tests pass

parent 6a612a6e
......@@ -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:
......
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
......
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)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment