Skip to content

Commit 95f6ef1

Browse files
committed
test: drop the addition of XModuleMixin for the xblocks-contrib blocks
1 parent bfe407e commit 95f6ef1

File tree

9 files changed

+78
-10
lines changed

9 files changed

+78
-10
lines changed

cms/djangoapps/contentstore/views/component.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
)
3838
from cms.djangoapps.contentstore.xblock_storage_handlers.view_handlers import load_services_for_studio
3939
from openedx.core.lib.xblock_utils import get_aside_from_xblock, is_xblock_aside
40+
from openedx.core.djangoapps.xblock.utils import filter_mixins_for_standard_xblocks
4041
from openedx.core.djangoapps.discussions.models import DiscussionsConfiguration
4142
from openedx.core.djangoapps.content_tagging.api import get_object_tags
4243
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
@@ -132,7 +133,8 @@ def _load_mixed_class(category):
132133
return None
133134

134135
component_class = XBlock.load_class(category)
135-
mixologist = Mixologist(settings.XBLOCK_MIXINS)
136+
mixins = filter_mixins_for_standard_xblocks(component_class, settings.XBLOCK_MIXINS)
137+
mixologist = Mixologist(mixins)
136138
return mixologist.mix(component_class)
137139

138140

cms/djangoapps/contentstore/views/preview.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
from common.djangoapps.student.models import anonymous_id_for_user
3939
from common.djangoapps.edxmako.shortcuts import render_to_string
4040
from common.djangoapps.edxmako.services import MakoService
41+
from openedx.core.djangoapps.xblock.utils import filter_mixins_for_standard_xblocks
4142
from common.djangoapps.xblock_django.user_service import DjangoXBlockUserService
4243
from lms.djangoapps.lms_xblock.field_data import LmsFieldData
4344
from openedx.core.lib.license import wrap_with_license
@@ -234,7 +235,7 @@ def _prepare_runtime_for_preview(request, block):
234235
}
235236

236237
block.runtime.get_block_for_descriptor = partial(_load_preview_block, request)
237-
block.runtime.mixins = settings.XBLOCK_MIXINS
238+
block.runtime.mixins = filter_mixins_for_standard_xblocks(block.__class__, settings.XBLOCK_MIXINS)
238239

239240
# Set up functions to modify the fragment produced by student_view
240241
block.runtime.wrappers = wrappers

openedx/core/djangoapps/xblock/runtime/openedx_content_runtime.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from xblock.exceptions import NoSuchUsage
2121
from xblock.fields import Field, Scope, ScopeIds
2222
from xblock.field_data import FieldData
23+
from xblock.runtime import Mixologist
2324

2425
from openedx.core.djangoapps.xblock.api import get_xblock_app_config
2526
from openedx.core.lib.xblock_serializer.api import serialize_modulestore_block_for_openedx_content
@@ -28,6 +29,7 @@
2829
from ..utils import get_auto_latest_version
2930
from ..learning_context.manager import get_learning_context_impl
3031
from .runtime import XBlockRuntime
32+
from openedx.core.djangoapps.xblock.utils import filter_mixins_for_standard_xblocks
3133

3234

