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 = 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 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 definition_to_xml(self, resource_fs): '''If the contents are valid xml, write them to filename.xml. Otherwise, write just <html filename="" [meta-attrs="..."]> to filename.xml, and the html string to filename.html. ''' try: return etree.fromstring(self.data) except etree.XMLSyntaxError: pass # Not proper format. Write html to file, return an empty tag pathname = name_to_pathname(self.url_name) filepath = u'{category}/{pathname}.html'.format(category=self.category, pathname=pathname) resource_fs.makedir(os.path.dirname(filepath), recursive=True, allow_recreate=True) with resource_fs.open(filepath, 'w') as file: html_data = self.data.encode('utf-8') file.write(html_data) # write out the relative name relname = path(pathname).basename() elt = etree.Element('html') elt.set("filename", relname) return elt
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 definition_to_xml(self, resource_fs): """ Write <html filename="" [meta-attrs="..."]> to filename.xml, and the html string to filename.html. """ # Write html to file, return an empty tag pathname = name_to_pathname(self.url_name) filepath = u"{category}/{pathname}.html".format(category=self.category, pathname=pathname) resource_fs.makedir(os.path.dirname(filepath), recursive=True, allow_recreate=True) with resource_fs.open(filepath, "w") as filestream: html_data = self.data.encode("utf-8") filestream.write(html_data) # write out the relative name relname = path(pathname).basename() elt = etree.Element("html") elt.set("filename", relname) return elt
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 definition_to_xml(self, resource_fs): ''' Write <html filename="" [meta-attrs="..."]> to filename.xml, and the html string to filename.html. ''' # Write html to file, return an empty tag pathname = name_to_pathname(self.url_name) filepath = u'{category}/{pathname}.html'.format(category=self.category, pathname=pathname) resource_fs.makedirs(os.path.dirname(filepath), recreate=True) with resource_fs.open(filepath, 'wb') as filestream: html_data = self.data.encode('utf-8') filestream.write(html_data) # write out the relative name relname = path(pathname).basename() elt = etree.Element('html') elt.set("filename", relname) return elt
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 definition_to_xml(self, resource_fs): ''' Write <html filename="" [meta-attrs="..."]> to filename.xml, and the html string to filename.html. ''' # Write html to file, return an empty tag pathname = name_to_pathname(self.url_name) filepath = u'{category}/{pathname}.html'.format( category=self.category, pathname=pathname ) resource_fs.makedirs(os.path.dirname(filepath), recreate=True) with resource_fs.open(filepath, 'wb') as filestream: html_data = self.data.encode('utf-8') filestream.write(html_data) # write out the relative name relname = path(pathname).basename() elt = etree.Element('html') elt.set("filename", relname) return elt
def load_definition(cls, xml_object, system, location): '''Load a descriptor from the specified xml_object: If there is a filename attribute, load it as a string, and log a warning if it is not parseable by etree.HTMLParser. If there is not a filename attribute, the definition is the body of the xml_object, without the root tag (do not want <html> in the middle of a page) ''' filename = xml_object.get('filename') if filename is None: definition_xml = copy.deepcopy(xml_object) cls.clean_metadata_from_xml(definition_xml) return {'data': stringify_children(definition_xml)}, [] else: # html is special. cls.filename_extension is 'xml', but # if 'filename' is in the definition, that means to load # from .html # 'filename' in html pointers is a relative path # (not same as 'html/blah.html' when the pointer is in a directory itself) pointer_path = "{category}/{url_path}".format( category='html', url_path=name_to_pathname(location.name)) base = path(pointer_path).dirname() # log.debug("base = {0}, base.dirname={1}, filename={2}".format(base, base.dirname(), filename)) filepath = "{base}/{name}.html".format(base=base, name=filename) # log.debug("looking for html file for {0} at {1}".format(location, filepath)) # VS[compat] # TODO (cpennington): If the file doesn't exist at the right path, # give the class a chance to fix it up. The file will be written out # again in the correct format. This should go away once the CMS is # online and has imported all current (fall 2012) courses from xml if not system.resources_fs.exists(filepath): candidates = cls.backcompat_paths(filepath) # log.debug("candidates = {0}".format(candidates)) for candidate in candidates: if system.resources_fs.exists(candidate): filepath = candidate break try: with system.resources_fs.open(filepath) as file: html = file.read().decode('utf-8') # Log a warning if we can't parse the file, but don't error if not check_html(html) and len(html) > 0: msg = "Couldn't parse html in {0}, content = {1}".format( filepath, html) log.warning(msg) system.error_tracker("Warning: " + msg) definition = {'data': html} # TODO (ichuang): remove this after migration # for Fall 2012 LMS migration: keep filename (and unmangled filename) definition['filename'] = [filepath, filename] return definition, [] except (ResourceNotFoundError) as err: msg = 'Unable to load file contents at path {0}: {1} '.format( filepath, err) # add more info and re-raise raise Exception(msg), None, sys.exc_info()[2]
def load_definition(cls, xml_object, system, location, id_generator): '''Load a descriptor from the specified xml_object: If there is a filename attribute, load it as a string, and log a warning if it is not parseable by etree.HTMLParser. If there is not a filename attribute, the definition is the body of the xml_object, without the root tag (do not want <html> in the middle of a page) Args: xml_object: an lxml.etree._Element containing the definition to load system: the modulestore system or runtime which caches data location: the usage id for the block--used to compute the filename if none in the xml_object id_generator: used by other impls of this method to generate the usage_id ''' filename = xml_object.get('filename') if filename is None: definition_xml = copy.deepcopy(xml_object) cls.clean_metadata_from_xml(definition_xml) return {'data': stringify_children(definition_xml)}, [] else: # html is special. cls.filename_extension is 'xml', but # if 'filename' is in the definition, that means to load # from .html # 'filename' in html pointers is a relative path # (not same as 'html/blah.html' when the pointer is in a directory itself) pointer_path = "{category}/{url_path}".format( category='html', url_path=name_to_pathname(location.name) ) base = path(pointer_path).dirname() # log.debug("base = {0}, base.dirname={1}, filename={2}".format(base, base.dirname(), filename)) filepath = "{base}/{name}.html".format(base=base, name=filename) # log.debug("looking for html file for {0} at {1}".format(location, filepath)) # VS[compat] # TODO (cpennington): If the file doesn't exist at the right path, # give the class a chance to fix it up. The file will be written out # again in the correct format. This should go away once the CMS is # online and has imported all current (fall 2012) courses from xml if not system.resources_fs.exists(filepath): candidates = cls.backcompat_paths(filepath) # log.debug("candidates = {0}".format(candidates)) for candidate in candidates: if system.resources_fs.exists(candidate): filepath = candidate break try: with system.resources_fs.open(filepath) as file: html = file.read().decode('utf-8') # Log a warning if we can't parse the file, but don't error if not check_html(html) and len(html) > 0: msg = "Couldn't parse html in {0}, content = {1}".format(filepath, html) log.warning(msg) system.error_tracker("Warning: " + msg) definition = {'data': html} # TODO (ichuang): remove this after migration # for Fall 2012 LMS migration: keep filename (and unmangled filename) definition['filename'] = [filepath, filename] return definition, [] except (ResourceNotFoundError) as err: msg = 'Unable to load file contents at path {0}: {1} '.format( filepath, err) # add more info and re-raise raise Exception(msg), None, sys.exc_info()[2]