Make our deserializing consistent with serializing.
Also fixes problems with double-quoted strings (historical artifact). STUD-640 Conflicts: common/lib/xmodule/xmodule/video_module.py
This commit is contained in:
@@ -264,6 +264,62 @@ class VideoDescriptorImportTestCase(unittest.TestCase):
|
|||||||
'data': ''
|
'data': ''
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def test_from_xml_double_quotes(self):
|
||||||
|
"""
|
||||||
|
Make sure we can handle the double-quoted string format (which was used for exporting for
|
||||||
|
a few weeks).
|
||||||
|
"""
|
||||||
|
module_system = DummySystem(load_error_modules=True)
|
||||||
|
xml_data ='''
|
||||||
|
<video display_name=""display_name""
|
||||||
|
html5_sources="["source_1", "source_2"]"
|
||||||
|
show_captions="false"
|
||||||
|
source=""http://download_video""
|
||||||
|
sub=""html5_subtitles""
|
||||||
|
track=""http://download_track""
|
||||||
|
youtube_id_0_75=""OEoXaMPEzf65""
|
||||||
|
youtube_id_1_25=""OEoXaMPEzf125""
|
||||||
|
youtube_id_1_5=""OEoXaMPEzf15""
|
||||||
|
youtube_id_1_0=""OEoXaMPEzf10""
|
||||||
|
/>
|
||||||
|
'''
|
||||||
|
output = VideoDescriptor.from_xml(xml_data, module_system)
|
||||||
|
self.assert_attributes_equal(output, {
|
||||||
|
'youtube_id_0_75': 'OEoXaMPEzf65',
|
||||||
|
'youtube_id_1_0': 'OEoXaMPEzf10',
|
||||||
|
'youtube_id_1_25': 'OEoXaMPEzf125',
|
||||||
|
'youtube_id_1_5': 'OEoXaMPEzf15',
|
||||||
|
'show_captions': False,
|
||||||
|
'start_time': 0.0,
|
||||||
|
'end_time': 0.0,
|
||||||
|
'track': 'http://download_track',
|
||||||
|
'source': 'http://download_video',
|
||||||
|
'html5_sources': ["source_1", "source_2"],
|
||||||
|
'data': ''
|
||||||
|
})
|
||||||
|
|
||||||
|
def test_from_xml_double_quote_concatenated_youtube(self):
|
||||||
|
module_system = DummySystem(load_error_modules=True)
|
||||||
|
xml_data = '''
|
||||||
|
<video display_name="Test Video"
|
||||||
|
youtube="1.0:"p2Q6BrNhdh8",1.25:"1EeWXzPdhSA"">
|
||||||
|
</video>
|
||||||
|
'''
|
||||||
|
output = VideoDescriptor.from_xml(xml_data, module_system)
|
||||||
|
self.assert_attributes_equal(output, {
|
||||||
|
'youtube_id_0_75': '',
|
||||||
|
'youtube_id_1_0': 'p2Q6BrNhdh8',
|
||||||
|
'youtube_id_1_25': '1EeWXzPdhSA',
|
||||||
|
'youtube_id_1_5': '',
|
||||||
|
'show_captions': True,
|
||||||
|
'start_time': 0.0,
|
||||||
|
'end_time': 0.0,
|
||||||
|
'track': '',
|
||||||
|
'source': '',
|
||||||
|
'html5_sources': [],
|
||||||
|
'data': ''
|
||||||
|
})
|
||||||
|
|
||||||
def test_old_video_format(self):
|
def test_old_video_format(self):
|
||||||
"""
|
"""
|
||||||
Test backwards compatibility with VideoModule's XML format.
|
Test backwards compatibility with VideoModule's XML format.
|
||||||
|
|||||||
@@ -291,19 +291,19 @@ class VideoDescriptor(VideoFields, TabsEditingDescriptor, EmptyDataRawDescriptor
|
|||||||
XML-based courses.
|
XML-based courses.
|
||||||
"""
|
"""
|
||||||
ret = {'0.75': '', '1.00': '', '1.25': '', '1.50': ''}
|
ret = {'0.75': '', '1.00': '', '1.25': '', '1.50': ''}
|
||||||
if data == '':
|
|
||||||
return ret
|
|
||||||
videos = data.split(',')
|
videos = data.split(',')
|
||||||
for video in videos:
|
for video in videos:
|
||||||
pieces = video.split(':')
|
pieces = video.split(':')
|
||||||
# HACK
|
try:
|
||||||
# To elaborate somewhat: in many LMS tests, the keys for
|
speed = '%.2f' % float(pieces[0]) # normalize speed
|
||||||
# Youtube IDs are inconsistent. Sometimes a particular
|
# Handle the fact that youtube IDs got double-quoted for a period of time.
|
||||||
# speed isn't present, and formatting is also inconsistent
|
# Note: we pass in "VideoFields.youtube_id_1_0" so we deserialize as a String--
|
||||||
# ('1.0' versus '1.00'). So it's necessary to either do
|
# it doesn't matter what the actual speed is for the purposes of deserializing.
|
||||||
# something like this or update all the tests to work
|
youtube_id = VideoDescriptor._deserialize(VideoFields.youtube_id_1_0.name, pieces[1])
|
||||||
# properly.
|
ret[speed] = youtube_id
|
||||||
ret['%.2f' % float(pieces[0])] = pieces[1]
|
except (ValueError, IndexError):
|
||||||
|
log.warning('Invalid YouTube ID: %s' % video)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -316,7 +316,6 @@ class VideoDescriptor(VideoFields, TabsEditingDescriptor, EmptyDataRawDescriptor
|
|||||||
model_data = {}
|
model_data = {}
|
||||||
|
|
||||||
conversions = {
|
conversions = {
|
||||||
'show_captions': json.loads,
|
|
||||||
'start_time': VideoDescriptor._parse_time,
|
'start_time': VideoDescriptor._parse_time,
|
||||||
'end_time': VideoDescriptor._parse_time
|
'end_time': VideoDescriptor._parse_time
|
||||||
}
|
}
|
||||||
@@ -355,10 +354,21 @@ class VideoDescriptor(VideoFields, TabsEditingDescriptor, EmptyDataRawDescriptor
|
|||||||
# Convert XML attrs into Python values.
|
# Convert XML attrs into Python values.
|
||||||
if attr in conversions:
|
if attr in conversions:
|
||||||
value = conversions[attr](value)
|
value = conversions[attr](value)
|
||||||
|
else:
|
||||||
|
# We export values with json.dumps (well, except for Strings, but
|
||||||
|
# for about a month we did it for Strings also).
|
||||||
|
value = VideoDescriptor._deserialize(attr, value)
|
||||||
model_data[attr] = value
|
model_data[attr] = value
|
||||||
|
|
||||||
return model_data
|
return model_data
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _deserialize(cls, attr, value):
|
||||||
|
"""
|
||||||
|
Handles deserializing values that may have been encoded with json.dumps.
|
||||||
|
"""
|
||||||
|
return cls.get_map_for_field(attr).from_xml(value)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse_time(str_time):
|
def _parse_time(str_time):
|
||||||
"""Converts s in '12:34:45' format to seconds. If s is
|
"""Converts s in '12:34:45' format to seconds. If s is
|
||||||
|
|||||||
@@ -167,6 +167,11 @@ class XmlDescriptor(XModuleDescriptor):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_map_for_field(cls, attr):
|
def get_map_for_field(cls, attr):
|
||||||
|
"""
|
||||||
|
Returns a serialize/deserialize AttrMap for the given field of a class.
|
||||||
|
|
||||||
|
Searches through fields defined by cls to find one named attr.
|
||||||
|
"""
|
||||||
for field in set(cls.fields + cls.lms.fields):
|
for field in set(cls.fields + cls.lms.fields):
|
||||||
if field.name == attr:
|
if field.name == attr:
|
||||||
from_xml = lambda val: deserialize_field(field, val)
|
from_xml = lambda val: deserialize_field(field, val)
|
||||||
|
|||||||
Reference in New Issue
Block a user