Merge branch 'master' into issue-35271-unpin-markdown

This commit is contained in:
Ram Chandra Bhavirisetty
2025-05-19 21:33:19 -06:00
committed by GitHub
26 changed files with 271 additions and 127 deletions

View File

@@ -64,7 +64,7 @@ def test_compile_xblock_translations(tmp_translations_dir):
'msgfmt', '--check-format', '-o', str(po_file.with_suffix('.mo')), str(po_file),
], 'Compiles the .po files'
js_file_text = get_javascript_i18n_file_path('done', 'tr').text()
js_file_text = get_javascript_i18n_file_path('done', 'tr').read_text()
assert 'Merhaba' in js_file_text, 'Ensures the JavaScript catalog is compiled'
assert 'TestingDoneXBlockI18n' in js_file_text, 'Ensures the namespace is used'
assert 'gettext' in js_file_text, 'Ensures the gettext function is defined'

View File

@@ -101,7 +101,7 @@ def compile_xblock_js_messages():
xblock_conf_locale_dir = xmodule_api.get_python_locale_root() / xblock_module
i18n_js_namespace = xblock_class.get_i18n_js_namespace()
for locale_dir in xblock_conf_locale_dir.listdir():
for locale_dir in xblock_conf_locale_dir.iterdir():
locale_code = str(locale_dir.basename())
locale_messages_dir = locale_dir / 'LC_MESSAGES'
js_translations_domain = None

View File

@@ -11,7 +11,7 @@ which communicate with edx-platform over AJAX, but are built and deployed
independently. Eventually, we expect that MFEs will replace all edx-platform
frontend pages, except perhaps XBlock views.*
Configuraiton
Configuration
*************
To customize the static assets build, set some or all of these variable in your

View File

