Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

video_module: Add deserialize logic for metadata fields. #679

Closed
wants to merge 2 commits into from
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
56 changes: 56 additions & 0 deletions common/lib/xmodule/xmodule/tests/test_video.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,62 @@ def test_from_xml_no_attributes(self):
'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="&quot;display_name&quot;"
html5_sources="[&quot;source_1&quot;, &quot;source_2&quot;]"
show_captions="false"
source="&quot;http://download_video&quot;"
sub="&quot;html5_subtitles&quot;"
track="&quot;http://download_track&quot;"
youtube_id_0_75="&quot;OEoXaMPEzf65&quot;"
youtube_id_1_25="&quot;OEoXaMPEzf125&quot;"
youtube_id_1_5="&quot;OEoXaMPEzf15&quot;"
youtube_id_1_0="&quot;OEoXaMPEzf10&quot;"
/>
'''
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:&quot;p2Q6BrNhdh8&quot;,1.25:&quot;1EeWXzPdhSA&quot;">
</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):
"""
Test backwards compatibility with VideoModule's XML format.
Expand Down
17 changes: 15 additions & 2 deletions common/lib/xmodule/xmodule/video_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,10 @@ def _parse_youtube(data):
pieces = video.split(':')
try:
speed = '%.2f' % float(pieces[0]) # normalize speed
youtube_id = pieces[1]
# Handle the fact that youtube IDs got double-quoted for a period of time.
# Note: we pass in "VideoFields.youtube_id_1_0" so we deserialize as a String--
# it doesn't matter what the actual speed is for the purposes of deserializing.
youtube_id = VideoDescriptor._deserialize(VideoFields.youtube_id_1_0.name, pieces[1])
ret[speed] = youtube_id
except (ValueError, IndexError):
log.warning('Invalid YouTube ID: %s' % video)
Expand All @@ -310,7 +313,6 @@ def _parse_video_xml(xml_data):
model_data = {}

conversions = {
'show_captions': json.loads,
'start_time': VideoDescriptor._parse_time,
'end_time': VideoDescriptor._parse_time
}
Expand Down Expand Up @@ -349,6 +351,11 @@ def _parse_video_xml(xml_data):
# Convert XML attrs into Python values.
if attr in conversions:
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

return model_data
Expand All @@ -367,6 +374,12 @@ def _parse_time(str_time):
seconds=obj_time.tm_sec
).total_seconds()

@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)

def _create_youtube_string(module):
"""
Expand Down
5 changes: 5 additions & 0 deletions common/lib/xmodule/xmodule/xml_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@ class XmlDescriptor(XModuleDescriptor):

@classmethod
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):
if field.name == attr:
from_xml = lambda val: deserialize_field(field, val)
Expand Down