def get_block(self, usage_id, for_parent=None): """ Create an XBlock instance in this runtime. The `usage_id` is used to find the XBlock class and data. """ def_id = self.id_reader.get_definition_id(usage_id) if def_id is None: raise ValueError( "Definition not found for usage {}".format(usage_id)) if not isinstance(def_id, BundleDefinitionLocator): raise TypeError( "This runtime can only load blocks stored in Blockstore bundles." ) try: block_type = self.id_reader.get_block_type(def_id) except NoSuchDefinition: raise NoSuchUsage(repr(usage_id)) keys = ScopeIds(self.user_id, block_type, def_id, usage_id) if self.system.authored_data_store.has_cached_definition(def_id): return self.construct_xblock(block_type, keys, for_parent=for_parent) else: # We need to load this block's field data from its OLX file in blockstore: xml_node = xml_for_definition(def_id) if xml_node.get("url_name", None): log.warning( "XBlock at %s should not specify an old-style url_name attribute.", def_id.olx_path) block_class = self.mixologist.mix(self.load_block_type(block_type)) if hasattr(block_class, 'parse_xml_new_runtime'): # This is a (former) XModule with messy XML parsing code; let its parse_xml() method continue to work # as it currently does in the old runtime, but let this parse_xml_new_runtime() method parse the XML in # a simpler way that's free of tech debt, if defined. # In particular, XmlParserMixin doesn't play well with this new runtime, so this is mostly about # bypassing that mixin's code. # When a former XModule no longer needs to support the old runtime, its parse_xml_new_runtime method # should be removed and its parse_xml() method should be simplified to just call the super().parse_xml() # plus some minor additional lines of code as needed. block = block_class.parse_xml_new_runtime(xml_node, runtime=self, keys=keys) else: block = block_class.parse_xml(xml_node, runtime=self, keys=keys, id_generator=None) # Update field data with parsed values. We can't call .save() because it will call save_block(), below. block.force_save_fields(block._get_fields_to_save()) # pylint: disable=protected-access self.system.authored_data_store.cache_fields(block) # There is no way to set the parent via parse_xml, so do what # HierarchyMixin would do: if for_parent is not None: block._parent_block = for_parent # pylint: disable=protected-access block._parent_block_id = for_parent.scope_ids.usage_id # pylint: disable=protected-access return block
def get_usage_id_from_aside(self, aside_id): """ Extract the usage_id from the aside_id. Arguments: aside_id: An XBlockAside usage_id """ try: return self._aside_usages[aside_id][0] except KeyError: raise NoSuchUsage(usage_id)
def get_aside_type_from_usage(self, usage_id): """ Parse the type of the aside from an XBlockAside usage_id. Arguments: usage_id: An XBlockAside usage_id. """ try: return self._aside_usages[usage_id][1] except KeyError: raise NoSuchUsage(usage_id)
def get_block(self, usage_id, for_parent=None): """ Create an XBlock instance in this runtime. The `usage_id` is used to find the XBlock class and data. """ def_id = self.id_reader.get_definition_id(usage_id) try: block_type = self.id_reader.get_block_type(def_id) except NoSuchDefinition: raise NoSuchUsage(repr(usage_id)) keys = ScopeIds(self.user_id, block_type, def_id, usage_id) block = self.construct_xblock(block_type, keys, for_parent=for_parent) return block
def get_definition_id(self, usage_id): """Get a definition_id by its usage id.""" try: return self._usages[usage_id] except KeyError: raise NoSuchUsage(repr(usage_id))