@@ -52,6 +52,7 @@ from .documents import (
searchable_doc_for_key,
searchable_doc_tags,
searchable_doc_tags_for_collection,
searchable_doc_units,
)
log = logging.getLogger(__name__)
@@ -451,6 +452,7 @@ def rebuild_index(status_cb: Callable[[str], None] | None = None, incremental=Fa
doc.update(searchable_doc_for_library_block(metadata))
doc.update(searchable_doc_tags(metadata.usage_key))
doc.update(searchable_doc_collections(metadata.usage_key))
doc.update(searchable_doc_units(metadata.usage_key))
docs.append(doc)
except Exception as err: # pylint: disable=broad-except
status_cb(f"Error indexing library component {component}: {err}")
@@ -853,6 +855,15 @@ def upsert_item_collections_index_docs(opaque_key: OpaqueKey):
_update_index_docs([doc])
def upsert_item_units_index_docs(opaque_key: OpaqueKey):
"""
Updates the units data in documents for the given Course/Library block
"""
doc = {Fields.id: meili_id_from_opaque_key(opaque_key)}
doc.update(searchable_doc_units(opaque_key))
_update_index_docs([doc])
def upsert_collection_tags_index_docs(collection_key: LibraryCollectionLocator):
"""
Updates the tags data in documents for the given library collection

View File

@@ -67,6 +67,10 @@ class Fields:
collections = "collections"
collections_display_name = "display_name"
collections_key = "key"
# Units (dictionary) that this object belongs to.
units = "units"
units_display_name = "display_name"
units_key = "key"
# The "content" field is a dictionary of arbitrary data, depending on the block_type.
# It comes from each XBlock's index_dictionary() method (if present) plus some processing.
@@ -369,6 +373,54 @@ def _collections_for_content_object(object_id: OpaqueKey) -> dict:
return result
def _units_for_content_object(object_id: OpaqueKey) -> dict:
"""
Given an XBlock, course, library, etc., get the units for its index doc.
e.g. for something in Units "UNIT_A" and "UNIT_B", this would return:
{
"units": {
"display_name": ["Unit A", "Unit B"],
"key": ["UNIT_A", "UNIT_B"],
}
}
If the object is in no collections, returns:
{
"collections": {
"display_name": [],
"key": [],
},
}
"""
result = {
Fields.units: {
Fields.units_display_name: [],
Fields.units_key: [],
}
}
# Gather the units associated with this object
units = None
try:
if isinstance(object_id, UsageKey):
units = lib_api.get_containers_contains_component(object_id)
else:
log.warning(f"Unexpected key type for {object_id}")
except ObjectDoesNotExist:
log.warning(f"No library item found for {object_id}")
if not units:
return result
for unit in units:
result[Fields.units][Fields.units_display_name].append(unit.display_name)
result[Fields.units][Fields.units_key].append(str(unit.container_key))
return result
def _published_data_from_block(block_published) -> dict:
"""
Given an library block get the published data.
@@ -460,6 +512,17 @@ def searchable_doc_collections(opaque_key: OpaqueKey) -> dict:
return doc
def searchable_doc_units(opaque_key: OpaqueKey) -> dict:
"""
Generate a dictionary document suitable for ingestion into a search engine
like Meilisearch or Elasticsearch, with the units data for the given content object.
"""
doc = searchable_doc_for_key(opaque_key)
doc.update(_units_for_content_object(opaque_key))
return doc
def searchable_doc_tags_for_collection(
collection_key: LibraryCollectionLocator
) -> dict:

View File

@@ -46,6 +46,7 @@ from .api import (
upsert_content_object_tags_index_doc,
upsert_collection_tags_index_docs,
upsert_item_collections_index_docs,
upsert_item_units_index_docs,
)
from .tasks import (
delete_library_block_index_doc,
@@ -263,6 +264,8 @@ def content_object_associations_changed_handler(**kwargs) -> None:
upsert_content_object_tags_index_doc(opaque_key)
if not content_object.changes or "collections" in content_object.changes:
upsert_item_collections_index_docs(opaque_key)
if not content_object.changes or "units" in content_object.changes:
upsert_item_units_index_docs(opaque_key)
@receiver(LIBRARY_CONTAINER_CREATED)

View File

@@ -8,7 +8,7 @@ import copy
from datetime import datetime, timezone
from unittest.mock import MagicMock, Mock, call, patch
from opaque_keys.edx.keys import UsageKey
from opaque_keys.edx.locator import LibraryCollectionLocator
from opaque_keys.edx.locator import LibraryCollectionLocator, LibraryContainerLocator
import ddt
import pytest
@@ -134,8 +134,8 @@ class TestSearchApi(ModuleStoreTestCase):
lib_access, _ = SearchAccess.objects.get_or_create(context_key=self.library.key)
# Populate it with 2 problems, freezing the date so we can verify created date serializes correctly.
created_date = datetime(2023, 4, 5, 6, 7, 8, tzinfo=timezone.utc)
with freeze_time(created_date):
self.created_date = datetime(2023, 4, 5, 6, 7, 8, tzinfo=timezone.utc)
with freeze_time(self.created_date):
self.problem1 = library_api.create_library_block(self.library.key, "problem", "p1")
self.problem2 = library_api.create_library_block(self.library.key, "problem", "p2")
# Update problem1, freezing the date so we can verify modified date serializes correctly.
@@ -155,7 +155,7 @@ class TestSearchApi(ModuleStoreTestCase):
"type": "library_block",
"access_id": lib_access.id,
"last_published": None,
"created": created_date.timestamp(),
"created": self.created_date.timestamp(),
"modified": modified_date.timestamp(),
"publish_status": "never",
}
@@ -172,8 +172,8 @@ class TestSearchApi(ModuleStoreTestCase):
"type": "library_block",
"access_id": lib_access.id,
"last_published": None,
"created": created_date.timestamp(),
"modified": created_date.timestamp(),
"created": self.created_date.timestamp(),
"modified": self.created_date.timestamp(),
"publish_status": "never",
}
@@ -189,7 +189,7 @@ class TestSearchApi(ModuleStoreTestCase):
# Create a collection:
self.learning_package = authoring_api.get_learning_package_by_key(self.library.key)
with freeze_time(created_date):
with freeze_time(self.created_date):
self.collection = authoring_api.create_collection(
learning_package_id=self.learning_package.id,
key="MYCOL",
@@ -210,8 +210,8 @@ class TestSearchApi(ModuleStoreTestCase):
"num_children": 0,
"context_key": "lib:org1:lib",
"org": "org1",
"created": created_date.timestamp(),
"modified": created_date.timestamp(),
"created": self.created_date.timestamp(),
"modified": self.created_date.timestamp(),
"access_id": lib_access.id,
"published": {
"num_children": 0
@@ -220,7 +220,7 @@ class TestSearchApi(ModuleStoreTestCase):
}
# Create a unit:
with freeze_time(created_date):
with freeze_time(self.created_date):
self.unit = library_api.create_container(
library_key=self.library.key,
container_type=library_api.ContainerType.Unit,
@@ -242,8 +242,8 @@ class TestSearchApi(ModuleStoreTestCase):
"publish_status": "never",
"context_key": "lib:org1:lib",
"org": "org1",
"created": created_date.timestamp(),
"modified": created_date.timestamp(),
"created": self.created_date.timestamp(),
"modified": self.created_date.timestamp(),
"last_published": None,
"access_id": lib_access.id,
"breadcrumbs": [{"display_name": "Library"}],
@@ -268,9 +268,11 @@ class TestSearchApi(ModuleStoreTestCase):
doc_problem1 = copy.deepcopy(self.doc_problem1)
doc_problem1["tags"] = {}
doc_problem1["collections"] = {'display_name': [], 'key': []}
doc_problem1["units"] = {'display_name': [], 'key': []}
doc_problem2 = copy.deepcopy(self.doc_problem2)
doc_problem2["tags"] = {}
doc_problem2["collections"] = {'display_name': [], 'key': []}
doc_problem2["units"] = {'display_name': [], 'key': []}
doc_collection = copy.deepcopy(self.collection_dict)
doc_collection["tags"] = {}
doc_unit = copy.deepcopy(self.unit_dict)
@@ -300,9 +302,11 @@ class TestSearchApi(ModuleStoreTestCase):
doc_problem1 = copy.deepcopy(self.doc_problem1)
doc_problem1["tags"] = {}
doc_problem1["collections"] = {"display_name": [], "key": []}
doc_problem1["units"] = {'display_name': [], 'key': []}
doc_problem2 = copy.deepcopy(self.doc_problem2)
doc_problem2["tags"] = {}
doc_problem2["collections"] = {"display_name": [], "key": []}
doc_problem2["units"] = {'display_name': [], 'key': []}
doc_collection = copy.deepcopy(self.collection_dict)
doc_collection["tags"] = {}
doc_unit = copy.deepcopy(self.unit_dict)
@@ -417,6 +421,7 @@ class TestSearchApi(ModuleStoreTestCase):
doc_problem2 = copy.deepcopy(self.doc_problem2)
doc_problem2["tags"] = {}
doc_problem2["collections"] = {'display_name': [], 'key': []}
doc_problem2["units"] = {'display_name': [], 'key': []}
orig_from_component = library_api.LibraryXBlockMetadata.from_component
@@ -939,3 +944,34 @@ class TestSearchApi(ModuleStoreTestCase):
],
any_order=True,
)
@override_settings(MEILISEARCH_ENABLED=True)
def test_block_in_units(self, mock_meilisearch):
with freeze_time(self.created_date):
library_api.update_container_children(
LibraryContainerLocator.from_string(self.unit_key),
[self.problem1.usage_key],
None,
)
doc_block_with_units = {
"id": self.doc_problem1["id"],
"units": {
"display_name": [self.unit.display_name],
"key": [self.unit_key],
},
}
new_unit_dict = {
**self.unit_dict,
"num_children": 1,
'content': {'child_usage_keys': [self.doc_problem1["usage_key"]]}
}
assert mock_meilisearch.return_value.index.return_value.update_documents.call_count == 2
mock_meilisearch.return_value.index.return_value.update_documents.assert_has_calls(
[
call([doc_block_with_units]),
call([new_unit_dict]),
],
any_order=True,
)

