feat: add support for xblock 2
This commit is contained in:
1
.github/workflows/unit-tests.yml
vendored
1
.github/workflows/unit-tests.yml
vendored
@@ -12,6 +12,7 @@ jobs:
|
||||
if: (github.repository == 'edx/edx-platform-private') || (github.repository == 'openedx/edx-platform' && (startsWith(github.base_ref, 'open-release') == false))
|
||||
runs-on: [ edx-platform-runner ]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version:
|
||||
- "3.8"
|
||||
|
||||
@@ -344,7 +344,7 @@ def _import_xml_node_to_parent(
|
||||
|
||||
if not xblock_class.has_children:
|
||||
# No children to worry about. The XML may contain child nodes, but they're not XBlocks.
|
||||
temp_xblock = xblock_class.parse_xml(node, runtime, keys, id_generator)
|
||||
temp_xblock = xblock_class.parse_xml(node, runtime, keys)
|
||||
else:
|
||||
# We have to handle the children ourselves, because there are lots of complex interactions between
|
||||
# * the vanilla XBlock parse_xml() method, and its lack of API for "create and save a new XBlock"
|
||||
@@ -354,7 +354,7 @@ def _import_xml_node_to_parent(
|
||||
# serialization of a child block, in order. For blocks that don't support children, their XML content/nodes
|
||||
# could be anything (e.g. HTML, capa)
|
||||
node_without_children = etree.Element(node.tag, **node.attrib)
|
||||
temp_xblock = xblock_class.parse_xml(node_without_children, runtime, keys, id_generator)
|
||||
temp_xblock = xblock_class.parse_xml(node_without_children, runtime, keys)
|
||||
child_nodes = list(node)
|
||||
if xblock_class.has_children and temp_xblock.children:
|
||||
raise NotImplementedError("We don't yet support pasting XBlocks with children")
|
||||
|
||||
@@ -2027,7 +2027,8 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
|
||||
xml_object = etree.fromstring(xml_data)
|
||||
id_generator = Mock()
|
||||
id_generator.target_course_id = "test_course_id"
|
||||
video = self.block.parse_xml(xml_object, module_system, None, id_generator)
|
||||
module_system.id_generator = id_generator
|
||||
video = self.block.parse_xml(xml_object, module_system, None)
|
||||
|
||||
assert video.edx_video_id == 'test_edx_video_id'
|
||||
video_data = get_video_info(video.edx_video_id)
|
||||
@@ -2075,12 +2076,11 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
|
||||
xml_data = """<video><video_asset></video_asset></video>"""
|
||||
xml_object = etree.fromstring(xml_data)
|
||||
module_system = DummySystem(load_error_blocks=True)
|
||||
id_generator = Mock()
|
||||
|
||||
# Verify edx_video_id is empty before.
|
||||
assert self.block.edx_video_id == ''
|
||||
|
||||
video = self.block.parse_xml(xml_object, module_system, None, id_generator)
|
||||
video = self.block.parse_xml(xml_object, module_system, None)
|
||||
|
||||
# Verify edx_video_id is populated after the import.
|
||||
assert video.edx_video_id != ''
|
||||
@@ -2112,7 +2112,6 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
|
||||
)
|
||||
xml_object = etree.fromstring(xml_data)
|
||||
module_system = DummySystem(load_error_blocks=True)
|
||||
id_generator = Mock()
|
||||
|
||||
# Create static directory in import file system and place transcript files inside it.
|
||||
module_system.resources_fs.makedirs(EXPORT_IMPORT_STATIC_DIR, recreate=True)
|
||||
@@ -2128,7 +2127,7 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
|
||||
# Verify edx_video_id is empty before.
|
||||
assert self.block.edx_video_id == ''
|
||||
|
||||
video = self.block.parse_xml(xml_object, module_system, None, id_generator)
|
||||
video = self.block.parse_xml(xml_object, module_system, None)
|
||||
|
||||
# Verify edx_video_id is populated after the import.
|
||||
assert video.edx_video_id != ''
|
||||
@@ -2218,7 +2217,6 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
|
||||
language_code = 'en'
|
||||
|
||||
module_system = DummySystem(load_error_blocks=True)
|
||||
id_generator = Mock()
|
||||
|
||||
# Create static directory in import file system and place transcript files inside it.
|
||||
module_system.resources_fs.makedirs(EXPORT_IMPORT_STATIC_DIR, recreate=True)
|
||||
@@ -2270,7 +2268,7 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
|
||||
# Verify edx_video_id is empty before import.
|
||||
assert self.block.edx_video_id == ''
|
||||
|
||||
video = self.block.parse_xml(xml_object, module_system, None, id_generator)
|
||||
video = self.block.parse_xml(xml_object, module_system, None)
|
||||
|
||||
# Verify edx_video_id is not empty after import.
|
||||
assert video.edx_video_id != ''
|
||||
@@ -2298,7 +2296,7 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
|
||||
"""
|
||||
xml_object = etree.fromstring(xml_data)
|
||||
with pytest.raises(ValCannotCreateError):
|
||||
VideoBlock.parse_xml(xml_object, module_system, None, id_generator=Mock())
|
||||
VideoBlock.parse_xml(xml_object, module_system, None)
|
||||
with pytest.raises(ValVideoNotFoundError):
|
||||
get_video_info("test_edx_video_id")
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ class LearningCoreXBlockRuntime(XBlockRuntime):
|
||||
# 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)
|
||||
block = block_class.parse_xml(xml_node, runtime=self, keys=keys)
|
||||
|
||||
# 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
|
||||
|
||||
@@ -217,11 +217,11 @@ class XBlockRuntime(RuntimeShim, Runtime):
|
||||
""" Disable XBlock asides in this runtime """
|
||||
return []
|
||||
|
||||
def parse_xml_file(self, fileobj, id_generator=None):
|
||||
def parse_xml_file(self, fileobj):
|
||||
# Deny access to the inherited method
|
||||
raise NotImplementedError("XML Serialization is only supported with BlockstoreXBlockRuntime")
|
||||
|
||||
def add_node_as_child(self, block, node, id_generator=None):
|
||||
def add_node_as_child(self, block, node):
|
||||
"""
|
||||
Called by XBlock.parse_xml to treat a child node as a child block.
|
||||
"""
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#
|
||||
-e git+https://github.com/anupdhabarde/edx-proctoring-proctortrack.git@31c6c9923a51c903ae83760ecbbac191363aa2a2#egg=edx_proctoring_proctortrack
|
||||
# via -r requirements/edx/github.in
|
||||
acid-xblock==0.2.1
|
||||
acid-xblock==0.3.0
|
||||
# via -r requirements/edx/kernel.in
|
||||
aiohttp==3.9.3
|
||||
# via
|
||||
@@ -528,7 +528,7 @@ edx-rest-api-client==5.6.1
|
||||
# edx-proctoring
|
||||
edx-search==3.8.2
|
||||
# via -r requirements/edx/kernel.in
|
||||
edx-sga==0.23.1
|
||||
edx-sga==0.24.1
|
||||
# via -r requirements/edx/bundled.in
|
||||
edx-submissions==3.6.0
|
||||
# via
|
||||
@@ -804,7 +804,7 @@ optimizely-sdk==4.1.1
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/bundled.in
|
||||
ora2==6.5.1
|
||||
ora2==6.6.1
|
||||
# via -r requirements/edx/bundled.in
|
||||
packaging==23.2
|
||||
# via
|
||||
@@ -1222,7 +1222,7 @@ webob==1.8.7
|
||||
# xblock
|
||||
wrapt==1.16.0
|
||||
# via -r requirements/edx/paver.txt
|
||||
xblock[django]==1.10.0
|
||||
xblock[django]==2.0.0
|
||||
# via
|
||||
# -r requirements/edx/kernel.in
|
||||
# acid-xblock
|
||||
|
||||
@@ -12,7 +12,7 @@ accessible-pygments==0.0.4
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# pydata-sphinx-theme
|
||||
acid-xblock==0.2.1
|
||||
acid-xblock==0.3.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -825,7 +825,7 @@ edx-search==3.8.2
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
edx-sga==0.23.1
|
||||
edx-sga==0.24.1
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -1333,7 +1333,7 @@ optimizely-sdk==4.1.1
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
ora2==6.5.1
|
||||
ora2==6.6.1
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
@@ -2185,7 +2185,7 @@ wrapt==1.16.0
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
# astroid
|
||||
xblock[django]==1.10.0
|
||||
xblock[django]==2.0.0
|
||||
# via
|
||||
# -r requirements/edx/doc.txt
|
||||
# -r requirements/edx/testing.txt
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
# via -r requirements/edx/base.txt
|
||||
accessible-pygments==0.0.4
|
||||
# via pydata-sphinx-theme
|
||||
acid-xblock==0.2.1
|
||||
acid-xblock==0.3.0
|
||||
# via -r requirements/edx/base.txt
|
||||
aiohttp==3.9.3
|
||||
# via
|
||||
@@ -607,7 +607,7 @@ edx-rest-api-client==5.6.1
|
||||
# edx-proctoring
|
||||
edx-search==3.8.2
|
||||
# via -r requirements/edx/base.txt
|
||||
edx-sga==0.23.1
|
||||
edx-sga==0.24.1
|
||||
# via -r requirements/edx/base.txt
|
||||
edx-submissions==3.6.0
|
||||
# via
|
||||
@@ -942,7 +942,7 @@ optimizely-sdk==4.1.1
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
ora2==6.5.1
|
||||
ora2==6.6.1
|
||||
# via -r requirements/edx/base.txt
|
||||
packaging==23.2
|
||||
# via
|
||||
@@ -1488,7 +1488,7 @@ webob==1.8.7
|
||||
# xblock
|
||||
wrapt==1.16.0
|
||||
# via -r requirements/edx/base.txt
|
||||
xblock[django]==1.10.0
|
||||
xblock[django]==2.0.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# acid-xblock
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#
|
||||
-e git+https://github.com/anupdhabarde/edx-proctoring-proctortrack.git@31c6c9923a51c903ae83760ecbbac191363aa2a2#egg=edx_proctoring_proctortrack
|
||||
# via -r requirements/edx/base.txt
|
||||
acid-xblock==0.2.1
|
||||
acid-xblock==0.3.0
|
||||
# via -r requirements/edx/base.txt
|
||||
aiohttp==3.9.3
|
||||
# via
|
||||
@@ -633,7 +633,7 @@ edx-rest-api-client==5.6.1
|
||||
# edx-proctoring
|
||||
edx-search==3.8.2
|
||||
# via -r requirements/edx/base.txt
|
||||
edx-sga==0.23.1
|
||||
edx-sga==0.24.1
|
||||
# via -r requirements/edx/base.txt
|
||||
edx-submissions==3.6.0
|
||||
# via
|
||||
@@ -997,7 +997,7 @@ optimizely-sdk==4.1.1
|
||||
# via
|
||||
# -c requirements/edx/../constraints.txt
|
||||
# -r requirements/edx/base.txt
|
||||
ora2==6.5.1
|
||||
ora2==6.6.1
|
||||
# via -r requirements/edx/base.txt
|
||||
packaging==23.2
|
||||
# via
|
||||
@@ -1604,7 +1604,7 @@ wrapt==1.16.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# astroid
|
||||
xblock[django]==1.10.0
|
||||
xblock[django]==2.0.0
|
||||
# via
|
||||
# -r requirements/edx/base.txt
|
||||
# acid-xblock
|
||||
|
||||
@@ -1166,8 +1166,8 @@ class CourseBlock(
|
||||
return policy_str
|
||||
|
||||
@classmethod
|
||||
def parse_xml(cls, node, runtime, keys, id_generator):
|
||||
instance = super().parse_xml(node, runtime, keys, id_generator)
|
||||
def parse_xml(cls, node, runtime, keys):
|
||||
instance = super().parse_xml(node, runtime, keys)
|
||||
|
||||
policy_dir = None
|
||||
url_name = node.get('url_name')
|
||||
|
||||
@@ -233,7 +233,7 @@ class DiscussionXBlock(XBlock, StudioEditableXBlockMixin, XmlMixin): # lint-amn
|
||||
return {'topic_id': self.discussion_id}
|
||||
|
||||
@classmethod
|
||||
def parse_xml(cls, node, runtime, keys, id_generator):
|
||||
def parse_xml(cls, node, runtime, keys):
|
||||
"""
|
||||
Parses OLX into XBlock.
|
||||
|
||||
@@ -246,7 +246,7 @@ class DiscussionXBlock(XBlock, StudioEditableXBlockMixin, XmlMixin): # lint-amn
|
||||
XBlock.parse_xml. Otherwise this method parses file in "discussion" folder (known as definition_xml), applies
|
||||
policy.json and updates fields accordingly.
|
||||
"""
|
||||
block = super().parse_xml(node, runtime, keys, id_generator)
|
||||
block = super().parse_xml(node, runtime, keys)
|
||||
|
||||
cls._apply_metadata_and_policy(block, node, runtime)
|
||||
|
||||
|
||||
@@ -178,13 +178,13 @@ class ErrorBlock(
|
||||
return cls._construct(system, xml_data, error_msg, location=id_generator.create_definition('error'))
|
||||
|
||||
@classmethod
|
||||
def parse_xml(cls, node, runtime, keys, id_generator): # lint-amnesty, pylint: disable=unused-argument
|
||||
def parse_xml(cls, node, runtime, keys): # lint-amnesty, pylint: disable=unused-argument
|
||||
"""
|
||||
Interpret the parsed XML in `node`, creating an XModuleDescriptor.
|
||||
"""
|
||||
# It'd be great to not reserialize and deserialize the xml
|
||||
xml = etree.tostring(node).decode('utf-8')
|
||||
block = cls.from_xml(xml, runtime, id_generator)
|
||||
block = cls.from_xml(xml, runtime, runtime.id_generator)
|
||||
return block
|
||||
|
||||
def export_to_xml(self, resource_fs):
|
||||
|
||||
@@ -259,7 +259,7 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem): # lint-amnesty, pyl
|
||||
|
||||
# id_generator is ignored, because each ImportSystem is already local to
|
||||
# a course, and has it's own id_generator already in place
|
||||
def add_node_as_child(self, block, node, id_generator): # lint-amnesty, pylint: disable=signature-differs
|
||||
def add_node_as_child(self, block, node): # lint-amnesty, pylint: disable=signature-differs
|
||||
child_block = self.process_xml(etree.tostring(node))
|
||||
block.children.append(child_block.scope_ids.usage_id)
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ class RawMixin:
|
||||
try:
|
||||
block = super().parse_xml_new_runtime(node, runtime, keys)
|
||||
except AttributeError:
|
||||
block = super().parse_xml(node, runtime, keys, id_generator=None)
|
||||
block = super().parse_xml(node, runtime, keys)
|
||||
block.data = data_field_value
|
||||
return block
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ class TranslateCustomTagBlock( # pylint: disable=abstract-method
|
||||
resources_dir = None
|
||||
|
||||
@classmethod
|
||||
def parse_xml(cls, node, runtime, _keys, _id_generator):
|
||||
def parse_xml(cls, node, runtime, _keys):
|
||||
"""
|
||||
Transforms the xml_data from <$custom_tag attr="" attr=""/> to
|
||||
<customtag attr="" attr="" impl="$custom_tag"/>
|
||||
|
||||
@@ -69,7 +69,7 @@ class DiscussionXBlockImportExportTests(TestCase):
|
||||
self.runtime_mock = mock.Mock(spec=Runtime)
|
||||
self.runtime_mock.construct_xblock_from_class = mock.Mock(side_effect=self._construct_xblock_mock)
|
||||
self.runtime_mock.get_policy = mock.Mock(return_value={})
|
||||
self.id_gen_mock = mock.Mock()
|
||||
self.id_generator = mock.Mock()
|
||||
|
||||
def _construct_xblock_mock(self, cls, keys): # pylint: disable=unused-argument
|
||||
"""
|
||||
@@ -102,7 +102,7 @@ class DiscussionXBlockImportExportTests(TestCase):
|
||||
|
||||
patched_load_definition_xml.side_effect = Exception("Irrelevant")
|
||||
|
||||
block = DiscussionXBlock.parse_xml(node, self.runtime_mock, self.keys, self.id_gen_mock)
|
||||
block = DiscussionXBlock.parse_xml(node, self.runtime_mock, self.keys)
|
||||
try:
|
||||
assert block.discussion_id == id_pair.value
|
||||
assert block.discussion_category == category_pair.value
|
||||
@@ -134,7 +134,7 @@ class DiscussionXBlockImportExportTests(TestCase):
|
||||
|
||||
patched_load_definition_xml.return_value = (definition_node, "irrelevant")
|
||||
|
||||
block = DiscussionXBlock.parse_xml(node, self.runtime_mock, self.keys, self.id_gen_mock)
|
||||
block = DiscussionXBlock.parse_xml(node, self.runtime_mock, self.keys)
|
||||
try:
|
||||
assert block.discussion_id == id_pair.value
|
||||
assert block.discussion_category == category_pair.value
|
||||
|
||||
@@ -195,7 +195,7 @@ class TestLibraryContentExportImport(LibraryContentTest):
|
||||
|
||||
# Now import it.
|
||||
olx_element = etree.fromstring(exported_olx)
|
||||
imported_lc_block = LibraryContentBlock.parse_xml(olx_element, self.runtime, None, self.id_generator)
|
||||
imported_lc_block = LibraryContentBlock.parse_xml(olx_element, self.runtime, None)
|
||||
|
||||
self._verify_xblock_properties(imported_lc_block)
|
||||
|
||||
@@ -219,7 +219,7 @@ class TestLibraryContentExportImport(LibraryContentTest):
|
||||
|
||||
# Import the olx.
|
||||
olx_element = etree.fromstring(olx_with_comments)
|
||||
imported_lc_block = LibraryContentBlock.parse_xml(olx_element, self.runtime, None, self.id_generator)
|
||||
imported_lc_block = LibraryContentBlock.parse_xml(olx_element, self.runtime, None)
|
||||
|
||||
self._verify_xblock_properties(imported_lc_block)
|
||||
|
||||
|
||||
@@ -72,7 +72,8 @@ class PollBlockTest(unittest.TestCase):
|
||||
'''
|
||||
node = etree.fromstring(sample_poll_xml)
|
||||
|
||||
output = PollBlock.parse_xml(node, module_system, self.scope_ids, id_generator)
|
||||
module_system.id_generator = id_generator
|
||||
output = PollBlock.parse_xml(node, module_system, self.scope_ids)
|
||||
# Update the answer with invalid character.
|
||||
invalid_characters_poll_answer = output.answers[0]
|
||||
# Invalid less-than character.
|
||||
|
||||
@@ -83,8 +83,7 @@ class RandomizeBlockTest(MixedSplitTestCase):
|
||||
|
||||
# Now import it.
|
||||
olx_element = etree.fromstring(exported_olx)
|
||||
id_generator = Mock()
|
||||
imported_randomize_block = RandomizeBlock.parse_xml(olx_element, runtime, None, id_generator)
|
||||
imported_randomize_block = RandomizeBlock.parse_xml(olx_element, runtime, None)
|
||||
|
||||
# Check the new XBlock has the same properties as the old one.
|
||||
assert imported_randomize_block.display_name == randomize_block.display_name
|
||||
|
||||
@@ -586,8 +586,7 @@ class SplitTestBlockExportImportTest(MixedSplitTestCase):
|
||||
|
||||
# Now import it.
|
||||
olx_element = lxml.etree.fromstring(exported_olx)
|
||||
id_generator = Mock()
|
||||
imported_split_test_block = SplitTestBlock.parse_xml(olx_element, runtime, None, id_generator)
|
||||
imported_split_test_block = SplitTestBlock.parse_xml(olx_element, runtime, None)
|
||||
|
||||
# Check the new XBlock has the same properties as the old one.
|
||||
assert imported_split_test_block.display_name == split_test_block.display_name
|
||||
|
||||
@@ -298,7 +298,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
</video>
|
||||
'''
|
||||
xml_object = etree.fromstring(xml_data)
|
||||
output = VideoBlock.parse_xml(xml_object, module_system, None, Mock())
|
||||
output = VideoBlock.parse_xml(xml_object, module_system, None)
|
||||
self.assert_attributes_equal(output, {
|
||||
'youtube_id_0_75': 'izygArpw-Qo',
|
||||
'youtube_id_1_0': 'p2Q6BrNhdh8',
|
||||
@@ -347,7 +347,8 @@ class VideoBlockImportTestCase(TestCase):
|
||||
id_generator = Mock()
|
||||
id_generator.target_course_id = course_id
|
||||
|
||||
output = VideoBlock.parse_xml(xml_object, module_system, None, id_generator)
|
||||
module_system.id_generator = id_generator
|
||||
output = VideoBlock.parse_xml(xml_object, module_system, None)
|
||||
self.assert_attributes_equal(output, {
|
||||
'youtube_id_0_75': 'izygArpw-Qo',
|
||||
'youtube_id_1_0': 'p2Q6BrNhdh8',
|
||||
@@ -379,7 +380,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
</video>
|
||||
'''
|
||||
xml_object = etree.fromstring(xml_data)
|
||||
output = VideoBlock.parse_xml(xml_object, module_system, None, Mock())
|
||||
output = VideoBlock.parse_xml(xml_object, module_system, None)
|
||||
self.assert_attributes_equal(output, {
|
||||
'youtube_id_0_75': '',
|
||||
'youtube_id_1_0': 'p2Q6BrNhdh8',
|
||||
@@ -411,7 +412,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
</video>
|
||||
'''
|
||||
xml_object = etree.fromstring(xml_data)
|
||||
output = VideoBlock.parse_xml(xml_object, module_system, None, Mock())
|
||||
output = VideoBlock.parse_xml(xml_object, module_system, None)
|
||||
self.assert_attributes_equal(output, {
|
||||
'youtube_id_0_75': '',
|
||||
'youtube_id_1_0': 'p2Q6BrNhdh8',
|
||||
@@ -435,7 +436,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
module_system = DummySystem(load_error_blocks=True)
|
||||
xml_data = '<video></video>'
|
||||
xml_object = etree.fromstring(xml_data)
|
||||
output = VideoBlock.parse_xml(xml_object, module_system, None, Mock())
|
||||
output = VideoBlock.parse_xml(xml_object, module_system, None)
|
||||
self.assert_attributes_equal(output, {
|
||||
'youtube_id_0_75': '',
|
||||
'youtube_id_1_0': '3_yD_cEKoCk',
|
||||
@@ -475,7 +476,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
/>
|
||||
'''
|
||||
xml_object = etree.fromstring(xml_data)
|
||||
output = VideoBlock.parse_xml(xml_object, module_system, None, Mock())
|
||||
output = VideoBlock.parse_xml(xml_object, module_system, None)
|
||||
self.assert_attributes_equal(output, {
|
||||
'youtube_id_0_75': 'OEoXaMPEzf65',
|
||||
'youtube_id_1_0': 'OEoXaMPEzf10',
|
||||
@@ -500,7 +501,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
</video>
|
||||
'''
|
||||
xml_object = etree.fromstring(xml_data)
|
||||
output = VideoBlock.parse_xml(xml_object, module_system, None, Mock())
|
||||
output = VideoBlock.parse_xml(xml_object, module_system, None)
|
||||
self.assert_attributes_equal(output, {
|
||||
'youtube_id_0_75': '',
|
||||
'youtube_id_1_0': 'p2Q6BrNhdh8',
|
||||
@@ -534,7 +535,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
</video>
|
||||
"""
|
||||
xml_object = etree.fromstring(xml_data)
|
||||
output = VideoBlock.parse_xml(xml_object, module_system, None, Mock())
|
||||
output = VideoBlock.parse_xml(xml_object, module_system, None)
|
||||
self.assert_attributes_equal(output, {
|
||||
'youtube_id_0_75': 'izygArpw-Qo',
|
||||
'youtube_id_1_0': 'p2Q6BrNhdh8',
|
||||
@@ -565,7 +566,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
</video>
|
||||
"""
|
||||
xml_object = etree.fromstring(xml_data)
|
||||
video = VideoBlock.parse_xml(xml_object, module_system, None, Mock())
|
||||
video = VideoBlock.parse_xml(xml_object, module_system, None)
|
||||
self.assert_attributes_equal(video, {
|
||||
'youtube_id_0_75': 'izygArpw-Qo',
|
||||
'youtube_id_1_0': 'p2Q6BrNhdh8',
|
||||
@@ -596,7 +597,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
</video>
|
||||
"""
|
||||
xml_object = etree.fromstring(xml_data)
|
||||
video = VideoBlock.parse_xml(xml_object, module_system, None, Mock())
|
||||
video = VideoBlock.parse_xml(xml_object, module_system, None)
|
||||
self.assert_attributes_equal(video, {
|
||||
'youtube_id_0_75': 'izygArpw-Qo',
|
||||
'youtube_id_1_0': 'p2Q6BrNhdh8',
|
||||
@@ -645,7 +646,8 @@ class VideoBlockImportTestCase(TestCase):
|
||||
xml_object = etree.fromstring(xml_data)
|
||||
id_generator = Mock()
|
||||
id_generator.target_course_id = 'test_course_id'
|
||||
video = VideoBlock.parse_xml(xml_object, module_system, None, id_generator)
|
||||
module_system.id_generator = id_generator
|
||||
video = VideoBlock.parse_xml(xml_object, module_system, None)
|
||||
|
||||
self.assert_attributes_equal(video, {'edx_video_id': edx_video_id})
|
||||
mock_val_api.import_from_xml.assert_called_once_with(
|
||||
@@ -671,7 +673,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
"""
|
||||
xml_object = etree.fromstring(xml_data)
|
||||
with pytest.raises(mock_val_api.ValCannotCreateError):
|
||||
VideoBlock.parse_xml(xml_object, module_system, None, Mock())
|
||||
VideoBlock.parse_xml(xml_object, module_system, None)
|
||||
|
||||
|
||||
class VideoExportTestCase(VideoBlockTestBase):
|
||||
|
||||
@@ -41,8 +41,8 @@ class WordCloudBlockTest(TestCase):
|
||||
)
|
||||
|
||||
olx_element = etree.fromstring(original_xml)
|
||||
id_generator = Mock()
|
||||
block = WordCloudBlock.parse_xml(olx_element, runtime, None, id_generator)
|
||||
runtime.id_generator = Mock()
|
||||
block = WordCloudBlock.parse_xml(olx_element, runtime, None)
|
||||
block.location = BlockUsageLocator(
|
||||
CourseLocator('org', 'course', 'run', branch='revision'), 'word_cloud', 'block_id'
|
||||
)
|
||||
|
||||
@@ -40,6 +40,7 @@ class InMemorySystem(XMLParsingSystem, MakoDescriptorSystem): # pylint: disable
|
||||
render_template=lambda template, context: pprint.pformat((template, context)),
|
||||
services={'field-data': KvsFieldData(DictKeyValueStore())},
|
||||
)
|
||||
self.id_generator = Mock()
|
||||
|
||||
def process_xml(self, xml): # pylint: disable=method-hidden
|
||||
"""Parse `xml` as an XBlock, and add it to `self._blocks`"""
|
||||
|
||||
@@ -727,7 +727,7 @@ class VideoBlock(
|
||||
return video_block
|
||||
|
||||
@classmethod
|
||||
def parse_xml(cls, node, runtime, _keys, id_generator):
|
||||
def parse_xml(cls, node, runtime, _keys):
|
||||
"""
|
||||
Use `node` to construct a new block.
|
||||
|
||||
@@ -735,13 +735,13 @@ class VideoBlock(
|
||||
"""
|
||||
url_name = node.get('url_name')
|
||||
block_type = 'video'
|
||||
definition_id = id_generator.create_definition(block_type, url_name)
|
||||
usage_id = id_generator.create_usage(definition_id)
|
||||
definition_id = runtime.id_generator.create_definition(block_type, url_name)
|
||||
usage_id = runtime.id_generator.create_usage(definition_id)
|
||||
if is_pointer_tag(node):
|
||||
filepath = cls._format_filepath(node.tag, name_to_pathname(url_name))
|
||||
node = cls.load_file(filepath, runtime.resources_fs, usage_id)
|
||||
runtime.parse_asides(node, definition_id, usage_id, id_generator)
|
||||
field_data = cls.parse_video_xml(node, id_generator)
|
||||
runtime.parse_asides(node, definition_id, usage_id, runtime.id_generator)
|
||||
field_data = cls.parse_video_xml(node, runtime.id_generator)
|
||||
kvs = InheritanceKeyValueStore(initial_values=field_data)
|
||||
field_data = KvsFieldData(kvs)
|
||||
video = runtime.construct_xblock_from_class(
|
||||
@@ -757,7 +757,7 @@ class VideoBlock(
|
||||
video.edx_video_id = video.import_video_info_into_val(
|
||||
node,
|
||||
runtime.resources_fs,
|
||||
getattr(id_generator, 'target_course_id', None)
|
||||
getattr(runtime.id_generator, 'target_course_id', None)
|
||||
)
|
||||
|
||||
return video
|
||||
|
||||
@@ -1529,18 +1529,16 @@ class XMLParsingSystem(DescriptorSystem): # lint-amnesty, pylint: disable=abstr
|
||||
super().__init__(**kwargs)
|
||||
self.process_xml = process_xml
|
||||
|
||||
def _usage_id_from_node(self, node, parent_id, id_generator=None):
|
||||
def _usage_id_from_node(self, node, parent_id):
|
||||
"""Create a new usage id from an XML dom node.
|
||||
|
||||
Args:
|
||||
node (lxml.etree.Element): The DOM node to interpret.
|
||||
parent_id: The usage ID of the parent block
|
||||
id_generator (IdGenerator): The :class:`.IdGenerator` to use
|
||||
for creating ids
|
||||
Returns:
|
||||
UsageKey: the usage key for the new xblock
|
||||
"""
|
||||
return self.xblock_from_node(node, parent_id, id_generator).scope_ids.usage_id
|
||||
return self.xblock_from_node(node, parent_id, self.id_generator).scope_ids.usage_id
|
||||
|
||||
def xblock_from_node(self, node, parent_id, id_generator=None):
|
||||
"""
|
||||
@@ -1575,7 +1573,7 @@ class XMLParsingSystem(DescriptorSystem): # lint-amnesty, pylint: disable=abstr
|
||||
aside_children = self.parse_asides(node, def_id, usage_id, id_generator)
|
||||
asides_tags = [x.tag for x in aside_children]
|
||||
|
||||
block = block_class.parse_xml(node, self, keys, id_generator)
|
||||
block = block_class.parse_xml(node, self, keys)
|
||||
self._convert_reference_fields_to_keys(block) # difference from XBlock.runtime
|
||||
block.parent = parent_id
|
||||
block.save()
|
||||
@@ -1599,7 +1597,7 @@ class XMLParsingSystem(DescriptorSystem): # lint-amnesty, pylint: disable=abstr
|
||||
aside_children.append(child)
|
||||
# now process them & remove them from the xml payload
|
||||
for child in aside_children:
|
||||
self._aside_from_xml(child, def_id, usage_id, id_generator)
|
||||
self._aside_from_xml(child, def_id, usage_id)
|
||||
node.remove(child)
|
||||
return aside_children
|
||||
|
||||
|
||||
@@ -285,7 +285,7 @@ class XmlMixin:
|
||||
metadata[attr] = value
|
||||
|
||||
@classmethod
|
||||
def parse_xml(cls, node, runtime, keys, id_generator): # pylint: disable=too-many-statements
|
||||
def parse_xml(cls, node, runtime, keys): # pylint: disable=too-many-statements
|
||||
"""
|
||||
Use `node` to construct a new block.
|
||||
|
||||
@@ -297,20 +297,15 @@ class XmlMixin:
|
||||
keys (:class:`.ScopeIds`): The keys identifying where this block
|
||||
will store its data.
|
||||
|
||||
id_generator (:class:`.IdGenerator`): An object that will allow the
|
||||
runtime to generate correct definition and usage ids for
|
||||
children of this block.
|
||||
|
||||
Returns (XBlock): The newly parsed XBlock
|
||||
|
||||
"""
|
||||
from xmodule.modulestore.xml import ImportSystem # done here to avoid circular import
|
||||
if id_generator is None:
|
||||
id_generator = runtime.id_generator
|
||||
|
||||
if keys is None:
|
||||
# Passing keys=None is against the XBlock API but some platform tests do it.
|
||||
def_id = id_generator.create_definition(node.tag, node.get('url_name'))
|
||||
keys = ScopeIds(None, node.tag, def_id, id_generator.create_usage(def_id))
|
||||
def_id = runtime.id_generator.create_definition(node.tag, node.get('url_name'))
|
||||
keys = ScopeIds(None, node.tag, def_id, runtime.id_generator.create_usage(def_id))
|
||||
aside_children = []
|
||||
|
||||
# VS[compat]
|
||||
@@ -324,13 +319,13 @@ class XmlMixin:
|
||||
# new style:
|
||||
# read the actual definition file--named using url_name.replace(':','/')
|
||||
definition_xml, filepath = cls.load_definition_xml(node, runtime, keys.def_id)
|
||||
aside_children = runtime.parse_asides(definition_xml, keys.def_id, keys.usage_id, id_generator)
|
||||
aside_children = runtime.parse_asides(definition_xml, keys.def_id, keys.usage_id, runtime.id_generator)
|
||||
else:
|
||||
filepath = None
|
||||
definition_xml = node
|
||||
|
||||
# Note: removes metadata.
|
||||
definition, children = cls.load_definition(definition_xml, runtime, keys.def_id, id_generator)
|
||||
definition, children = cls.load_definition(definition_xml, runtime, keys.def_id, runtime.id_generator)
|
||||
|
||||
# VS[compat]
|
||||
# Make Ike's github preview links work in both old and new file layouts.
|
||||
@@ -399,7 +394,7 @@ class XmlMixin:
|
||||
try:
|
||||
return super().parse_xml_new_runtime(node, runtime, keys)
|
||||
except AttributeError:
|
||||
return super().parse_xml(node, runtime, keys, id_generator=None)
|
||||
return super().parse_xml(node, runtime, keys)
|
||||
|
||||
@classmethod
|
||||
def load_definition_xml(cls, node, runtime, def_id):
|
||||
|
||||
Reference in New Issue
Block a user