3335
log = logging.getLogger(__name__)
@@ -203,7 +205,9 @@ def get_block(self, usage_key, for_parent=None, *, version: int | LatestVersion
203205
if xml_node.get("url_name", None):
204206
log.warning("XBlock at %s should not specify an old-style url_name attribute.", usage_key)
205207

206-
block_class = self.mixologist.mix(self.load_block_type(block_type))
208+
base_class = self.load_block_type(block_type)
209+
mixins = filter_mixins_for_standard_xblocks(base_class, mixologist=self.mixologist)
210+
block_class = Mixologist(mixins).mix(base_class)
207211

208212
if hasattr(block_class, 'parse_xml_new_runtime'):
209213
# This is a (former) XModule with messy XML parsing code; let its parse_xml() method continue to work

openedx/core/djangoapps/xblock/utils.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import hashlib
66
import hmac
7+
import inspect
78
import math
89
import time
910
from uuid import uuid4
@@ -14,6 +15,7 @@
1415
from openedx.core.djangoapps.xblock.apps import get_xblock_app_config
1516

1617
from .data import AuthoredDataMode, LatestVersion
18+
from xmodule.x_module import XModuleMixin
1719

1820

1921
def get_secure_token_for_xblock_handler(user_id, block_key_str, time_idx=0):
@@ -186,3 +188,34 @@ def get_auto_latest_version(version: int | LatestVersion) -> int | LatestVersion
186188
else LatestVersion.PUBLISHED
187189
)
188190
return version
191+
192+
193+
def filter_mixins_for_standard_xblocks(xblock_class, mixins=None, mixologist=None):
194+
"""
195+
Filter legacy mixins for standard-compliant extracted XBlocks.
196+
197+
If the fully-qualified class name of ``xblock_class`` is listed in
198+
``settings.STANDARD_COMPLIANT_XBLOCKS``, then we remove ``XModuleMixin`` from the
199+
provided ``mixins``.
200+
"""
201+
if mixins is None:
202+
mixins = ()
203+
if mixologist is not None:
204+
mixins = getattr(mixologist, "_mixins", mixins)
205+
if not xblock_class:
206+
return mixins
207+
208+
full_class_name = f"{xblock_class.__module__}.{xblock_class.__name__}"
209+
210+
if full_class_name not in getattr(settings, "STANDARD_COMPLIANT_XBLOCKS", ()):
211+
return mixins
212+
213+
filtered_mixins = tuple(m for m in mixins if m is not XModuleMixin)
214+
215+
if XModuleMixin not in filtered_mixins:
216+
caller = None
217+
frame = inspect.currentframe()
218+
if frame is not None and frame.f_back is not None:
219+
caller = f"{frame.f_back.f_code.co_filename}:{frame.f_back.f_lineno} ({frame.f_back.f_code.co_name})"
220+
print(f"XModuleMixin removed/not-added in {full_class_name} mixins: {filtered_mixins} | caller={caller}")
221+
return filtered_mixins

openedx/envs/common.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,6 +2030,20 @@ def add_optional_apps(optional_apps, installed_apps):
20302030
EditInfoMixin,
20312031
)
20322032

2033+
# .. setting_name: STANDARD_COMPLIANT_XBLOCKS
2034+
# .. setting_default: ()
2035+
# .. setting_description: Tuple of fully-qualified XBlock class names that conform to the standard XBlock
2036+
# interface. For these XBlocks, the platform will not inject legacy mixins like XModuleMixin when
2037+
# instantiating them via the various XBlock runtimes.
2038+
STANDARD_COMPLIANT_XBLOCKS = (
2039+
"xblocks_contrib.video.video.VideoBlock",
2040+
"xblocks_contrib.word_cloud.word_cloud.WordCloudBlock",
2041+
"xblocks_contrib.discussion.discussion.DiscussionXBlock",
2042+
"xblocks_contrib.poll.poll.PollBlock",
2043+
"xblocks_contrib.html.html.HtmlBlockMixin",
2044+
"xblocks_contrib.annotatable.annotatable.AnnotatableBlock",
2045+
)
2046+
20332047
######################## Built-in Blocks Extraction ########################
20342048

20352049
# The following Django settings flags have been introduced temporarily to facilitate

xmodule/modulestore/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from xblock.core import XBlock
2222
from xblock.plugin import default_select
2323
from xblock.runtime import Mixologist
24+
from openedx.core.djangoapps.xblock.utils import filter_mixins_for_standard_xblocks
2425

2526
# The below import is not used within this module, but ir is still needed becuase
2627
# other modules are imorting EdxJSONEncoder from here
@@ -1311,7 +1312,8 @@ def partition_fields_by_scope(self, category, fields):
13111312
if fields is None:
13121313
return result
13131314
classes = XBlock.load_class(category, default=self.default_class)
1314-
cls = self.mixologist.mix(classes)
1315+
mixins = filter_mixins_for_standard_xblocks(classes, mixologist=self.mixologist)
1316+
cls = Mixologist(mixins).mix(classes)
13151317
for field_name, value in fields.items():
13161318
field = getattr(cls, field_name)
13171319
result[field.scope][field_name] = value

