Commit 512269f8 by Peter Fogg

Add descriptor for modules with empty XML data.

This allows a more general approach to modules such as word_cloud and
video which have no XML data (it's all store in metadata), but use
XmlDescriptor for backwards compatibility. They now generate an empty
tag on export, and clear out empty tags on import.

Also a small change to the video module as a result -- if it's asked
to parse empty XML data, it won't try to parse anything.
parent f355e4a8
......@@ -883,6 +883,40 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
shutil.rmtree(root_dir)
def test_empty_data_roundtrip(self):
"""
Test that an empty `data` field is preserved through
export/import.
"""
module_store = modulestore('direct')
draft_store = modulestore('draft')
content_store = contentstore()
import_from_xml(module_store, 'common/test/data/', ['toy'])
location = CourseDescriptor.id_to_location('edX/toy/2012_Fall')
verticals = module_store.get_items(['i4x', 'edX', 'toy', 'vertical', None, None])
self.assertGreater(len(verticals), 0)
parent = verticals[0]
# Create a module, and ensure that its `data` field is empty
word_cloud = ItemFactory.create(parent_location=parent.location, category="word_cloud", display_name="untitled")
del word_cloud.data
self.assertEquals(word_cloud.data, '')
# Export the course
root_dir = path(mkdtemp_clean())
export_to_xml(module_store, content_store, location, root_dir, 'test_roundtrip', draft_modulestore=draft_store)
# Reimport and get the video back
import_from_xml(module_store, root_dir)
imported_word_cloud = module_store.get_item(Location(['i4x', 'edX', 'toy', 'word_cloud', 'untitled', None]))
# It should now contain empty data
self.assertEquals(imported_word_cloud.data, '')
def test_course_handouts_rewrites(self):
module_store = modulestore('direct')
......
......@@ -20,8 +20,6 @@ class RawDescriptor(XmlDescriptor, XMLEditingDescriptor):
return {'data': etree.tostring(xml_object, pretty_print=True, encoding='unicode')}, []
def definition_to_xml(self, resource_fs):
if not self.data:
return etree.fromstring('<{0} />'.format(self.category))
try:
return etree.fromstring(self.data)
except etree.XMLSyntaxError as err:
......@@ -34,3 +32,22 @@ class RawDescriptor(XmlDescriptor, XMLEditingDescriptor):
context=lines[line - 1][offset - 40:offset + 40],
loc=self.location))
raise Exception, msg, sys.exc_info()[2]
class EmptyDataRawDescriptor(XmlDescriptor, XMLEditingDescriptor):
"""
Version of RawDescriptor for modules which may have no XML data,
but use XMLEditingDescriptor for import/export handling.
"""
data = String(default='', scope=Scope.content)
@classmethod
def definition_from_xml(cls, xml_object, system):
if len(xml_object) == 0 and len(xml_object.items()) == 0:
return {'data': ''}, []
return {'data': etree.tostring(xml_object, pretty_print=True, encoding='unicode')}, []
def definition_to_xml(self, resource_fs):
if self.data:
return etree.fromstring(self.data)
return etree.Element(self.category)
......@@ -12,7 +12,7 @@ import time
from django.http import Http404
from xmodule.x_module import XModule
from xmodule.raw_module import RawDescriptor
from xmodule.raw_module import EmptyDataRawDescriptor
from xmodule.editing_module import MetadataOnlyEditingDescriptor
from xblock.core import Integer, Scope, String, Float, Boolean
......@@ -97,7 +97,7 @@ class VideoModule(VideoFields, XModule):
class VideoDescriptor(VideoFields,
MetadataOnlyEditingDescriptor,
RawDescriptor):
EmptyDataRawDescriptor):
module_class = VideoModule
def __init__(self, *args, **kwargs):
......@@ -136,6 +136,9 @@ def _parse_video_xml(video, xml_data):
Parse video fields out of xml_data. The fields are set if they are
present in the XML.
"""
if not xml_data:
return
xml = etree.fromstring(xml_data)
display_name = xml.get('display_name')
......
......@@ -10,7 +10,7 @@ import json
import logging
from pkg_resources import resource_string
from xmodule.raw_module import RawDescriptor
from xmodule.raw_module import EmptyDataRawDescriptor
from xmodule.editing_module import MetadataOnlyEditingDescriptor
from xmodule.x_module import XModule
......@@ -240,7 +240,7 @@ class WordCloudModule(WordCloudFields, XModule):
return self.content
class WordCloudDescriptor(WordCloudFields, MetadataOnlyEditingDescriptor, RawDescriptor):
class WordCloudDescriptor(WordCloudFields, MetadataOnlyEditingDescriptor, EmptyDataRawDescriptor):
"""Descriptor for WordCloud Xmodule."""
module_class = WordCloudModule
template_dir_name = 'word_cloud'
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