View File

@@ -646,11 +646,11 @@ def restore_library_block(usage_key: LibraryUsageLocatorV2, user_id: int | None
)
)
# Add tags and collections back to index
# Add tags, collections and units back to index
CONTENT_OBJECT_ASSOCIATIONS_CHANGED.send_event(
content_object=ContentObjectChangedData(
object_id=str(usage_key),
changes=["collections", "tags"],
changes=["collections", "tags", "units"],
),
)

View File

@@ -429,6 +429,14 @@ def update_container_children(
created_by=user_id,
entities_action=entities_action,
)
for key in children_ids:
CONTENT_OBJECT_ASSOCIATIONS_CHANGED.send_event(
content_object=ContentObjectChangedData(
object_id=str(key),
changes=["units"],
),
)
case _:
raise ValueError(f"Invalid container type: {container_type}")

View File

@@ -839,6 +839,83 @@ class ContentLibraryContainersTest(ContentLibrariesRestApiTest):
self._set_library_block_fields(self.html_block_usage_key, {"data": block_olx, "metadata": {}})
self._validate_calls_of_html_block(container_update_event_receiver)
def test_call_object_changed_signal_when_remove_component(self):
html_block_1 = self._add_block_to_library(
self.lib1.library_key, "html", "html3",
)
api.update_container_children(
self.unit2.container_key,
[UsageKey.from_string(html_block_1["id"])],
None,
entities_action=authoring_api.ChildrenEntitiesAction.APPEND,
)
event_reciver = mock.Mock()
CONTENT_OBJECT_ASSOCIATIONS_CHANGED.connect(event_reciver)
api.update_container_children(
self.unit2.container_key,
[UsageKey.from_string(html_block_1["id"])],
None,
entities_action=authoring_api.ChildrenEntitiesAction.REMOVE,
)
assert event_reciver.call_count == 1
self.assertDictContainsSubset(
{
"signal": CONTENT_OBJECT_ASSOCIATIONS_CHANGED,
"sender": None,
"content_object": ContentObjectChangedData(
object_id=html_block_1["id"],
changes=["units"],
),
},
event_reciver.call_args_list[0].kwargs,
)
def test_call_object_changed_signal_when_add_component(self):
event_reciver = mock.Mock()
CONTENT_OBJECT_ASSOCIATIONS_CHANGED.connect(event_reciver)
html_block_1 = self._add_block_to_library(
self.lib1.library_key, "html", "html4",
)
html_block_2 = self._add_block_to_library(
self.lib1.library_key, "html", "html5",
)
api.update_container_children(
self.unit2.container_key,
[
UsageKey.from_string(html_block_1["id"]),
UsageKey.from_string(html_block_2["id"])
],
None,
entities_action=authoring_api.ChildrenEntitiesAction.APPEND,
)
assert event_reciver.call_count == 2
self.assertDictContainsSubset(
{
"signal": CONTENT_OBJECT_ASSOCIATIONS_CHANGED,
"sender": None,
"content_object": ContentObjectChangedData(
object_id=html_block_1["id"],
changes=["units"],
),
},
event_reciver.call_args_list[0].kwargs,
)
self.assertDictContainsSubset(
{
"signal": CONTENT_OBJECT_ASSOCIATIONS_CHANGED,
"sender": None,
"content_object": ContentObjectChangedData(
object_id=html_block_2["id"],
changes=["units"],
),
},
event_reciver.call_args_list[1].kwargs,
)
def test_delete_component_and_revert(self):
"""
When a component is deleted and then the delete is reverted, signals

View File

@@ -57,13 +57,6 @@ django-stubs<6
# for them.
edx-enterprise==5.13.7
# Date: 2024-07-26
# To override the constraint of edx-lint
# This can be removed once https://github.com/openedx/edx-platform/issues/34586 is resolved
# and the upstream constraint in edx-lint has been removed.
# Issue for unpinning: https://github.com/openedx/edx-platform/issues/35273
event-tracking==3.0.0
# Date: 2023-07-26
# Our legacy Sass code is incompatible with anything except this ancient libsass version.
# Here is a ticket to upgrade, but it's of debatable importance given that we are rapidly moving

View File

@@ -546,9 +546,8 @@ enmerkar==0.7.1
# via enmerkar-underscore
enmerkar-underscore==2.4.0
# via -r requirements/edx/kernel.in
event-tracking==3.0.0
event-tracking==3.3.0
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/kernel.in
# edx-completion
# edx-proctoring

View File

@@ -860,9 +860,8 @@ enmerkar-underscore==2.4.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
event-tracking==3.0.0
event-tracking==3.3.0
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# edx-completion

View File

@@ -637,9 +637,8 @@ enmerkar==0.7.1
# enmerkar-underscore
enmerkar-underscore==2.4.0
# via -r requirements/edx/base.txt
event-tracking==3.0.0
event-tracking==3.3.0
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
# edx-completion
# edx-proctoring

View File

@@ -664,9 +664,8 @@ enmerkar==0.7.1
# enmerkar-underscore
enmerkar-underscore==2.4.0
# via -r requirements/edx/base.txt
event-tracking==3.0.0
event-tracking==3.3.0
# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
# edx-completion
# edx-proctoring

View File

@@ -3399,7 +3399,7 @@ class ImageResponse(LoncapaResponse):
parsed_region = [parsed_region]
for region in parsed_region:
polygon = MultiPoint(region).convex_hull
if (polygon.type == 'Polygon' and
if (polygon.geom_type == 'Polygon' and
polygon.contains(Point(ans_x, ans_y))):
correct_map.set(aid, 'correct')
break

View File

@@ -58,10 +58,9 @@ class StubXQueueService:
return dispatch
def test_capa_system(render_template=None):
def mock_capa_system(render_template=None):
"""
Construct a mock LoncapaSystem instance.
"""
the_system = Mock(
spec=LoncapaSystem,
@@ -102,7 +101,7 @@ def mock_capa_block():
def new_loncapa_problem(xml, problem_id='1', capa_system=None, seed=723, use_capa_render_template=False):
"""Construct a `LoncapaProblem` suitable for unit tests."""
render_template = capa_render_template if use_capa_render_template else None
return LoncapaProblem(xml, id=problem_id, seed=seed, capa_system=capa_system or test_capa_system(render_template),
return LoncapaProblem(xml, id=problem_id, seed=seed, capa_system=capa_system or mock_capa_system(render_template),
capa_block=mock_capa_block())

View File

@@ -8,7 +8,7 @@ import textwrap
import unittest
from xmodule.capa.responsetypes import LoncapaProblemError
from xmodule.capa.tests.helpers import new_loncapa_problem, test_capa_system
from xmodule.capa.tests.helpers import new_loncapa_problem, mock_capa_system
class CapaAnswerPoolTest(unittest.TestCase):
@@ -16,7 +16,7 @@ class CapaAnswerPoolTest(unittest.TestCase):
def setUp(self):
super(CapaAnswerPoolTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
self.system = test_capa_system()
self.system = mock_capa_system()
# XML problem setup used by a few tests.
common_question_xml = textwrap.dedent("""

