def test_is_pointer_tag(self): """ Check that is_pointer_tag works properly. """ yes = ["""<html url_name="blah"/>""", """<html url_name="blah"></html>""", """<html url_name="blah"> </html>""", """<problem url_name="blah"/>""", """<course org="HogwartsX" course="Mathemagics" url_name="3.14159"/>"""] no = ["""<html url_name="blah" also="this"/>""", """<html url_name="blah">some text</html>""", """<problem url_name="blah"><sub>tree</sub></problem>""", """<course org="HogwartsX" course="Mathemagics" url_name="3.14159"> <chapter>3</chapter> </course> """] for xml_str in yes: print("should be True for {0}".format(xml_str)) self.assertTrue(is_pointer_tag(etree.fromstring(xml_str))) for xml_str in no: print("should be False for {0}".format(xml_str)) self.assertFalse(is_pointer_tag(etree.fromstring(xml_str)))
def test_is_pointer_tag(self): """ Check that is_pointer_tag works properly. """ yes = [ """<html url_name="blah"/>""", """<html url_name="blah"></html>""", """<html url_name="blah"> </html>""", """<problem url_name="blah"/>""", """<course org="HogwartsX" course="Mathemagics" url_name="3.14159"/>""" ] no = [ """<html url_name="blah" also="this"/>""", """<html url_name="blah">some text</html>""", """<problem url_name="blah"><sub>tree</sub></problem>""", """<course org="HogwartsX" course="Mathemagics" url_name="3.14159"> <chapter>3</chapter> </course> """ ] for xml_str in yes: print("should be True for {0}".format(xml_str)) self.assertTrue(is_pointer_tag(etree.fromstring(xml_str))) for xml_str in no: print("should be False for {0}".format(xml_str)) self.assertFalse(is_pointer_tag(etree.fromstring(xml_str)))
def test_metadata_import_export(self): """Two checks: - unknown metadata is preserved across import-export - inherited metadata doesn't leak to children. """ system = self.get_system() v = 'March 20 17:00' url_name = 'test1' start_xml = ''' <course org="{org}" course="{course}" due="{due}" url_name="{url_name}" unicorn="purple"> <chapter url="hi" url_name="ch" display_name="CH"> <html url_name="h" display_name="H">Two houses, ...</html> </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, Date().from_json(v)) # Check that the child inherits due correctly child = descriptor.get_children()[0] self.assertEqual(child.lms.due, Date().from_json(v)) self.assertEqual(child._inheritable_metadata, child._inherited_metadata) self.assertEqual(2, len(child._inherited_metadata)) self.assertEqual('1970-01-01T00:00:00Z', child._inherited_metadata['start']) self.assertEqual(v, child._inherited_metadata['due']) # Now export and check things resource_fs = MemoryFS() exported_xml = descriptor.export_to_xml(resource_fs) # Check that the exported xml is just a pointer print("Exported xml:", exported_xml) pointer = etree.fromstring(exported_xml) self.assertTrue(is_pointer_tag(pointer)) # but it's a special case course pointer self.assertEqual(pointer.attrib['course'], COURSE) self.assertEqual(pointer.attrib['org'], ORG) # Does the course still have unicorns? with resource_fs.open('course/{url_name}.xml'.format(url_name=url_name)) as f: course_xml = etree.fromstring(f.read()) self.assertEqual(course_xml.attrib['unicorn'], 'purple') # the course and org tags should be _only_ in the pointer self.assertTrue('course' not in course_xml.attrib) self.assertTrue('org' not in course_xml.attrib) # did we successfully strip the url_name from the definition contents? self.assertTrue('url_name' not in course_xml.attrib) # Does the chapter tag now have a due attribute? # hardcoded path to child with resource_fs.open('chapter/ch.xml') as f: chapter_xml = etree.fromstring(f.read()) self.assertEqual(chapter_xml.tag, 'chapter') self.assertFalse('due' in chapter_xml.attrib)
def from_xml(cls, xml_data, system, id_generator): """ Creates an instance of this descriptor from the supplied xml_data. This may be overridden by subclasses xml_data: A string of xml that will be translated into data and children for this module system: A DescriptorSystem for interacting with external resources id_generator is used to generate course-specific urls and identifiers """ xml_object = etree.fromstring(xml_data) url_name = xml_object.get('url_name', xml_object.get('slug')) block_type = 'video' definition_id = id_generator.create_definition(block_type, url_name) usage_id = id_generator.create_usage(definition_id) if is_pointer_tag(xml_object): filepath = cls._format_filepath(xml_object.tag, name_to_pathname(url_name)) xml_object = cls.load_file(filepath, system.resources_fs, usage_id) system.parse_asides(xml_object, definition_id, usage_id, id_generator) field_data = cls._parse_video_xml(xml_object, id_generator) kvs = InheritanceKeyValueStore(initial_values=field_data) field_data = KvsFieldData(kvs) video = system.construct_xblock_from_class( cls, # We're loading a descriptor, so student_id is meaningless # We also don't have separate notions of definition and usage ids yet, # so we use the location for both ScopeIds(None, block_type, definition_id, usage_id), field_data, ) return video
def from_xml(cls, xml_data, system, org=None, course=None): """ Creates an instance of this descriptor from the supplied xml_data. This may be overridden by subclasses xml_data: A string of xml that will be translated into data and children for this module system: A DescriptorSystem for interacting with external resources org and course are optional strings that will be used in the generated modules url identifiers """ xml_object = etree.fromstring(xml_data) url_name = xml_object.get('url_name', xml_object.get('slug')) location = Location( 'i4x', org, course, 'video', url_name ) if is_pointer_tag(xml_object): filepath = cls._format_filepath(xml_object.tag, name_to_pathname(url_name)) xml_data = etree.tostring(cls.load_file(filepath, system.resources_fs, location)) field_data = VideoDescriptor._parse_video_xml(xml_data) field_data['location'] = location kvs = InheritanceKeyValueStore(initial_values=field_data) field_data = DbModel(kvs) video = system.construct_xblock_from_class( cls, field_data, # We're loading a descriptor, so student_id is meaningless # We also don't have separate notions of definition and usage ids yet, # so we use the location for both ScopeIds(None, location.category, location, location) ) return video
def from_xml(cls, xml_data, system, org=None, course=None): """ Creates an instance of this descriptor from the supplied xml_data. This may be overridden by subclasses xml_data: A string of xml that will be translated into data and children for this module system: A DescriptorSystem for interacting with external resources org and course are optional strings that will be used in the generated modules url identifiers """ xml_object = etree.fromstring(xml_data) url_name = xml_object.get('url_name', xml_object.get('slug')) location = Location('i4x', org, course, 'video', url_name) if is_pointer_tag(xml_object): filepath = cls._format_filepath(xml_object.tag, name_to_pathname(url_name)) xml_data = etree.tostring( cls.load_file(filepath, system.resources_fs, location)) field_data = cls._parse_video_xml(xml_data) field_data['location'] = location kvs = InheritanceKeyValueStore(initial_values=field_data) field_data = DbModel(kvs) video = system.construct_xblock_from_class( cls, # We're loading a descriptor, so student_id is meaningless # We also don't have separate notions of definition and usage ids yet, # so we use the location for both ScopeIds(None, location.category, location, location), field_data, ) return video
def course_descriptor_inheritance_check(self, descriptor, from_date_string, unicorn_color, course_run=RUN): """ Checks to make sure that metadata inheritance on a course descriptor is respected. """ # pylint: disable=protected-access print((descriptor, descriptor._field_data)) self.assertEqual(descriptor.due, ImportTestCase.date.from_json(from_date_string)) # Check that the child inherits due correctly child = descriptor.get_children()[0] self.assertEqual(child.due, ImportTestCase.date.from_json(from_date_string)) # need to convert v to canonical json b4 comparing self.assertEqual( ImportTestCase.date.to_json( ImportTestCase.date.from_json(from_date_string)), child.xblock_kvs.inherited_settings['due']) # Now export and check things file_system = OSFS(mkdtemp()) descriptor.runtime.export_fs = file_system.makedir(u'course', recreate=True) node = etree.Element('unknown') descriptor.add_xml_to_node(node) # Check that the exported xml is just a pointer print(("Exported xml:", etree.tostring(node))) self.assertTrue(is_pointer_tag(node)) # but it's a special case course pointer self.assertEqual(node.attrib['course'], COURSE) self.assertEqual(node.attrib['org'], ORG) # Does the course still have unicorns? with descriptor.runtime.export_fs.open( u'course/{course_run}.xml'.format(course_run=course_run)) as f: course_xml = etree.fromstring(f.read()) self.assertEqual(course_xml.attrib['unicorn'], unicorn_color) # the course and org tags should be _only_ in the pointer self.assertNotIn('course', course_xml.attrib) self.assertNotIn('org', course_xml.attrib) # did we successfully strip the url_name from the definition contents? self.assertNotIn('url_name', course_xml.attrib) # Does the chapter tag now have a due attribute? # hardcoded path to child with descriptor.runtime.export_fs.open(u'chapter/ch.xml') as f: chapter_xml = etree.fromstring(f.read()) self.assertEqual(chapter_xml.tag, 'chapter') self.assertNotIn('due', chapter_xml.attrib)
def course_descriptor_inheritance_check(self, descriptor, from_date_string, unicorn_color, course_run=RUN): """ Checks to make sure that metadata inheritance on a course descriptor is respected. """ # pylint: disable=protected-access print((descriptor, descriptor._field_data)) self.assertEqual(descriptor.due, ImportTestCase.date.from_json(from_date_string)) # Check that the child inherits due correctly child = descriptor.get_children()[0] self.assertEqual(child.due, ImportTestCase.date.from_json(from_date_string)) # need to convert v to canonical json b4 comparing self.assertEqual( ImportTestCase.date.to_json(ImportTestCase.date.from_json(from_date_string)), child.xblock_kvs.inherited_settings['due'] ) # Now export and check things file_system = OSFS(mkdtemp()) descriptor.runtime.export_fs = file_system.makedir(u'course', recreate=True) node = etree.Element('unknown') descriptor.add_xml_to_node(node) # Check that the exported xml is just a pointer print(("Exported xml:", etree.tostring(node))) self.assertTrue(is_pointer_tag(node)) # but it's a special case course pointer self.assertEqual(node.attrib['course'], COURSE) self.assertEqual(node.attrib['org'], ORG) # Does the course still have unicorns? with descriptor.runtime.export_fs.open(u'course/{course_run}.xml'.format(course_run=course_run)) as f: course_xml = etree.fromstring(f.read()) self.assertEqual(course_xml.attrib['unicorn'], unicorn_color) # the course and org tags should be _only_ in the pointer self.assertNotIn('course', course_xml.attrib) self.assertNotIn('org', course_xml.attrib) # did we successfully strip the url_name from the definition contents? self.assertNotIn('url_name', course_xml.attrib) # Does the chapter tag now have a due attribute? # hardcoded path to child with descriptor.runtime.export_fs.open(u'chapter/ch.xml') as f: chapter_xml = etree.fromstring(f.read()) self.assertEqual(chapter_xml.tag, 'chapter') self.assertNotIn('due', chapter_xml.attrib)
def from_xml(cls, xml_data, system, org=None, course=None): """ Creates an instance of this descriptor from the supplied xml_data. This may be overridden by subclasses xml_data: A string of xml that will be translated into data and children for this module system: A DescriptorSystem for interacting with external resources org and course are optional strings that will be used in the generated modules url identifiers """ xml_object = etree.fromstring(xml_data) url_name = xml_object.get('url_name', xml_object.get('slug')) location = Location('i4x', org, course, 'video', url_name) if is_pointer_tag(xml_object): filepath = cls._format_filepath(xml_object.tag, name_to_pathname(url_name)) xml_data = etree.tostring( cls.load_file(filepath, system.resources_fs, location)) upload_asset_path = VideoDescriptor._get_upload_asset_path( system.course_dir) model_data = {} xml = etree.fromstring(xml_data) display_name = xml.get('display_name') if display_name: model_data['display_name'] = display_name sources = xml.findall('source') if sources: model_data['source'] = [ele.get('src') for ele in sources][0] tracks = xml.findall('track') if tracks: for ele in tracks: if ele.get('srclang') == 'zh': model_data['track_zh'] = upload_asset_path + ele.get( 'src').rsplit('/', 1)[1] elif ele.get('srclang') == 'en': model_data['track_en'] = upload_asset_path + ele.get( 'src').rsplit('/', 1)[1] model_data['location'] = location video = cls(system, model_data) return video
def from_xml(cls, xml_data, system, org=None, course=None): """ Creates an instance of this descriptor from the supplied xml_data. This may be overridden by subclasses xml_data: A string of xml that will be translated into data and children for this module system: A DescriptorSystem for interacting with external resources org and course are optional strings that will be used in the generated modules url identifiers """ xml_object = etree.fromstring(xml_data) url_name = xml_object.get('url_name', xml_object.get('slug')) location = Location('i4x', org, course, 'video', url_name) if is_pointer_tag(xml_object): filepath = cls._format_filepath(xml_object.tag, name_to_pathname(url_name)) xml_data = etree.tostring(cls.load_file(filepath, system.resources_fs, location)) upload_asset_path = VideoDescriptor._get_upload_asset_path(system.course_dir) model_data = {} xml = etree.fromstring(xml_data) display_name = xml.get('display_name') if display_name: model_data['display_name'] = display_name sources = xml.findall('source') if sources: model_data['source'] = [ele.get('src') for ele in sources][0] tracks = xml.findall('track') if tracks: for ele in tracks: if ele.get('srclang') == 'zh': model_data['track_zh'] = upload_asset_path + ele.get('src').rsplit('/', 1)[1] elif ele.get('srclang') == 'en': model_data['track_en'] = upload_asset_path + ele.get('src').rsplit('/', 1)[1] model_data['location'] = location video = cls(system, model_data) return video
def from_xml(cls, xml_data, system, org=None, course=None): """ Creates an instance of this descriptor from the supplied xml_data. This may be overridden by subclasses xml_data: A string of xml that will be translated into data and children for this module system: A DescriptorSystem for interacting with external resources org and course are optional strings that will be used in the generated modules url identifiers """ xml_object = etree.fromstring(xml_data) url_name = xml_object.get('url_name', xml_object.get('slug')) location = Location('i4x', org, course, 'video', url_name) if is_pointer_tag(xml_object): filepath = cls._format_filepath(xml_object.tag, name_to_pathname(url_name)) xml_data = etree.tostring( cls.load_file(filepath, system.resources_fs, location)) model_data = VideoDescriptor._parse_video_xml(xml_data) model_data['location'] = location video = cls(system, model_data) return video
def from_xml(cls, xml_data, system, org=None, course=None): """ Creates an instance of this descriptor from the supplied xml_data. This may be overridden by subclasses xml_data: A string of xml that will be translated into data and children for this module system: A DescriptorSystem for interacting with external resources org and course are optional strings that will be used in the generated modules url identifiers """ xml_object = etree.fromstring(xml_data) url_name = xml_object.get('url_name', xml_object.get('slug')) location = Location( 'i4x', org, course, 'video', url_name ) if is_pointer_tag(xml_object): filepath = cls._format_filepath(xml_object.tag, name_to_pathname(url_name)) xml_data = etree.tostring(cls.load_file(filepath, system.resources_fs, location)) model_data = VideoDescriptor._parse_video_xml(xml_data) model_data['location'] = location video = cls(system, model_data) return video
def test_metadata_import_export(self): """Two checks: - unknown metadata is preserved across import-export - inherited metadata doesn't leak to children. """ system = self.get_system() v = "March 20 17:00" url_name = "test1" start_xml = """ <course org="{org}" course="{course}" due="{due}" url_name="{url_name}" unicorn="purple"> <chapter url="hi" url_name="ch" display_name="CH"> <html url_name="h" display_name="H">Two houses, ...</html> </chapter> </course>""".format( due=v, org=ORG, course=COURSE, url_name=url_name ) descriptor = system.process_xml(start_xml) compute_inherited_metadata(descriptor) # pylint: disable=W0212 print(descriptor, descriptor._field_data) self.assertEqual(descriptor.due, ImportTestCase.date.from_json(v)) # Check that the child inherits due correctly child = descriptor.get_children()[0] self.assertEqual(child.due, ImportTestCase.date.from_json(v)) # need to convert v to canonical json b4 comparing self.assertEqual( ImportTestCase.date.to_json(ImportTestCase.date.from_json(v)), child.xblock_kvs.inherited_settings["due"] ) # Now export and check things resource_fs = MemoryFS() exported_xml = descriptor.export_to_xml(resource_fs) # Check that the exported xml is just a pointer print("Exported xml:", exported_xml) pointer = etree.fromstring(exported_xml) self.assertTrue(is_pointer_tag(pointer)) # but it's a special case course pointer self.assertEqual(pointer.attrib["course"], COURSE) self.assertEqual(pointer.attrib["org"], ORG) # Does the course still have unicorns? with resource_fs.open("course/{url_name}.xml".format(url_name=url_name)) as f: course_xml = etree.fromstring(f.read()) self.assertEqual(course_xml.attrib["unicorn"], "purple") # the course and org tags should be _only_ in the pointer self.assertTrue("course" not in course_xml.attrib) self.assertTrue("org" not in course_xml.attrib) # did we successfully strip the url_name from the definition contents? self.assertTrue("url_name" not in course_xml.attrib) # Does the chapter tag now have a due attribute? # hardcoded path to child with resource_fs.open("chapter/ch.xml") as f: chapter_xml = etree.fromstring(f.read()) self.assertEqual(chapter_xml.tag, "chapter") self.assertFalse("due" in chapter_xml.attrib)
def test_metadata_import_export(self): """Two checks: - unknown metadata is preserved across import-export - inherited metadata doesn't leak to children. """ system = self.get_system() v = 'March 20 17:00' url_name = 'test1' start_xml = ''' <course org="{org}" course="{course}" due="{due}" url_name="{url_name}" unicorn="purple"> <chapter url="hi" url_name="ch" display_name="CH"> <html url_name="h" display_name="H">Two houses, ...</html> </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, Date().from_json(v)) # Check that the child inherits due correctly child = descriptor.get_children()[0] self.assertEqual(child.lms.due, Date().from_json(v)) self.assertEqual(child._inheritable_metadata, child._inherited_metadata) self.assertEqual(2, len(child._inherited_metadata)) self.assertEqual('1970-01-01T00:00:00Z', child._inherited_metadata['start']) self.assertEqual(v, child._inherited_metadata['due']) # Now export and check things resource_fs = MemoryFS() exported_xml = descriptor.export_to_xml(resource_fs) # Check that the exported xml is just a pointer print("Exported xml:", exported_xml) pointer = etree.fromstring(exported_xml) self.assertTrue(is_pointer_tag(pointer)) # but it's a special case course pointer self.assertEqual(pointer.attrib['course'], COURSE) self.assertEqual(pointer.attrib['org'], ORG) # Does the course still have unicorns? with resource_fs.open( 'course/{url_name}.xml'.format(url_name=url_name)) as f: course_xml = etree.fromstring(f.read()) self.assertEqual(course_xml.attrib['unicorn'], 'purple') # the course and org tags should be _only_ in the pointer self.assertTrue('course' not in course_xml.attrib) self.assertTrue('org' not in course_xml.attrib) # did we successfully strip the url_name from the definition contents? self.assertTrue('url_name' not in course_xml.attrib) # Does the chapter tag now have a due attribute? # hardcoded path to child with resource_fs.open('chapter/ch.xml') as f: chapter_xml = etree.fromstring(f.read()) self.assertEqual(chapter_xml.tag, 'chapter') self.assertFalse('due' in chapter_xml.attrib)
def test_metadata_import_export(self): """Two checks: - unknown metadata is preserved across import-export - inherited metadata doesn't leak to children. """ system = self.get_system() v = 'March 20 17:00' url_name = 'test1' start_xml = ''' <course org="{org}" course="{course}" due="{due}" url_name="{url_name}" unicorn="purple"> <chapter url="hi" url_name="ch" display_name="CH"> <html url_name="h" display_name="H">Two houses, ...</html> </chapter> </course>'''.format(due=v, org=ORG, course=COURSE, url_name=url_name) descriptor = system.process_xml(start_xml) compute_inherited_metadata(descriptor) # pylint: disable=protected-access print(descriptor, descriptor._field_data) self.assertEqual(descriptor.due, ImportTestCase.date.from_json(v)) # Check that the child inherits due correctly child = descriptor.get_children()[0] self.assertEqual(child.due, ImportTestCase.date.from_json(v)) # need to convert v to canonical json b4 comparing self.assertEqual( ImportTestCase.date.to_json(ImportTestCase.date.from_json(v)), child.xblock_kvs.inherited_settings['due'] ) # Now export and check things descriptor.runtime.export_fs = MemoryFS() node = etree.Element('unknown') descriptor.add_xml_to_node(node) # Check that the exported xml is just a pointer print("Exported xml:", etree.tostring(node)) self.assertTrue(is_pointer_tag(node)) # but it's a special case course pointer self.assertEqual(node.attrib['course'], COURSE) self.assertEqual(node.attrib['org'], ORG) # Does the course still have unicorns? with descriptor.runtime.export_fs.open('course/{url_name}.xml'.format(url_name=url_name)) as f: course_xml = etree.fromstring(f.read()) self.assertEqual(course_xml.attrib['unicorn'], 'purple') # the course and org tags should be _only_ in the pointer self.assertTrue('course' not in course_xml.attrib) self.assertTrue('org' not in course_xml.attrib) # did we successfully strip the url_name from the definition contents? self.assertTrue('url_name' not in course_xml.attrib) # Does the chapter tag now have a due attribute? # hardcoded path to child with descriptor.runtime.export_fs.open('chapter/ch.xml') as f: chapter_xml = etree.fromstring(f.read()) self.assertEqual(chapter_xml.tag, 'chapter') self.assertFalse('due' in chapter_xml.attrib)
def test_metadata_import_export(self): """Two checks: - unknown metadata is preserved across import-export - inherited metadata doesn't leak to children. """ system = self.get_system() v = 'March 20 17:00' url_name = 'test1' start_xml = ''' <course org="{org}" course="{course}" due="{due}" url_name="{url_name}" unicorn="purple"> <chapter url="hi" url_name="ch" display_name="CH"> <html url_name="h" display_name="H">Two houses, ...</html> </chapter> </course>'''.format(due=v, org=ORG, course=COURSE, url_name=url_name) descriptor = system.process_xml(start_xml) compute_inherited_metadata(descriptor) # pylint: disable=W0212 print(descriptor, descriptor._field_data) self.assertEqual(descriptor.due, ImportTestCase.date.from_json(v)) # Check that the child inherits due correctly child = descriptor.get_children()[0] self.assertEqual(child.due, ImportTestCase.date.from_json(v)) # need to convert v to canonical json b4 comparing self.assertEqual( ImportTestCase.date.to_json(ImportTestCase.date.from_json(v)), child.xblock_kvs.inherited_settings['due']) # Now export and check things descriptor.runtime.export_fs = MemoryFS() node = etree.Element('unknown') descriptor.add_xml_to_node(node) # Check that the exported xml is just a pointer print("Exported xml:", etree.tostring(node)) self.assertTrue(is_pointer_tag(node)) # but it's a special case course pointer self.assertEqual(node.attrib['course'], COURSE) self.assertEqual(node.attrib['org'], ORG) # Does the course still have unicorns? with descriptor.runtime.export_fs.open( 'course/{url_name}.xml'.format(url_name=url_name)) as f: course_xml = etree.fromstring(f.read()) self.assertEqual(course_xml.attrib['unicorn'], 'purple') # the course and org tags should be _only_ in the pointer self.assertTrue('course' not in course_xml.attrib) self.assertTrue('org' not in course_xml.attrib) # did we successfully strip the url_name from the definition contents? self.assertTrue('url_name' not in course_xml.attrib) # Does the chapter tag now have a due attribute? # hardcoded path to child with descriptor.runtime.export_fs.open('chapter/ch.xml') as f: chapter_xml = etree.fromstring(f.read()) self.assertEqual(chapter_xml.tag, 'chapter') self.assertFalse('due' in chapter_xml.attrib)