From 6602e96bd9d9d4a88e4d69b7a21df7ea56b54641 Mon Sep 17 00:00:00 2001 From: farhan Date: Thu, 7 Nov 2024 16:22:58 +0500 Subject: [PATCH 1/7] chore: Add xblocks-contrib in budle.in --- requirements/edx/bundled.in | 1 + xmodule/toggles.py | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 xmodule/toggles.py diff --git a/requirements/edx/bundled.in b/requirements/edx/bundled.in index 5a46c710a6d2..a9394b809f55 100644 --- a/requirements/edx/bundled.in +++ b/requirements/edx/bundled.in @@ -47,3 +47,4 @@ ora2>=4.5.0 # Open Response Assessment XBlock xblock-poll # Xblock for polling users xblock-drag-and-drop-v2 # Drag and Drop XBlock xblock-google-drive # XBlock for google docs and calendar +xblocks-contrib # Package having multiple core XBlocks, https://github.com/openedx/xblocks-contrib?tab=readme-ov-file#xblocks-being-moved-here diff --git a/xmodule/toggles.py b/xmodule/toggles.py new file mode 100644 index 000000000000..7fc1fc774bfe --- /dev/null +++ b/xmodule/toggles.py @@ -0,0 +1,23 @@ +""" +Add Waffle flags to roll out the extracted XBlocks. +Flags will use to toggle between the old and new block quickly +without putting course content or user state at risk. + +Ticket: https://github.com/openedx/edx-platform/issues/35308 +""" +from edx_toggles.toggles import WaffleFlag + +# .. toggle_name: USE_EXTRACTED_WORD_CLOUD_BLOCK +# .. toggle_description: Enables the use of the extracted Word Cloud XBlock, which has been shifted to the 'openedx/xblocks-contrib' repo. +# .. toggle_warning: Not production-ready until https://github.com/openedx/edx-platform/issues/34840 is done. +# .. toggle_use_cases: temporary +# .. toggle_default: False +USE_EXTRACTED_WORD_CLOUD_BLOCK = WaffleFlag('xmodule.use_extracted_block.word_cloud', __name__) +# TODO: Add flag docs once above approved +USE_EXTRACTED_ANNOTATABLE_BLOCK = WaffleFlag('xmodule.use_extracted_block.annotatable', __name__) +USE_EXTRACTED_POLL_BLOCK = WaffleFlag('xmodule.use_extracted_block.poll', __name__) +USE_EXTRACTED_LTI_BLOCK = WaffleFlag('xmodule.use_extracted_block.lti', __name__) +USE_EXTRACTED_HTML_BLOCK = WaffleFlag('xmodule.use_extracted_block.html', __name__) +USE_EXTRACTED_DISCUSSION_BLOCK = WaffleFlag('xmodule.use_extracted_block.discussion', __name__) +USE_EXTRACTED_PROBLEM_BLOCK = WaffleFlag('xmodule.use_extracted_block.problem', __name__) +USE_EXTRACTED_VIDEO_BLOCK = WaffleFlag('xmodule.use_extracted_block.video', __name__) From a8707eeb2317e820196a33d017c4fa1bb98a3e5d Mon Sep 17 00:00:00 2001 From: farhan <25842457+farhan@users.noreply.github.com> Date: Wed, 13 Nov 2024 09:26:34 +0000 Subject: [PATCH 2/7] feat: Upgrade Python dependency xblocks-contrib chore: Update xblocks-contrib pypi package Commit generated by workflow `openedx/edx-platform/.github/workflows/upgrade-one-python-dependency.yml@refs/heads/farhan/waffle-flag-for-extracted-xblock` --- requirements/edx/base.txt | 6 ++++++ requirements/edx/development.txt | 8 ++++++++ requirements/edx/doc.txt | 6 ++++++ requirements/edx/testing.txt | 6 ++++++ 4 files changed, 26 insertions(+) diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index ed6de1269447..7d432e2a7b7a 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -345,6 +345,7 @@ django-statici18n==2.5.0 # lti-consumer-xblock # xblock-drag-and-drop-v2 # xblock-poll + # xblocks-contrib django-storages==1.14.3 # via # -c requirements/edx/../constraints.txt @@ -480,6 +481,7 @@ edx-i18n-tools==1.5.0 # -c requirements/edx/../constraints.txt # -r requirements/edx/bundled.in # ora2 + # xblocks-contrib edx-milestones==0.6.0 # via -r requirements/edx/kernel.in edx-name-affirmation==3.0.1 @@ -809,6 +811,7 @@ openedx-django-pyfs==3.7.0 # via # lti-consumer-xblock # xblock + # xblocks-contrib openedx-django-require==2.1.0 # via -r requirements/edx/kernel.in openedx-django-wiki==2.1.0 @@ -1277,6 +1280,7 @@ xblock[django]==5.1.0 # xblock-drag-and-drop-v2 # xblock-google-drive # xblock-utils + # xblocks-contrib xblock-drag-and-drop-v2==4.0.3 # via -r requirements/edx/bundled.in xblock-google-drive==0.7.0 @@ -1287,6 +1291,8 @@ xblock-utils==4.0.0 # via # edx-sga # xblock-poll +xblocks-contrib==0.1.0 + # via -r requirements/edx/bundled.in xmlsec==1.3.14 # via python3-saml xss-utils==0.6.0 diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index 4e5e4fc6801d..1f65f6c90138 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -568,6 +568,7 @@ django-statici18n==2.5.0 # lti-consumer-xblock # xblock-drag-and-drop-v2 # xblock-poll + # xblocks-contrib django-storages==1.14.3 # via # -c requirements/edx/../constraints.txt @@ -763,6 +764,7 @@ edx-i18n-tools==1.5.0 # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt # ora2 + # xblocks-contrib edx-lint==5.4.1 # via -r requirements/edx/testing.txt edx-milestones==0.6.0 @@ -1362,6 +1364,7 @@ openedx-django-pyfs==3.7.0 # -r requirements/edx/testing.txt # lti-consumer-xblock # xblock + # xblocks-contrib openedx-django-require==2.1.0 # via # -r requirements/edx/doc.txt @@ -2266,6 +2269,7 @@ xblock[django]==5.1.0 # xblock-drag-and-drop-v2 # xblock-google-drive # xblock-utils + # xblocks-contrib xblock-drag-and-drop-v2==4.0.3 # via # -r requirements/edx/doc.txt @@ -2284,6 +2288,10 @@ xblock-utils==4.0.0 # -r requirements/edx/testing.txt # edx-sga # xblock-poll +xblocks-contrib==0.1.0 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt xmlsec==1.3.14 # via # -r requirements/edx/doc.txt diff --git a/requirements/edx/doc.txt b/requirements/edx/doc.txt index 946e31c433de..2388cb4a0e1d 100644 --- a/requirements/edx/doc.txt +++ b/requirements/edx/doc.txt @@ -419,6 +419,7 @@ django-statici18n==2.5.0 # lti-consumer-xblock # xblock-drag-and-drop-v2 # xblock-poll + # xblocks-contrib django-storages==1.14.3 # via # -c requirements/edx/../constraints.txt @@ -564,6 +565,7 @@ edx-i18n-tools==1.5.0 # -c requirements/edx/../constraints.txt # -r requirements/edx/base.txt # ora2 + # xblocks-contrib edx-milestones==0.6.0 # via -r requirements/edx/base.txt edx-name-affirmation==3.0.1 @@ -979,6 +981,7 @@ openedx-django-pyfs==3.7.0 # -r requirements/edx/base.txt # lti-consumer-xblock # xblock + # xblocks-contrib openedx-django-require==2.1.0 # via -r requirements/edx/base.txt openedx-django-wiki==2.1.0 @@ -1585,6 +1588,7 @@ xblock[django]==5.1.0 # xblock-drag-and-drop-v2 # xblock-google-drive # xblock-utils + # xblocks-contrib xblock-drag-and-drop-v2==4.0.3 # via -r requirements/edx/base.txt xblock-google-drive==0.7.0 @@ -1596,6 +1600,8 @@ xblock-utils==4.0.0 # -r requirements/edx/base.txt # edx-sga # xblock-poll +xblocks-contrib==0.1.0 + # via -r requirements/edx/base.txt xmlsec==1.3.14 # via # -r requirements/edx/base.txt diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 3bdd5c6e6f2c..672e70166503 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -445,6 +445,7 @@ django-statici18n==2.5.0 # lti-consumer-xblock # xblock-drag-and-drop-v2 # xblock-poll + # xblocks-contrib django-storages==1.14.3 # via # -c requirements/edx/../constraints.txt @@ -585,6 +586,7 @@ edx-i18n-tools==1.5.0 # -c requirements/edx/../constraints.txt # -r requirements/edx/base.txt # ora2 + # xblocks-contrib edx-lint==5.4.1 # via -r requirements/edx/testing.in edx-milestones==0.6.0 @@ -1024,6 +1026,7 @@ openedx-django-pyfs==3.7.0 # -r requirements/edx/base.txt # lti-consumer-xblock # xblock + # xblocks-contrib openedx-django-require==2.1.0 # via -r requirements/edx/base.txt openedx-django-wiki==2.1.0 @@ -1672,6 +1675,7 @@ xblock[django]==5.1.0 # xblock-drag-and-drop-v2 # xblock-google-drive # xblock-utils + # xblocks-contrib xblock-drag-and-drop-v2==4.0.3 # via -r requirements/edx/base.txt xblock-google-drive==0.7.0 @@ -1683,6 +1687,8 @@ xblock-utils==4.0.0 # -r requirements/edx/base.txt # edx-sga # xblock-poll +xblocks-contrib==0.1.0 + # via -r requirements/edx/base.txt xmlsec==1.3.14 # via # -r requirements/edx/base.txt From efc63c620d765136acadcdfc196db0cbea9c1c5e Mon Sep 17 00:00:00 2001 From: farhan Date: Tue, 19 Nov 2024 13:15:40 +0500 Subject: [PATCH 3/7] chore: add analytics --- lms/djangoapps/courseware/views/views.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py index 88f0ed05ccf7..6e0804db8ca0 100644 --- a/lms/djangoapps/courseware/views/views.py +++ b/lms/djangoapps/courseware/views/views.py @@ -33,6 +33,8 @@ from django.views.generic import View from edx_django_utils.monitoring import set_custom_attribute, set_custom_attributes_for_course_key from ipware.ip import get_client_ip +from xblock.core import XBlock + from lms.djangoapps.static_template_view.views import render_500 from markupsafe import escape from opaque_keys import InvalidKeyError @@ -1562,6 +1564,10 @@ def render_xblock(request, usage_key_string, check_if_enrolled=True, disable_sta set_custom_attributes_for_course_key(course_key) set_custom_attribute('usage_key', usage_key_string) set_custom_attribute('block_type', usage_key.block_type) + block_class = XBlock.load_class(usage_key.block_type) + if hasattr(block_class, 'is_extracted'): + is_extracted = block_class.is_extracted + set_custom_attribute('block_extracted', is_extracted) requested_view = request.GET.get('view', 'student_view') if requested_view != 'student_view' and requested_view != 'public_view': # lint-amnesty, pylint: disable=consider-using-in From 5a8af960f816cc0d39b9a4f2a9a89224a7f13876 Mon Sep 17 00:00:00 2001 From: farhan Date: Tue, 26 Nov 2024 22:25:35 +0500 Subject: [PATCH 4/7] chore: Adds django settings flag impl --- cms/envs/common.py | 10 ++++ lms/envs/common.py | 88 ++++++++++++++++++++++++++++++ xmodule/annotatable_block.py | 14 ++++- xmodule/capa_block.py | 27 +++++---- xmodule/discussion_block.py | 14 ++++- xmodule/html_block.py | 13 ++++- xmodule/lti_block.py | 24 +++++--- xmodule/poll_block.py | 21 +++++-- xmodule/toggles.py | 23 -------- xmodule/video_block/video_block.py | 13 ++++- xmodule/word_cloud_block.py | 16 +++++- 11 files changed, 203 insertions(+), 60 deletions(-) delete mode 100644 xmodule/toggles.py diff --git a/cms/envs/common.py b/cms/envs/common.py index 00a384a359c6..20e99974b3fb 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -122,6 +122,16 @@ # Password Validator Settings AUTH_PASSWORD_VALIDATORS ) +from lms.envs.common import ( + USE_EXTRACTED_WORD_CLOUD_BLOCK, + USE_EXTRACTED_ANNOTATABLE_BLOCK, + USE_EXTRACTED_POLL_QUESTION_BLOCK, + USE_EXTRACTED_LTI_BLOCK, + USE_EXTRACTED_HTML_BLOCK, + USE_EXTRACTED_DISCUSSION_BLOCK, + USE_EXTRACTED_PROBLEM_BLOCK, + USE_EXTRACTED_VIDEO_BLOCK, +) from path import Path as path from django.urls import reverse_lazy diff --git a/lms/envs/common.py b/lms/envs/common.py index d74c28e75687..7d32c78a47b5 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -5558,3 +5558,91 @@ def _should_send_learning_badge_events(settings): LMS_COMM_DEFAULT_FROM_EMAIL = "no-reply@example.com" + + +####################### Setting for built-in Blocks Extraction ####################### +# The following Django settings flags have been introduced temporarily to facilitate +# the rollout of the extracted built-in Blocks. Flags will use to toggle between +# the old and new block quickly without putting course content or user state at risk. +# +# Ticket: https://github.com/openedx/edx-platform/issues/35308 + +# .. toggle_name: USE_EXTRACTED_WORD_CLOUD_BLOCK +# .. toggle_default: False +# .. toggle_implementation: DjangoSetting +# .. toggle_description: Enables the use of the extracted Word Cloud XBlock, which has been shifted to the 'openedx/xblocks-contrib' repo. +# .. toggle_use_cases: temporary +# .. toggle_warning: Not production-ready until https://github.com/openedx/edx-platform/issues/34840 is done. +# .. toggle_creation_date: 2024-11-10 +# .. toggle_target_removal_date: 2025-06-01 +USE_EXTRACTED_WORD_CLOUD_BLOCK = False + +# .. toggle_name: USE_EXTRACTED_ANNOTATABLE_BLOCK +# .. toggle_default: False +# .. toggle_implementation: DjangoSetting +# .. toggle_description: Enables the use of the extracted annotatable XBlock, which has been shifted to the 'openedx/xblocks-contrib' repo. +# .. toggle_use_cases: temporary +# .. toggle_warning: Not production-ready until https://github.com/openedx/edx-platform/issues/34841 is done. +# .. toggle_creation_date: 2024-11-10 +# .. toggle_target_removal_date: 2025-06-01 +USE_EXTRACTED_ANNOTATABLE_BLOCK = False + +# .. toggle_name: USE_EXTRACTED_POLL_QUESTION_BLOCK +# .. toggle_default: False +# .. toggle_implementation: DjangoSetting +# .. toggle_description: Enables the use of the extracted poll question XBlock, which has been shifted to the 'openedx/xblocks-contrib' repo. +# .. toggle_use_cases: temporary +# .. toggle_warning: Not production-ready until https://github.com/openedx/edx-platform/issues/34839 is done. +# .. toggle_creation_date: 2024-11-10 +# .. toggle_target_removal_date: 2025-06-01 +USE_EXTRACTED_POLL_QUESTION_BLOCK = False + +# .. toggle_name: USE_EXTRACTED_LTI_BLOCK +# .. toggle_default: False +# .. toggle_implementation: DjangoSetting +# .. toggle_description: Enables the use of the extracted LTI XBlock, which has been shifted to the 'openedx/xblocks-contrib' repo. +# .. toggle_use_cases: temporary +# .. toggle_warning: Not production-ready until relevant subtask https://github.com/openedx/edx-platform/issues/34827 is done. +# .. toggle_creation_date: 2024-11-10 +# .. toggle_target_removal_date: 2025-06-01 +USE_EXTRACTED_LTI_BLOCK = False + +# .. toggle_name: USE_EXTRACTED_HTML_BLOCK +# .. toggle_default: False +# .. toggle_implementation: DjangoSetting +# .. toggle_description: Enables the use of the extracted HTML XBlock, which has been shifted to the 'openedx/xblocks-contrib' repo. +# .. toggle_use_cases: temporary +# .. toggle_warning: Not production-ready until relevant subtask https://github.com/openedx/edx-platform/issues/34827 is done. +# .. toggle_creation_date: 2024-11-10 +# .. toggle_target_removal_date: 2025-06-01 +USE_EXTRACTED_HTML_BLOCK = False + +# .. toggle_name: USE_EXTRACTED_DISCUSSION_BLOCK +# .. toggle_default: False +# .. toggle_implementation: DjangoSetting +# .. toggle_description: Enables the use of the extracted Discussion XBlock, which has been shifted to the 'openedx/xblocks-contrib' repo. +# .. toggle_use_cases: temporary +# .. toggle_warning: Not production-ready until relevant subtask https://github.com/openedx/edx-platform/issues/34827 is done. +# .. toggle_creation_date: 2024-11-10 +# .. toggle_target_removal_date: 2025-06-01 +USE_EXTRACTED_DISCUSSION_BLOCK = False + +# .. toggle_name: USE_EXTRACTED_PROBLEM_BLOCK +# .. toggle_default: False +# .. toggle_implementation: DjangoSetting +# .. toggle_description: Enables the use of the extracted Problem XBlock, which has been shifted to the 'openedx/xblocks-contrib' repo. +# .. toggle_use_cases: temporary +# .. toggle_warning: Not production-ready until relevant subtask https://github.com/openedx/edx-platform/issues/34827 is done. +# .. toggle_creation_date: 2024-11-10 +# .. toggle_target_removal_date: 2025-06-01 +USE_EXTRACTED_PROBLEM_BLOCK = False + +# .. toggle_name: USE_EXTRACTED_VIDEO_BLOCK +# .. toggle_default: False +# .. toggle_implementation: DjangoSetting +# .. toggle_description: Enables the use of the extracted Video XBlock, which has been shifted to the 'openedx/xblocks-contrib' repo. +# .. toggle_use_cases: temporary +# .. toggle_warning: Not production-ready until relevant subtask https://github.com/openedx/edx-platform/issues/34827 is done. +# .. toggle_creation_date: 2024-11-10 +# .. toggle_target_removal_date: 2025-06-01 +USE_EXTRACTED_VIDEO_BLOCK = False diff --git a/xmodule/annotatable_block.py b/xmodule/annotatable_block.py index cec677f6c5d5..033ec8eb66c2 100644 --- a/xmodule/annotatable_block.py +++ b/xmodule/annotatable_block.py @@ -3,22 +3,24 @@ import logging import textwrap +from django.conf import settings from lxml import etree from web_fragments.fragment import Fragment from xblock.core import XBlock from xblock.fields import Scope, String +from xblocks_contrib.annotatable import AnnotatableBlock as _ExtractedAnnotatableBlock from openedx.core.djangolib.markup import HTML, Text from xmodule.editing_block import EditingMixin from xmodule.raw_block import RawMixin from xmodule.util.builtin_assets import add_webpack_js_to_fragment, add_css_to_fragment -from xmodule.xml_block import XmlMixin from xmodule.x_module import ( ResourceTemplates, shim_xmodule_js, XModuleMixin, XModuleToXBlockMixin, ) +from xmodule.xml_block import XmlMixin log = logging.getLogger(__name__) @@ -28,7 +30,7 @@ @XBlock.needs('mako') -class AnnotatableBlock( +class _BuiltInAnnotatableBlock( RawMixin, XmlMixin, EditingMixin, @@ -40,6 +42,8 @@ class AnnotatableBlock( Annotatable XBlock. """ + is_extracted = False + data = String( help=_("XML data for the annotation"), scope=Scope.content, @@ -197,3 +201,9 @@ def studio_view(self, _context): add_webpack_js_to_fragment(fragment, 'AnnotatableBlockEditor') shim_xmodule_js(fragment, self.studio_js_module_name) return fragment + + +AnnotatableBlock = ( + _ExtractedAnnotatableBlock if settings.USE_EXTRACTED_ANNOTATABLE_BLOCK + else _BuiltInAnnotatableBlock +) diff --git a/xmodule/capa_block.py b/xmodule/capa_block.py index 24737b689845..bf13386ef1c5 100644 --- a/xmodule/capa_block.py +++ b/xmodule/capa_block.py @@ -25,7 +25,14 @@ from xblock.core import XBlock from xblock.fields import Boolean, Dict, Float, Integer, Scope, String, XMLString, List from xblock.scorable import ScorableXBlockMixin, Score +from xblocks_contrib.problem import ProblemBlock as _ExtractedProblemBlock +from common.djangoapps.xblock_django.constants import ( + ATTR_KEY_DEPRECATED_ANONYMOUS_USER_ID, + ATTR_KEY_USER_IS_STAFF, + ATTR_KEY_USER_ID, +) +from openedx.core.djangolib.markup import HTML, Text from xmodule.capa import responsetypes from xmodule.capa.capa_problem import LoncapaProblem, LoncapaSystem from xmodule.capa.inputtypes import Status @@ -36,8 +43,8 @@ from xmodule.exceptions import NotFoundError, ProcessingError from xmodule.graders import ShowCorrectness from xmodule.raw_block import RawMixin -from xmodule.util.sandboxing import SandboxService from xmodule.util.builtin_assets import add_webpack_js_to_fragment, add_css_to_fragment +from xmodule.util.sandboxing import SandboxService from xmodule.x_module import ( ResourceTemplates, XModuleMixin, @@ -45,20 +52,12 @@ shim_xmodule_js ) from xmodule.xml_block import XmlMixin -from common.djangoapps.xblock_django.constants import ( - ATTR_KEY_DEPRECATED_ANONYMOUS_USER_ID, - ATTR_KEY_USER_IS_STAFF, - ATTR_KEY_USER_ID, -) -from openedx.core.djangolib.markup import HTML, Text from .capa.xqueue_interface import XQueueService - from .fields import Date, ListScoreField, ScoreField, Timedelta from .progress import Progress log = logging.getLogger("edx.courseware") - # Make '_' a no-op so we can scrape strings. Using lambda instead of # `django.utils.translation.gettext_noop` because Django cannot be imported in this file _ = lambda text: text @@ -134,7 +133,7 @@ def from_json(self, value): @XBlock.needs('sandbox') @XBlock.needs('replace_urls') @XBlock.wants('call_to_action') -class ProblemBlock( +class _BuiltInProblemBlock( ScorableXBlockMixin, RawMixin, XmlMixin, @@ -161,6 +160,8 @@ class ProblemBlock( """ INDEX_CONTENT_TYPE = 'CAPA' + is_extracted = False + resources_dir = None has_score = True @@ -2509,3 +2510,9 @@ def randomization_bin(seed, problem_id): r_hash.update(str(problem_id).encode()) # get the first few digits of the hash, convert to an int, then mod. return int(r_hash.hexdigest()[:7], 16) % NUM_RANDOMIZATION_BINS + + +ProblemBlock = ( + _ExtractedProblemBlock if settings.USE_EXTRACTED_PROBLEM_BLOCK + else _BuiltInProblemBlock +) diff --git a/xmodule/discussion_block.py b/xmodule/discussion_block.py index 89e573c07c83..d1ae1bfdc38f 100644 --- a/xmodule/discussion_block.py +++ b/xmodule/discussion_block.py @@ -4,7 +4,7 @@ import logging import urllib - +from django.conf import settings from django.contrib.staticfiles.storage import staticfiles_storage from django.urls import reverse from django.utils.translation import get_language_bidi @@ -14,6 +14,7 @@ from xblock.fields import UNIQUE_ID, Scope, String from xblock.utils.resources import ResourceLoader from xblock.utils.studio_editable import StudioEditableXBlockMixin +from xblocks_contrib.discussion import DiscussionXBlock as _ExtractedDiscussionXBlock from lms.djangoapps.discussion.django_comment_client.permissions import has_permission from openedx.core.djangoapps.discussions.models import DiscussionsConfiguration, Provider @@ -21,7 +22,6 @@ from openedx.core.lib.xblock_utils import get_css_dependencies, get_js_dependencies from xmodule.xml_block import XmlMixin - log = logging.getLogger(__name__) loader = ResourceLoader(__name__) # pylint: disable=invalid-name @@ -36,10 +36,12 @@ def _(text): @XBlock.needs('user') # pylint: disable=abstract-method @XBlock.needs('i18n') @XBlock.needs('mako') -class DiscussionXBlock(XBlock, StudioEditableXBlockMixin, XmlMixin): # lint-amnesty, pylint: disable=abstract-method +class _BuiltInDiscussionXBlock(XBlock, StudioEditableXBlockMixin, + XmlMixin): # lint-amnesty, pylint: disable=abstract-method """ Provides a discussion forum that is inline with other content in the courseware. """ + is_extracted = False completion_mode = XBlockCompletionMode.EXCLUDED discussion_id = String(scope=Scope.settings, default=UNIQUE_ID) @@ -275,3 +277,9 @@ def _apply_metadata_and_policy(cls, block, node, runtime): for field_name, value in metadata.items(): if field_name in block.fields: setattr(block, field_name, value) + + +DiscussionXBlock = ( + _ExtractedDiscussionXBlock if settings.USE_EXTRACTED_DISCUSSION_BLOCK + else _BuiltInDiscussionXBlock +) diff --git a/xmodule/html_block.py b/xmodule/html_block.py index 62949647cee3..c819d657cfe9 100644 --- a/xmodule/html_block.py +++ b/xmodule/html_block.py @@ -15,6 +15,7 @@ from web_fragments.fragment import Fragment from xblock.core import XBlock from xblock.fields import Boolean, List, Scope, String +from xblocks_contrib.html import HtmlBlock as _ExtractedHtmlBlock from common.djangoapps.xblock_django.constants import ATTR_KEY_DEPRECATED_ANONYMOUS_USER_ID from xmodule.contentstore.content import StaticContent @@ -22,8 +23,8 @@ from xmodule.edxnotes_utils import edxnotes from xmodule.html_checker import check_html from xmodule.stringify import stringify_children -from xmodule.util.misc import escape_html_characters from xmodule.util.builtin_assets import add_webpack_js_to_fragment, add_css_to_fragment +from xmodule.util.misc import escape_html_characters from xmodule.x_module import ( ResourceTemplates, shim_xmodule_js, @@ -50,6 +51,8 @@ class HtmlBlockMixin( # lint-amnesty, pylint: disable=abstract-method The HTML XBlock mixin. This provides the base class for all Html-ish blocks (including the HTML XBlock). """ + is_extracted = False + display_name = String( display_name=_("Display Name"), help=_("The display name for this component."), @@ -353,7 +356,7 @@ def index_dictionary(self): @edxnotes -class HtmlBlock(HtmlBlockMixin): # lint-amnesty, pylint: disable=abstract-method +class _BuiltInHtmlBlock(HtmlBlockMixin): # lint-amnesty, pylint: disable=abstract-method """ This is the actual HTML XBlock. Nothing extra is required; this is just a wrapper to include edxnotes support. @@ -489,3 +492,9 @@ def safe_parse_date(date): return datetime.strptime(date, '%B %d, %Y') except ValueError: # occurs for ill-formatted date values return datetime.today() + + +HtmlBlock = ( + _ExtractedHtmlBlock if settings.USE_EXTRACTED_HTML_BLOCK + else _BuiltInHtmlBlock +) diff --git a/xmodule/lti_block.py b/xmodule/lti_block.py index e7c173075b4e..7bea50bd6639 100644 --- a/xmodule/lti_block.py +++ b/xmodule/lti_block.py @@ -59,9 +59,9 @@ import hashlib import logging import textwrap -from xml.sax.saxutils import escape from unittest import mock from urllib import parse +from xml.sax.saxutils import escape import nh3 import oauthlib.oauth1 @@ -69,30 +69,29 @@ from lxml import etree from oauthlib.oauth1.rfc5849 import signature from pytz import UTC -from webob import Response from web_fragments.fragment import Fragment +from webob import Response from xblock.core import List, Scope, String, XBlock from xblock.fields import Boolean, Float -from xmodule.mako_block import MakoTemplateBlockBase - -from openedx.core.djangolib.markup import HTML, Text -from xmodule.editing_block import EditingMixin +from xblocks_contrib.lti import LTIBlock as _ExtractedLTIBlock from common.djangoapps.xblock_django.constants import ( ATTR_KEY_ANONYMOUS_USER_ID, ATTR_KEY_USER_ROLE, ) +from openedx.core.djangolib.markup import HTML, Text +from xmodule.editing_block import EditingMixin from xmodule.lti_2_util import LTI20BlockMixin, LTIError +from xmodule.mako_block import MakoTemplateBlockBase from xmodule.raw_block import EmptyDataRawMixin from xmodule.util.builtin_assets import add_webpack_js_to_fragment, add_css_to_fragment -from xmodule.xml_block import XmlMixin from xmodule.x_module import ( ResourceTemplates, shim_xmodule_js, XModuleMixin, XModuleToXBlockMixin, ) - +from xmodule.xml_block import XmlMixin log = logging.getLogger(__name__) @@ -274,7 +273,7 @@ class LTIFields: @XBlock.needs("mako") @XBlock.needs("user") @XBlock.needs("rebind_user") -class LTIBlock( +class _BuiltInLTIBlock( LTIFields, LTI20BlockMixin, EmptyDataRawMixin, @@ -366,6 +365,7 @@ class LTIBlock( Otherwise error message from LTI provider is generated. """ + is_extracted = False resources_dir = None uses_xmodule_styles_setup = True @@ -984,3 +984,9 @@ def is_past_due(self): else: close_date = due_date return close_date is not None and datetime.datetime.now(UTC) > close_date + + +LTIBlock = ( + _ExtractedLTIBlock if settings.USE_EXTRACTED_LTI_BLOCK + else _BuiltInLTIBlock +) diff --git a/xmodule/poll_block.py b/xmodule/poll_block.py index a1c9686f42ac..981ed7169f5e 100644 --- a/xmodule/poll_block.py +++ b/xmodule/poll_block.py @@ -6,18 +6,19 @@ If student have answered - Question with statistics for each answers. """ - import html import json import logging -from collections import OrderedDict from copy import deepcopy -from web_fragments.fragment import Fragment - +from collections import OrderedDict +from django.conf import settings from lxml import etree +from web_fragments.fragment import Fragment from xblock.core import XBlock from xblock.fields import Boolean, Dict, List, Scope, String # lint-amnesty, pylint: disable=wrong-import-order +from xblocks_contrib.poll import PollBlock as _ExtractedPollBlock + from openedx.core.djangolib.markup import Text, HTML from xmodule.mako_block import MakoTemplateBlockBase from xmodule.stringify import stringify_children @@ -30,13 +31,12 @@ ) from xmodule.xml_block import XmlMixin - log = logging.getLogger(__name__) _ = lambda text: text @XBlock.needs('mako') -class PollBlock( +class _BuiltInPollBlock( MakoTemplateBlockBase, XmlMixin, XModuleToXBlockMixin, @@ -44,6 +44,9 @@ class PollBlock( XModuleMixin, ): # pylint: disable=abstract-method """Poll Block""" + + is_extracted = False + # Name of poll to use in links to this poll display_name = String( help=_("The display name for this component."), @@ -244,3 +247,9 @@ def add_child(xml_obj, answer): # lint-amnesty, pylint: disable=unused-argument add_child(xml_object, answer) return xml_object + + +PollBlock = ( + _ExtractedPollBlock if settings.USE_EXTRACTED_POLL_QUESTION_BLOCK + else _BuiltInPollBlock +) diff --git a/xmodule/toggles.py b/xmodule/toggles.py deleted file mode 100644 index 7fc1fc774bfe..000000000000 --- a/xmodule/toggles.py +++ /dev/null @@ -1,23 +0,0 @@ -""" -Add Waffle flags to roll out the extracted XBlocks. -Flags will use to toggle between the old and new block quickly -without putting course content or user state at risk. - -Ticket: https://github.com/openedx/edx-platform/issues/35308 -""" -from edx_toggles.toggles import WaffleFlag - -# .. toggle_name: USE_EXTRACTED_WORD_CLOUD_BLOCK -# .. toggle_description: Enables the use of the extracted Word Cloud XBlock, which has been shifted to the 'openedx/xblocks-contrib' repo. -# .. toggle_warning: Not production-ready until https://github.com/openedx/edx-platform/issues/34840 is done. -# .. toggle_use_cases: temporary -# .. toggle_default: False -USE_EXTRACTED_WORD_CLOUD_BLOCK = WaffleFlag('xmodule.use_extracted_block.word_cloud', __name__) -# TODO: Add flag docs once above approved -USE_EXTRACTED_ANNOTATABLE_BLOCK = WaffleFlag('xmodule.use_extracted_block.annotatable', __name__) -USE_EXTRACTED_POLL_BLOCK = WaffleFlag('xmodule.use_extracted_block.poll', __name__) -USE_EXTRACTED_LTI_BLOCK = WaffleFlag('xmodule.use_extracted_block.lti', __name__) -USE_EXTRACTED_HTML_BLOCK = WaffleFlag('xmodule.use_extracted_block.html', __name__) -USE_EXTRACTED_DISCUSSION_BLOCK = WaffleFlag('xmodule.use_extracted_block.discussion', __name__) -USE_EXTRACTED_PROBLEM_BLOCK = WaffleFlag('xmodule.use_extracted_block.problem', __name__) -USE_EXTRACTED_VIDEO_BLOCK = WaffleFlag('xmodule.use_extracted_block.video', __name__) diff --git a/xmodule/video_block/video_block.py b/xmodule/video_block/video_block.py index ea9d1a44280a..6961a26ea175 100644 --- a/xmodule/video_block/video_block.py +++ b/xmodule/video_block/video_block.py @@ -29,6 +29,7 @@ from xblock.core import XBlock from xblock.fields import ScopeIds from xblock.runtime import KvsFieldData +from xblocks_contrib.video import VideoBlock as _ExtractedVideoBlock from common.djangoapps.xblock_django.constants import ATTR_KEY_REQUEST_COUNTRY_CODE, ATTR_KEY_USER_ID from openedx.core.djangoapps.video_config.models import HLSPlaybackEnabledFlag, CourseYoutubeBlockedFlag @@ -47,8 +48,8 @@ from xmodule.mako_block import MakoTemplateBlockBase from xmodule.modulestore.inheritance import InheritanceKeyValueStore, own_metadata from xmodule.raw_block import EmptyDataRawMixin +from xmodule.util.builtin_assets import add_css_to_fragment, add_webpack_js_to_fragment from xmodule.validation import StudioValidation, StudioValidationMessage -from xmodule.util.builtin_assets import add_webpack_js_to_fragment, add_css_to_fragment from xmodule.video_block import manage_video_subtitles_save from xmodule.x_module import ( PUBLIC_VIEW, STUDENT_VIEW, @@ -56,7 +57,6 @@ XModuleMixin, XModuleToXBlockMixin, ) from xmodule.xml_block import XmlMixin, deserialize_field, is_pointer_tag, name_to_pathname - from .bumper_utils import bumperize from .sharing_sites import sharing_sites_info_for_video from .transcripts_utils import ( @@ -119,7 +119,7 @@ @XBlock.wants('settings', 'completion', 'i18n', 'request_cache') @XBlock.needs('mako', 'user') -class VideoBlock( +class _BuiltInVideoBlock( VideoFields, VideoTranscriptsMixin, VideoStudioViewHandlers, VideoStudentViewHandlers, EmptyDataRawMixin, XmlMixin, EditingMixin, XModuleToXBlockMixin, ResourceTemplates, XModuleMixin, LicenseMixin): @@ -134,6 +134,7 @@ class VideoBlock( """ + is_extracted = False has_custom_completion = True completion_mode = XBlockCompletionMode.COMPLETABLE @@ -1260,3 +1261,9 @@ def _poster(self): edx_video_id=self.edx_video_id.strip() ) return None + + +VideoBlock = ( + _ExtractedVideoBlock if settings.USE_EXTRACTED_VIDEO_BLOCK + else _BuiltInVideoBlock +) diff --git a/xmodule/word_cloud_block.py b/xmodule/word_cloud_block.py index d678f2a9a9f5..dae67175d5de 100644 --- a/xmodule/word_cloud_block.py +++ b/xmodule/word_cloud_block.py @@ -6,23 +6,27 @@ If student have answered - words he entered and cloud. """ +from xblocks_contrib.word_cloud import WordCloudBlock as _ExtractedWordCloudBlock import json import logging +from django.conf import settings from web_fragments.fragment import Fragment from xblock.core import XBlock from xblock.fields import Boolean, Dict, Integer, List, Scope, String + from xmodule.editing_block import EditingMixin from xmodule.raw_block import EmptyDataRawMixin from xmodule.util.builtin_assets import add_webpack_js_to_fragment, add_css_to_fragment -from xmodule.xml_block import XmlMixin from xmodule.x_module import ( ResourceTemplates, shim_xmodule_js, XModuleMixin, XModuleToXBlockMixin, ) +from xmodule.xml_block import XmlMixin + log = logging.getLogger(__name__) # Make '_' a no-op so we can scrape strings. Using lambda instead of @@ -41,7 +45,7 @@ def pretty_bool(value): @XBlock.needs('mako') -class WordCloudBlock( # pylint: disable=abstract-method +class _BuiltInWordCloudBlock( # pylint: disable=abstract-method EmptyDataRawMixin, XmlMixin, EditingMixin, @@ -53,6 +57,8 @@ class WordCloudBlock( # pylint: disable=abstract-method Word Cloud XBlock. """ + is_extracted = False + display_name = String( display_name=_("Display Name"), help=_("The display name for this component."), @@ -308,3 +314,9 @@ def index_dictionary(self): xblock_body["content_type"] = "Word Cloud" return xblock_body + + +WordCloudBlock = ( + _ExtractedWordCloudBlock if settings.USE_EXTRACTED_WORD_CLOUD_BLOCK + else _BuiltInWordCloudBlock +) From f413dc5be2304107c3ae4cf79df77707968cb8e6 Mon Sep 17 00:00:00 2001 From: farhan Date: Tue, 26 Nov 2024 22:26:05 +0500 Subject: [PATCH 5/7] chore: fix test cases --- lms/djangoapps/courseware/tests/test_block_render.py | 9 +++++---- xmodule/tests/test_vertical.py | 5 +++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lms/djangoapps/courseware/tests/test_block_render.py b/lms/djangoapps/courseware/tests/test_block_render.py index 182f8d0c03ab..3b4334335a6f 100644 --- a/lms/djangoapps/courseware/tests/test_block_render.py +++ b/lms/djangoapps/courseware/tests/test_block_render.py @@ -1550,8 +1550,8 @@ def test_xblock_display_wrapper_enabled(self): wrap_xblock_display=True, ) result_fragment = block.render(STUDENT_VIEW) - - assert len(PyQuery(result_fragment.content)('div.xblock.xblock-student_view.xmodule_HtmlBlock')) == 1 + html_block_identifier = f"div.xblock.xblock-student_view.xmodule_{HtmlBlock.__name__}" + assert len(PyQuery(result_fragment.content)(html_block_identifier)) == 1 def test_xmodule_display_wrapper_disabled(self): block = render.get_block( @@ -2573,11 +2573,12 @@ def test_get_item(self): def test_dynamic_updates(self): """Tests that the list of disabled xblocks can dynamically update.""" course = CourseFactory() - item_usage_id = self._verify_block('problem', course, 'ProblemBlockWithMixins') + block = f"{ProblemBlock.__name__}WithMixins" + item_usage_id = self._verify_block('problem', course, block) XBlockConfiguration(name='problem', enabled=False).save() # First verify that the cached value is used until there is a new request cache. - self._verify_block('problem', course, 'ProblemBlockWithMixins', item_usage_id) + self._verify_block('problem', course, block, item_usage_id) # Now simulate a new request cache. self.store.request_cache.data.clear() diff --git a/xmodule/tests/test_vertical.py b/xmodule/tests/test_vertical.py index a3c596d253ac..426569f1ab11 100644 --- a/xmodule/tests/test_vertical.py +++ b/xmodule/tests/test_vertical.py @@ -18,6 +18,7 @@ from openedx_filters import PipelineStep from openedx_filters.learning.filters import VerticalBlockChildRenderStarted, VerticalBlockRenderCompleted +from ..html_block import HtmlBlock from ..x_module import AUTHOR_VIEW, PUBLIC_VIEW, STUDENT_VIEW from . import prepare_block_runtime from .helpers import StubUserService @@ -89,7 +90,7 @@ class TestVerticalBlockChildRenderStep(PipelineStep): def run_filter(self, block, context): # lint-amnesty, pylint: disable=arguments-differ """Pipeline step that changes child content""" - if type(block).__name__ == "HtmlBlockWithMixins": + if type(block).__name__ == f"{HtmlBlock.__name__}WithMixins": block.get_html = lambda: TestVerticalBlockChildRenderStep.filter_content return {"block": block, "context": context} @@ -101,7 +102,7 @@ class TestPreventVerticalBlockChildRender(PipelineStep): def run_filter(self, block, context): # lint-amnesty, pylint: disable=arguments-differ """Pipeline step that raises exceptions during child block rendering""" - if type(block).__name__ == "HtmlBlockWithMixins": + if type(block).__name__ == f"{HtmlBlock.__name__}WithMixins": raise VerticalBlockChildRenderStarted.PreventChildBlockRender( "Skip block test exception" ) From 1ffb7fe1eae102a58340dd3c09c3134fd864f353 Mon Sep 17 00:00:00 2001 From: farhan Date: Tue, 26 Nov 2024 22:45:41 +0500 Subject: [PATCH 6/7] chore: change class name defining strategy for fix test cases --- xmodule/annotatable_block.py | 1 + xmodule/capa_block.py | 1 + xmodule/discussion_block.py | 1 + xmodule/html_block.py | 3 ++- xmodule/lti_block.py | 1 + xmodule/poll_block.py | 1 + xmodule/video_block/video_block.py | 1 + xmodule/word_cloud_block.py | 1 + 8 files changed, 9 insertions(+), 1 deletion(-) diff --git a/xmodule/annotatable_block.py b/xmodule/annotatable_block.py index 033ec8eb66c2..dbcf0123c59a 100644 --- a/xmodule/annotatable_block.py +++ b/xmodule/annotatable_block.py @@ -207,3 +207,4 @@ def studio_view(self, _context): _ExtractedAnnotatableBlock if settings.USE_EXTRACTED_ANNOTATABLE_BLOCK else _BuiltInAnnotatableBlock ) +AnnotatableBlock.__name__ = "AnnotatableBlock" diff --git a/xmodule/capa_block.py b/xmodule/capa_block.py index bf13386ef1c5..fa0e87325bb7 100644 --- a/xmodule/capa_block.py +++ b/xmodule/capa_block.py @@ -2516,3 +2516,4 @@ def randomization_bin(seed, problem_id): _ExtractedProblemBlock if settings.USE_EXTRACTED_PROBLEM_BLOCK else _BuiltInProblemBlock ) +ProblemBlock.__name__ = "ProblemBlock" diff --git a/xmodule/discussion_block.py b/xmodule/discussion_block.py index d1ae1bfdc38f..79914b63d6b2 100644 --- a/xmodule/discussion_block.py +++ b/xmodule/discussion_block.py @@ -283,3 +283,4 @@ def _apply_metadata_and_policy(cls, block, node, runtime): _ExtractedDiscussionXBlock if settings.USE_EXTRACTED_DISCUSSION_BLOCK else _BuiltInDiscussionXBlock ) +DiscussionXBlock.__name__ = "DiscussionXBlock" diff --git a/xmodule/html_block.py b/xmodule/html_block.py index c819d657cfe9..9840c3007f92 100644 --- a/xmodule/html_block.py +++ b/xmodule/html_block.py @@ -51,7 +51,6 @@ class HtmlBlockMixin( # lint-amnesty, pylint: disable=abstract-method The HTML XBlock mixin. This provides the base class for all Html-ish blocks (including the HTML XBlock). """ - is_extracted = False display_name = String( display_name=_("Display Name"), @@ -361,6 +360,7 @@ class _BuiltInHtmlBlock(HtmlBlockMixin): # lint-amnesty, pylint: disable=abstra This is the actual HTML XBlock. Nothing extra is required; this is just a wrapper to include edxnotes support. """ + is_extracted = False class AboutFields: # lint-amnesty, pylint: disable=missing-class-docstring @@ -498,3 +498,4 @@ def safe_parse_date(date): _ExtractedHtmlBlock if settings.USE_EXTRACTED_HTML_BLOCK else _BuiltInHtmlBlock ) +HtmlBlock.__name__ = "HtmlBlock" diff --git a/xmodule/lti_block.py b/xmodule/lti_block.py index 7bea50bd6639..944a7ec88db0 100644 --- a/xmodule/lti_block.py +++ b/xmodule/lti_block.py @@ -990,3 +990,4 @@ def is_past_due(self): _ExtractedLTIBlock if settings.USE_EXTRACTED_LTI_BLOCK else _BuiltInLTIBlock ) +LTIBlock.__name__ = "LTIBlock" diff --git a/xmodule/poll_block.py b/xmodule/poll_block.py index 981ed7169f5e..b8c65f1cdba8 100644 --- a/xmodule/poll_block.py +++ b/xmodule/poll_block.py @@ -253,3 +253,4 @@ def add_child(xml_obj, answer): # lint-amnesty, pylint: disable=unused-argument _ExtractedPollBlock if settings.USE_EXTRACTED_POLL_QUESTION_BLOCK else _BuiltInPollBlock ) +PollBlock.__name__ = "PollBlock" diff --git a/xmodule/video_block/video_block.py b/xmodule/video_block/video_block.py index 6961a26ea175..84d7edcf7263 100644 --- a/xmodule/video_block/video_block.py +++ b/xmodule/video_block/video_block.py @@ -1267,3 +1267,4 @@ def _poster(self): _ExtractedVideoBlock if settings.USE_EXTRACTED_VIDEO_BLOCK else _BuiltInVideoBlock ) +VideoBlock.__name__ = "VideoBlock" diff --git a/xmodule/word_cloud_block.py b/xmodule/word_cloud_block.py index dae67175d5de..37e82400df78 100644 --- a/xmodule/word_cloud_block.py +++ b/xmodule/word_cloud_block.py @@ -320,3 +320,4 @@ def index_dictionary(self): _ExtractedWordCloudBlock if settings.USE_EXTRACTED_WORD_CLOUD_BLOCK else _BuiltInWordCloudBlock ) +WordCloudBlock.__name__ = "WordCloudBlock" From 4360d9b89164e50fbfb73f3e1bff27942b6d1206 Mon Sep 17 00:00:00 2001 From: farhan Date: Wed, 27 Nov 2024 12:52:22 +0500 Subject: [PATCH 7/7] Revert "chore: fix test cases" This reverts commit 948922c0e43b3ff7a31f1efbde6abf50c42ca0c9. --- lms/djangoapps/courseware/tests/test_block_render.py | 9 ++++----- xmodule/tests/test_vertical.py | 5 ++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/lms/djangoapps/courseware/tests/test_block_render.py b/lms/djangoapps/courseware/tests/test_block_render.py index 3b4334335a6f..182f8d0c03ab 100644 --- a/lms/djangoapps/courseware/tests/test_block_render.py +++ b/lms/djangoapps/courseware/tests/test_block_render.py @@ -1550,8 +1550,8 @@ def test_xblock_display_wrapper_enabled(self): wrap_xblock_display=True, ) result_fragment = block.render(STUDENT_VIEW) - html_block_identifier = f"div.xblock.xblock-student_view.xmodule_{HtmlBlock.__name__}" - assert len(PyQuery(result_fragment.content)(html_block_identifier)) == 1 + + assert len(PyQuery(result_fragment.content)('div.xblock.xblock-student_view.xmodule_HtmlBlock')) == 1 def test_xmodule_display_wrapper_disabled(self): block = render.get_block( @@ -2573,12 +2573,11 @@ def test_get_item(self): def test_dynamic_updates(self): """Tests that the list of disabled xblocks can dynamically update.""" course = CourseFactory() - block = f"{ProblemBlock.__name__}WithMixins" - item_usage_id = self._verify_block('problem', course, block) + item_usage_id = self._verify_block('problem', course, 'ProblemBlockWithMixins') XBlockConfiguration(name='problem', enabled=False).save() # First verify that the cached value is used until there is a new request cache. - self._verify_block('problem', course, block, item_usage_id) + self._verify_block('problem', course, 'ProblemBlockWithMixins', item_usage_id) # Now simulate a new request cache. self.store.request_cache.data.clear() diff --git a/xmodule/tests/test_vertical.py b/xmodule/tests/test_vertical.py index 426569f1ab11..a3c596d253ac 100644 --- a/xmodule/tests/test_vertical.py +++ b/xmodule/tests/test_vertical.py @@ -18,7 +18,6 @@ from openedx_filters import PipelineStep from openedx_filters.learning.filters import VerticalBlockChildRenderStarted, VerticalBlockRenderCompleted -from ..html_block import HtmlBlock from ..x_module import AUTHOR_VIEW, PUBLIC_VIEW, STUDENT_VIEW from . import prepare_block_runtime from .helpers import StubUserService @@ -90,7 +89,7 @@ class TestVerticalBlockChildRenderStep(PipelineStep): def run_filter(self, block, context): # lint-amnesty, pylint: disable=arguments-differ """Pipeline step that changes child content""" - if type(block).__name__ == f"{HtmlBlock.__name__}WithMixins": + if type(block).__name__ == "HtmlBlockWithMixins": block.get_html = lambda: TestVerticalBlockChildRenderStep.filter_content return {"block": block, "context": context} @@ -102,7 +101,7 @@ class TestPreventVerticalBlockChildRender(PipelineStep): def run_filter(self, block, context): # lint-amnesty, pylint: disable=arguments-differ """Pipeline step that raises exceptions during child block rendering""" - if type(block).__name__ == f"{HtmlBlock.__name__}WithMixins": + if type(block).__name__ == "HtmlBlockWithMixins": raise VerticalBlockChildRenderStarted.PreventChildBlockRender( "Skip block test exception" )