xmodule/modulestore/mongo/base.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929
from path import Path as path
3030
from xblock.exceptions import InvalidScopeError
3131
from xblock.fields import Reference, ReferenceList, ReferenceValueDict, Scope, ScopeIds
32-
from xblock.runtime import KvsFieldData
32+
from xblock.runtime import KvsFieldData, Mixologist
33+
34+
from openedx.core.djangoapps.xblock.utils import filter_mixins_for_standard_xblocks
3335

3436
from xmodule.assetstore import AssetMetadata, CourseAssetsFromStorage
3537
from xmodule.course_block import CourseSummary
@@ -229,7 +231,8 @@ def load_item(self, location, for_parent=None): # lint-amnesty, pylint: disable
229231
if isinstance(data, str):
230232
data = {'data': data}
231233

232-
mixed_class = self.mixologist.mix(class_)
234+
mixins = filter_mixins_for_standard_xblocks(class_, mixologist=self.mixologist)
235+
mixed_class = Mixologist(mixins).mix(class_)
233236
if data: # empty or None means no work
234237
data = self._convert_reference_fields_to_keys(mixed_class, location.course_key, data)
235238
metadata = self._convert_reference_fields_to_keys(mixed_class, location.course_key, metadata)

xmodule/modulestore/split_mongo/split.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@
7575
from path import Path as path
7676
from xblock.core import XBlock
7777
from xblock.fields import Reference, ReferenceList, ReferenceValueDict, Scope
78+
from xblock.runtime import Mixologist
79+
80+
from openedx.core.djangoapps.xblock.utils import filter_mixins_for_standard_xblocks
7881

7982
from xmodule.assetstore import AssetMetadata
8083
from xmodule.course_block import CourseSummary
@@ -2925,7 +2928,8 @@ def robust_usage_key(block_key):
29252928
except KeyError:
29262929
return course_key.make_usage_key('unknown', block_key.id)
29272930

2928-
xblock_class = self.mixologist.mix(xblock_class)
2931+
mixins = filter_mixins_for_standard_xblocks(xblock_class, mixologist=self.mixologist)
2932+
xblock_class = Mixologist(mixins).mix(xblock_class)
29292933
# Make a shallow copy, so that we aren't manipulating a cached field dictionary
29302934
output_fields = dict(jsonfields)
29312935
for field_name, value in output_fields.items():
@@ -3030,7 +3034,8 @@ def _serialize_fields(self, category, fields):
30303034
"""
30313035
assert isinstance(fields, dict)
30323036
xblock_class = XBlock.load_class(category, self.default_class)
3033-
xblock_class = self.mixologist.mix(xblock_class)
3037+
mixins = filter_mixins_for_standard_xblocks(xblock_class, mixologist=self.mixologist)
3038+
xblock_class = Mixologist(mixins).mix(xblock_class)
30343039

30353040
def reference_block_id(reference):
30363041
"""

xmodule/modulestore/xml.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
ReferenceValueDict,
2727
ScopeIds,
2828
)
29-
from xblock.runtime import DictKeyValueStore
29+
from xblock.runtime import DictKeyValueStore, Mixologist
30+
31+
from openedx.core.djangoapps.xblock.utils import filter_mixins_for_standard_xblocks
3032

3133
from common.djangoapps.util.monitoring import monitor_import_failure
3234
from xmodule.error_block import ErrorBlock
@@ -100,7 +102,9 @@ def xblock_from_node(self, node, parent_id, id_generator=None):
100102
usage_id = id_generator.create_usage(def_id)
101103

102104
keys = ScopeIds(None, block_type, def_id, usage_id)
103-
block_class = self.mixologist.mix(self.load_block_type(block_type))
105+
base_class = self.load_block_type(block_type)
106+
mixins = filter_mixins_for_standard_xblocks(base_class, mixologist=self.mixologist)
107+
block_class = Mixologist(mixins).mix(base_class)
104108

105109
aside_children = self.parse_asides(node, def_id, usage_id, id_generator)
106110
asides_tags = [x.tag for x in aside_children]

0 commit comments

Comments
 (0)