View File

@@ -6,7 +6,7 @@ import xml.sax.saxutils as saxutils
from lxml import etree
from xmodule.capa import customrender
from xmodule.capa.tests.helpers import test_capa_system
from xmodule.capa.tests.helpers import mock_capa_system
# just a handy shortcut
lookup_tag = customrender.registry.get_class_for_tag
@@ -30,7 +30,7 @@ class HelperTest(unittest.TestCase):
'''
def check(self, d):
xml = etree.XML(test_capa_system().render_template('blah', d))
xml = etree.XML(mock_capa_system().render_template('blah', d))
assert d == extract_context(xml)
def test_extract_context(self):
@@ -50,7 +50,7 @@ class SolutionRenderTest(unittest.TestCase):
xml_str = """<solution id="solution_12">{s}</solution>""".format(s=solution)
element = etree.fromstring(xml_str)
renderer = lookup_tag('solution')(test_capa_system(), element)
renderer = lookup_tag('solution')(mock_capa_system(), element)
assert renderer.id == 'solution_12'
@@ -69,7 +69,7 @@ class MathRenderTest(unittest.TestCase):
xml_str = """<math>{tex}</math>""".format(tex=latex_in)
element = etree.fromstring(xml_str)
renderer = lookup_tag('math')(test_capa_system(), element)
renderer = lookup_tag('math')(mock_capa_system(), element)
assert renderer.mathstr == mathjax_out

View File

@@ -10,7 +10,7 @@ from unittest import mock
import ddt
from lxml import etree
from xmodule.capa.tests.helpers import new_loncapa_problem, test_capa_system
from xmodule.capa.tests.helpers import new_loncapa_problem, mock_capa_system
from openedx.core.djangolib.markup import HTML
from .response_xml_factory import CustomResponseXMLFactory, StringResponseXMLFactory
@@ -24,7 +24,7 @@ class CapaHtmlRenderTest(unittest.TestCase):
def setUp(self):
super(CapaHtmlRenderTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
self.capa_system = test_capa_system()
self.capa_system = mock_capa_system()
def test_blank_problem(self):
"""
@@ -148,7 +148,7 @@ class CapaHtmlRenderTest(unittest.TestCase):
xml_str = StringResponseXMLFactory().build_xml(**kwargs)
# Mock out the template renderer
the_system = test_capa_system()
the_system = mock_capa_system()
the_system.render_template = mock.Mock()
the_system.render_template.return_value = "<div class='input-template-render'>Input Template Render</div>"

View File

@@ -34,7 +34,7 @@ from six.moves import zip
from xmodule.capa import inputtypes
from xmodule.capa.checker import DemoSystem
from xmodule.capa.tests.helpers import test_capa_system
from xmodule.capa.tests.helpers import mock_capa_system
from xmodule.capa.xqueue_interface import XQUEUE_TIMEOUT
from openedx.core.djangolib.markup import HTML
@@ -72,7 +72,7 @@ class OptionInputTest(unittest.TestCase):
'default_option_text': 'Select an option',
'response_data': RESPONSE_DATA
}
option_input = lookup_tag('optioninput')(test_capa_system(), element, state)
option_input = lookup_tag('optioninput')(mock_capa_system(), element, state)
context = option_input._get_render_context() # pylint: disable=protected-access
prob_id = 'sky_input'
@@ -138,7 +138,7 @@ class ChoiceGroupTest(unittest.TestCase):
'response_data': RESPONSE_DATA
}
the_input = lookup_tag(tag)(test_capa_system(), element, state)
the_input = lookup_tag(tag)(mock_capa_system(), element, state)
context = the_input._get_render_context() # pylint: disable=protected-access
@@ -233,7 +233,7 @@ class JSInputTest(unittest.TestCase):
'value': 103,
'response_data': RESPONSE_DATA
}
the_input = lookup_tag('jsinput')(test_capa_system(), element, state)
the_input = lookup_tag('jsinput')(mock_capa_system(), element, state)
context = the_input._get_render_context() # pylint: disable=protected-access
@@ -270,7 +270,7 @@ class TextLineTest(unittest.TestCase):
'value': 'BumbleBee',
'response_data': RESPONSE_DATA
}
the_input = lookup_tag('textline')(test_capa_system(), element, state)
the_input = lookup_tag('textline')(mock_capa_system(), element, state)
context = the_input._get_render_context() # pylint: disable=protected-access
prob_id = 'prob_1_2'
@@ -306,7 +306,7 @@ class TextLineTest(unittest.TestCase):
'value': 'BumbleBee',
'response_data': RESPONSE_DATA
}
the_input = lookup_tag('textline')(test_capa_system(), element, state)
the_input = lookup_tag('textline')(mock_capa_system(), element, state)
context = the_input._get_render_context() # pylint: disable=protected-access
prob_id = 'prob_1_2'
@@ -354,7 +354,7 @@ class TextLineTest(unittest.TestCase):
'value': 'BumbleBee',
'response_data': RESPONSE_DATA
}
the_input = lookup_tag('textline')(test_capa_system(), element, state)
the_input = lookup_tag('textline')(mock_capa_system(), element, state)
context = the_input._get_render_context() # pylint: disable=protected-access
prob_id = 'prob_1_2'
@@ -400,7 +400,7 @@ class FileSubmissionTest(unittest.TestCase):
'response_data': RESPONSE_DATA
}
input_class = lookup_tag('filesubmission')
the_input = input_class(test_capa_system(), element, state)
the_input = input_class(mock_capa_system(), element, state)
context = the_input._get_render_context() # pylint: disable=protected-access
prob_id = 'prob_1_2'
@@ -450,7 +450,7 @@ class CodeInputTest(unittest.TestCase):
}
input_class = lookup_tag('codeinput')
the_input = input_class(test_capa_system(), element, state)
the_input = input_class(mock_capa_system(), element, state)
context = the_input._get_render_context() # pylint: disable=protected-access
prob_id = 'prob_1_2'
@@ -510,7 +510,7 @@ class MatlabTest(unittest.TestCase):
}
self.input_class = lookup_tag('matlabinput')
self.the_input = self.input_class(test_capa_system(), elt, state)
self.the_input = self.input_class(mock_capa_system(), elt, state)
def test_rendering(self):
context = self.the_input._get_render_context() # pylint: disable=protected-access
@@ -547,7 +547,7 @@ class MatlabTest(unittest.TestCase):
}
elt = etree.fromstring(self.xml)
the_input = self.input_class(test_capa_system(), elt, state)
the_input = self.input_class(mock_capa_system(), elt, state)
context = the_input._get_render_context() # pylint: disable=protected-access
prob_id = 'prob_1_2'
expected = {
@@ -582,7 +582,7 @@ class MatlabTest(unittest.TestCase):
}
elt = etree.fromstring(self.xml)
prob_id = 'prob_1_2'
the_input = self.input_class(test_capa_system(), elt, state)
the_input = self.input_class(mock_capa_system(), elt, state)
context = the_input._get_render_context() # pylint: disable=protected-access
expected = {
'STATIC_URL': '/dummy-static/',
@@ -616,7 +616,7 @@ class MatlabTest(unittest.TestCase):
}
elt = etree.fromstring(self.xml)
prob_id = 'prob_1_2'
the_input = self.input_class(test_capa_system(), elt, state)
the_input = self.input_class(mock_capa_system(), elt, state)
context = the_input._get_render_context() # pylint: disable=protected-access
expected = {
'STATIC_URL': '/dummy-static/',
@@ -668,7 +668,7 @@ class MatlabTest(unittest.TestCase):
'feedback': {'message': '3'}, }
elt = etree.fromstring(self.xml)
the_input = self.input_class(test_capa_system(), elt, state)
the_input = self.input_class(mock_capa_system(), elt, state)
inner_msg = 'hello!'
queue_msg = json.dumps({'msg': inner_msg})
@@ -687,7 +687,7 @@ class MatlabTest(unittest.TestCase):
'feedback': {'message': '3'}, }
elt = etree.fromstring(self.xml)
the_input = self.input_class(test_capa_system(), elt, state)
the_input = self.input_class(mock_capa_system(), elt, state)
inner_msg = 'hello!'
queue_msg = json.dumps({'msg': inner_msg})
@@ -702,7 +702,7 @@ class MatlabTest(unittest.TestCase):
state = {'input_state': {'queuestate': 'queued', 'queuetime': 5}}
elt = etree.fromstring(self.xml)
the_input = self.input_class(test_capa_system(), elt, state)
the_input = self.input_class(mock_capa_system(), elt, state)
assert the_input.status == 'queued'
@patch('xmodule.capa.inputtypes.time.time', return_value=45)
@@ -711,7 +711,7 @@ class MatlabTest(unittest.TestCase):
state = {'input_state': {'queuestate': 'queued', 'queuetime': 5}}
elt = etree.fromstring(self.xml)
the_input = self.input_class(test_capa_system(), elt, state)
the_input = self.input_class(mock_capa_system(), elt, state)
assert the_input.status == 'unsubmitted'
assert the_input.msg == 'No response from Xqueue within {} seconds. Aborted.'.format(XQUEUE_TIMEOUT)
@@ -723,7 +723,7 @@ class MatlabTest(unittest.TestCase):
state = {'input_state': {'queuestate': 'queued'}}
elt = etree.fromstring(self.xml)
the_input = self.input_class(test_capa_system(), elt, state)
the_input = self.input_class(mock_capa_system(), elt, state)
assert the_input.status == 'unsubmitted'
def test_matlab_api_key(self):
@@ -731,7 +731,7 @@ class MatlabTest(unittest.TestCase):
Test that api_key ends up in the xqueue payload
"""
elt = etree.fromstring(self.xml)
system = test_capa_system()
system = mock_capa_system()
system.matlab_api_key = 'test_api_key'
the_input = lookup_tag('matlabinput')(system, elt, {})
@@ -852,7 +852,7 @@ class MatlabTest(unittest.TestCase):
}
elt = etree.fromstring(self.xml)
the_input = self.input_class(test_capa_system(), elt, state)
the_input = self.input_class(mock_capa_system(), elt, state)
context = the_input._get_render_context() # pylint: disable=protected-access
self.maxDiff = None
expected = fromstring('\n<div class="matlabResponse"><div class="commandWindowOutput" style="white-space: pre;"> <strong>if</strong> Conditionally execute statements.\nThe general form of the <strong>if</strong> statement is\n\n <strong>if</strong> expression\n statements\n ELSEIF expression\n statements\n ELSE\n statements\n END\n\nThe statements are executed if the real part of the expression \nhas all non-zero elements. The ELSE and ELSEIF parts are optional.\nZero or more ELSEIF parts can be used as well as nested <strong>if</strong>\'s.\nThe expression is usually of the form expr rop expr where \nrop is ==, &lt;, &gt;, &lt;=, &gt;=, or ~=.\n<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAjAAAAGkCAIAAACgj==">\n\nExample\n if I == J\n A(I,J) = 2;\n elseif abs(I-J) == 1\n A(I,J) = -1;\n else\n A(I,J) = 0;\n end\n\nSee also <a>relop</a>, <a>else</a>, <a>elseif</a>, <a>end</a>, <a>for</a>, <a>while</a>, <a>switch</a>.\n\nReference page in Help browser\n <a>doc if</a>\n\n</div><ul></ul></div>\n') # lint-amnesty, pylint: disable=line-too-long
@@ -901,7 +901,7 @@ class MatlabTest(unittest.TestCase):
'status': 'queued',
}
elt = etree.fromstring(self.xml)
the_input = self.input_class(test_capa_system(), elt, state)
the_input = self.input_class(mock_capa_system(), elt, state)
assert the_input.queue_msg == queue_msg
def test_matlab_queue_message_not_allowed_tag(self):
@@ -915,7 +915,7 @@ class MatlabTest(unittest.TestCase):
'status': 'queued',
}
elt = etree.fromstring(self.xml)
the_input = self.input_class(test_capa_system(), elt, state)
the_input = self.input_class(mock_capa_system(), elt, state)
expected = ""
assert the_input.queue_msg == expected
@@ -974,7 +974,7 @@ class SchematicTest(unittest.TestCase):
'response_data': RESPONSE_DATA
}
the_input = lookup_tag('schematic')(test_capa_system(), element, state)
the_input = lookup_tag('schematic')(mock_capa_system(), element, state)
context = the_input._get_render_context() # pylint: disable=protected-access
prob_id = 'prob_1_2'
@@ -1021,7 +1021,7 @@ class ImageInputTest(unittest.TestCase):
'response_data': RESPONSE_DATA
}
the_input = lookup_tag('imageinput')(test_capa_system(), element, state)
the_input = lookup_tag('imageinput')(mock_capa_system(), element, state)
context = the_input._get_render_context() # pylint: disable=protected-access
prob_id = 'prob_1_2'
@@ -1079,7 +1079,7 @@ class CrystallographyTest(unittest.TestCase):
'response_data': RESPONSE_DATA
}
the_input = lookup_tag('crystallography')(test_capa_system(), element, state)
the_input = lookup_tag('crystallography')(mock_capa_system(), element, state)
context = the_input._get_render_context() # pylint: disable=protected-access
prob_id = 'prob_1_2'
@@ -1124,7 +1124,7 @@ class VseprTest(unittest.TestCase):
'response_data': RESPONSE_DATA
}
the_input = lookup_tag('vsepr_input')(test_capa_system(), element, state)
the_input = lookup_tag('vsepr_input')(mock_capa_system(), element, state)
context = the_input._get_render_context() # pylint: disable=protected-access
prob_id = 'prob_1_2'
@@ -1160,7 +1160,7 @@ class ChemicalEquationTest(unittest.TestCase):
'value': 'H2OYeah',
'response_data': RESPONSE_DATA
}
self.the_input = lookup_tag('chemicalequationinput')(test_capa_system(), element, state)
self.the_input = lookup_tag('chemicalequationinput')(mock_capa_system(), element, state)
def test_rendering(self):
"""
@@ -1255,7 +1255,7 @@ class FormulaEquationTest(unittest.TestCase):
'value': 'x^2+1/2',
'response_data': RESPONSE_DATA
}
self.the_input = lookup_tag('formulaequationinput')(test_capa_system(), element, state)
self.the_input = lookup_tag('formulaequationinput')(mock_capa_system(), element, state)
def test_rendering(self):
"""
@@ -1305,7 +1305,7 @@ class FormulaEquationTest(unittest.TestCase):
'value': 'x^2+1/2',
'response_data': RESPONSE_DATA
}
the_input = lookup_tag('formulaequationinput')(test_capa_system(), element, state)
the_input = lookup_tag('formulaequationinput')(mock_capa_system(), element, state)
context = the_input._get_render_context() # pylint: disable=protected-access
prob_id = 'prob_1_2'
@@ -1440,7 +1440,7 @@ class DragAndDropTest(unittest.TestCase):
]
}
the_input = lookup_tag('drag_and_drop_input')(test_capa_system(), element, state)
the_input = lookup_tag('drag_and_drop_input')(mock_capa_system(), element, state)
prob_id = 'prob_1_2'
context = the_input._get_render_context() # pylint: disable=protected-access
expected = {
@@ -1494,7 +1494,7 @@ class AnnotationInputTest(unittest.TestCase):
tag = 'annotationinput'
the_input = lookup_tag(tag)(test_capa_system(), element, state)
the_input = lookup_tag(tag)(mock_capa_system(), element, state)
context = the_input._get_render_context() # pylint: disable=protected-access
prob_id = 'annotation_input'
@@ -1588,7 +1588,7 @@ class TestChoiceText(unittest.TestCase):
'describedby_html': DESCRIBEDBY.format(status_id=prob_id)
}
expected.update(state)
the_input = lookup_tag(tag)(test_capa_system(), element, state)
the_input = lookup_tag(tag)(mock_capa_system(), element, state)
context = the_input._get_render_context() # pylint: disable=protected-access
assert context == expected

View File

@@ -20,7 +20,7 @@ from pytz import UTC
from xmodule.capa.correctmap import CorrectMap
from xmodule.capa.responsetypes import LoncapaProblemError, ResponseError, StudentInputError
from xmodule.capa.tests.helpers import load_fixture, new_loncapa_problem, test_capa_system
from xmodule.capa.tests.helpers import load_fixture, new_loncapa_problem, mock_capa_system
from xmodule.capa.tests.response_xml_factory import (
AnnotationResponseXMLFactory,
ChoiceResponseXMLFactory,
@@ -2326,7 +2326,7 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
import my_helper
num = my_helper.seventeen()
""")
capa_system = test_capa_system()
capa_system = mock_capa_system()
capa_system.get_python_lib_zip = lambda: zipstring.getvalue() # lint-amnesty, pylint: disable=unnecessary-lambda
problem = self.build_problem(script=script, capa_system=capa_system)
assert problem.context['num'] == 17

View File

@@ -5,7 +5,7 @@ import textwrap
import unittest
from xmodule.capa.responsetypes import LoncapaProblemError
from xmodule.capa.tests.helpers import new_loncapa_problem, test_capa_system
from xmodule.capa.tests.helpers import new_loncapa_problem, mock_capa_system
class CapaShuffleTest(unittest.TestCase):
@@ -13,7 +13,7 @@ class CapaShuffleTest(unittest.TestCase):
def setUp(self):
super(CapaShuffleTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
self.system = test_capa_system()
self.system = mock_capa_system()
def test_shuffle_4_choices(self):
xml_str = textwrap.dedent("""

View File

@@ -6,7 +6,7 @@ i.e. those with the <multiplechoiceresponse> element
import textwrap
import unittest
from xmodule.capa.tests.helpers import load_fixture, new_loncapa_problem, test_capa_system
from xmodule.capa.tests.helpers import load_fixture, new_loncapa_problem, mock_capa_system
class CapaTargetedFeedbackTest(unittest.TestCase):
@@ -16,7 +16,7 @@ class CapaTargetedFeedbackTest(unittest.TestCase):
def setUp(self):
super(CapaTargetedFeedbackTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
self.system = test_capa_system()
self.system = mock_capa_system()
def test_no_targeted_feedback(self):
xml_str = textwrap.dedent("""

View File

@@ -9,7 +9,7 @@ import unittest
import ddt
from lxml import etree
from xmodule.capa.tests.helpers import test_capa_system
from xmodule.capa.tests.helpers import mock_capa_system
from xmodule.capa.util import (
compare_with_tolerance,
contextualize_text,
@@ -25,7 +25,7 @@ class UtilTest(unittest.TestCase):
def setUp(self):
super(UtilTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
self.system = test_capa_system()
self.system = mock_capa_system()
def test_compare_with_tolerance(self): # lint-amnesty, pylint: disable=too-many-statements
# Test default tolerance '0.001%' (it is relative)

View File

@@ -2798,48 +2798,6 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
('shuffle', ['choice_3', 'choice_1', 'choice_2', 'choice_0'])
assert event_info['success'] == 'correct'
@unittest.skip("masking temporarily disabled")
def test_save_unmask(self):
"""On problem save, unmasked data should appear on publish."""
block = CapaFactory.create(xml=self.common_shuffle_xml)
with patch.object(block.runtime, 'publish') as mock_publish:
get_request_dict = {CapaFactory.input_key(): 'mask_0'}
block.save_problem(get_request_dict)
mock_call = mock_publish.mock_calls[0]
event_info = mock_call[1][1]
assert event_info['answers'][CapaFactory.answer_key()] == 'choice_2'
assert event_info['permutation'][CapaFactory.answer_key()] is not None
@unittest.skip("masking temporarily disabled")
def test_reset_unmask(self):
"""On problem reset, unmask names should appear publish."""
block = CapaFactory.create(xml=self.common_shuffle_xml)
get_request_dict = {CapaFactory.input_key(): 'mask_0'}
block.submit_problem(get_request_dict)
# On reset, 'old_state' should use unmasked names
with patch.object(block.runtime, 'publish') as mock_publish:
block.reset_problem(None)
mock_call = mock_publish.mock_calls[0]
event_info = mock_call[1][1]
assert mock_call[1][0] == 'reset_problem'
assert event_info['old_state']['student_answers'][CapaFactory.answer_key()] == 'choice_2'
assert event_info['permutation'][CapaFactory.answer_key()] is not None
@unittest.skip("masking temporarily disabled")
def test_rescore_unmask(self):
"""On problem rescore, unmasked names should appear on publish."""
block = CapaFactory.create(xml=self.common_shuffle_xml)
get_request_dict = {CapaFactory.input_key(): 'mask_0'}
block.submit_problem(get_request_dict)
# On rescore, state/student_answers should use unmasked names
with patch.object(block.runtime, 'publish') as mock_publish:
block.rescore_problem(only_if_higher=False) # lint-amnesty, pylint: disable=no-member
mock_call = mock_publish.mock_calls[0]
event_info = mock_call[1][1]
assert mock_call[1][0] == 'problem_rescore'
assert event_info['state']['student_answers'][CapaFactory.answer_key()] == 'choice_2'
assert event_info['permutation'][CapaFactory.answer_key()] is not None
def test_check_unmask_answerpool(self):
"""Check answer-pool question publish uses unmasked names"""
xml = textwrap.dedent("""