diff --git a/cms/djangoapps/contentstore/views/preview.py b/cms/djangoapps/contentstore/views/preview.py
index 92cba7a16e..5689ef558a 100644
--- a/cms/djangoapps/contentstore/views/preview.py
+++ b/cms/djangoapps/contentstore/views/preview.py
@@ -188,7 +188,7 @@ def _preview_module_system(request, descriptor, field_data):
mako_service = MakoService(namespace_prefix='lms.')
if settings.FEATURES.get("LICENSING", False):
# stick the license wrapper in front
- wrappers.insert(0, wrap_with_license)
+ wrappers.insert(0, partial(wrap_with_license, mako_service=mako_service))
return PreviewModuleSystem(
static_url=settings.STATIC_URL,
diff --git a/cms/lib/xblock/authoring_mixin.py b/cms/lib/xblock/authoring_mixin.py
index 39f8f10628..342c5ff054 100644
--- a/cms/lib/xblock/authoring_mixin.py
+++ b/cms/lib/xblock/authoring_mixin.py
@@ -39,7 +39,7 @@ class AuthoringMixin(XBlockMixin):
"""
fragment = Fragment()
from cms.djangoapps.contentstore.utils import reverse_course_url
- fragment.add_content(self.system.render_template('visibility_editor.html', {
+ fragment.add_content(self.runtime.service(self, 'mako').render_template('visibility_editor.html', {
'xblock': self,
'manage_groups_url': reverse_course_url('group_configurations_list_handler', self.location.course_key),
}))
diff --git a/common/lib/xmodule/xmodule/annotatable_module.py b/common/lib/xmodule/xmodule/annotatable_module.py
index 1c7a80122b..e07f81231d 100644
--- a/common/lib/xmodule/xmodule/annotatable_module.py
+++ b/common/lib/xmodule/xmodule/annotatable_module.py
@@ -6,6 +6,7 @@ import textwrap
from lxml import etree
from pkg_resources import resource_string
from web_fragments.fragment import Fragment
+from xblock.core import XBlock
from xblock.fields import Scope, String
from openedx.core.djangolib.markup import HTML, Text
@@ -29,6 +30,7 @@ log = logging.getLogger(__name__)
_ = lambda text: text
+@XBlock.needs('mako')
class AnnotatableBlock(
RawMixin,
XmlMixin,
@@ -201,7 +203,7 @@ class AnnotatableBlock(
'content_html': self._render_content()
}
- return self.system.render_template('annotatable.html', context)
+ return self.runtime.service(self, 'mako').render_template('annotatable.html', context)
def student_view(self, context): # lint-amnesty, pylint: disable=unused-argument
"""
@@ -219,7 +221,7 @@ class AnnotatableBlock(
Return the studio view.
"""
fragment = Fragment(
- self.system.render_template(self.mako_template, self.get_context())
+ self.runtime.service(self, 'mako').render_template(self.mako_template, self.get_context())
)
add_webpack_to_fragment(fragment, 'AnnotatableBlockStudio')
shim_xmodule_js(fragment, self.studio_js_module_name)
diff --git a/common/lib/xmodule/xmodule/capa_module.py b/common/lib/xmodule/xmodule/capa_module.py
index 25a133d19e..26a42d59d6 100644
--- a/common/lib/xmodule/xmodule/capa_module.py
+++ b/common/lib/xmodule/xmodule/capa_module.py
@@ -120,6 +120,7 @@ class Randomization(String):
@XBlock.needs('user')
@XBlock.needs('i18n')
+@XBlock.needs('mako')
@XBlock.wants('call_to_action')
class ProblemBlock(
ScorableXBlockMixin,
@@ -392,7 +393,7 @@ class ProblemBlock(
Return the studio view.
"""
fragment = Fragment(
- self.system.render_template(self.mako_template, self.get_context())
+ self.runtime.service(self, 'mako').render_template(self.mako_template, self.get_context())
)
add_webpack_to_fragment(fragment, 'ProblemBlockStudio')
shim_xmodule_js(fragment, 'MarkdownEditingDescriptor')
@@ -821,7 +822,7 @@ class ProblemBlock(
filestore=self.runtime.filestore,
i18n=self.runtime.service(self, "i18n"),
node_path=self.runtime.node_path,
- render_template=self.runtime.render_template,
+ render_template=self.runtime.service(self, 'mako').render_template,
seed=seed, # Why do we do this if we have self.seed?
STATIC_URL=self.runtime.STATIC_URL,
xqueue=self.runtime.xqueue,
@@ -915,7 +916,7 @@ class ProblemBlock(
"""
curr_score, total_possible = self.get_display_progress()
- return self.runtime.render_template('problem_ajax.html', {
+ return self.runtime.service(self, 'mako').render_template('problem_ajax.html', {
'element_id': self.location.html_id(),
'id': str(self.location),
'ajax_url': self.ajax_url,
@@ -1263,7 +1264,7 @@ class ProblemBlock(
'submit_disabled_cta': submit_disabled_ctas[0] if submit_disabled_ctas else None,
}
- html = self.runtime.render_template('problem.html', context)
+ html = self.runtime.service(self, 'mako').render_template('problem.html', context)
if encapsulate:
html = HTML('
{html}
').format(
@@ -1573,7 +1574,7 @@ class ProblemBlock(
return {
'answers': new_answers,
- 'correct_status_html': self.runtime.render_template(
+ 'correct_status_html': self.runtime.service(self, 'mako').render_template(
'status_span.html',
{'status': Status('correct', self.runtime.service(self, "i18n").ugettext)}
)
diff --git a/common/lib/xmodule/xmodule/conditional_module.py b/common/lib/xmodule/xmodule/conditional_module.py
index 8a2d50c63b..3605f36bf8 100644
--- a/common/lib/xmodule/xmodule/conditional_module.py
+++ b/common/lib/xmodule/xmodule/conditional_module.py
@@ -11,6 +11,7 @@ from lxml import etree
from opaque_keys.edx.locator import BlockUsageLocator
from pkg_resources import resource_string
from web_fragments.fragment import Fragment
+from xblock.core import XBlock
from xblock.fields import ReferenceList, Scope, String
from openedx.core.djangolib.markup import HTML, Text
@@ -38,6 +39,7 @@ log = logging.getLogger('edx.' + __name__)
_ = lambda text: text
+@XBlock.needs('mako')
class ConditionalBlock(
SequenceMixin,
MakoTemplateBlockBase,
@@ -245,7 +247,7 @@ class ConditionalBlock(
def get_html(self):
required_html_ids = [descriptor.location.html_id() for descriptor in self.get_required_blocks]
- return self.system.render_template('conditional_ajax.html', {
+ return self.runtime.service(self, 'mako').render_template('conditional_ajax.html', {
'element_id': self.location.html_id(),
'ajax_url': self.ajax_url,
'depends': ';'.join(required_html_ids)
@@ -271,7 +273,7 @@ class ConditionalBlock(
Return the studio view.
"""
fragment = Fragment(
- self.system.render_template(self.mako_template, self.get_context())
+ self.runtime.service(self, 'mako').render_template(self.mako_template, self.get_context())
)
add_webpack_to_fragment(fragment, 'ConditionalBlockStudio')
shim_xmodule_js(fragment, self.studio_js_module_name)
@@ -284,8 +286,7 @@ class ConditionalBlock(
if not self.is_condition_satisfied():
context = {'module': self,
'message': self.conditional_message}
- html = self.system.render_template('conditional_module.html',
- context)
+ html = self.runtime.service(self, 'mako').render_template('conditional_module.html', context)
return json.dumps({'fragments': [{'content': html}], 'message': bool(self.conditional_message)})
fragments = [child.render(STUDENT_VIEW).to_dict() for child in self.get_display_items()]
diff --git a/common/lib/xmodule/xmodule/error_module.py b/common/lib/xmodule/xmodule/error_module.py
index 2cefcc9da9..a96631954e 100644
--- a/common/lib/xmodule/xmodule/error_module.py
+++ b/common/lib/xmodule/xmodule/error_module.py
@@ -11,6 +11,7 @@ import sys
from lxml import etree
from web_fragments.fragment import Fragment
+from xblock.core import XBlock
from xblock.field_data import DictFieldData
from xblock.fields import Scope, ScopeIds, String
@@ -43,6 +44,7 @@ class ErrorFields:
display_name = String(scope=Scope.settings)
+@XBlock.needs('mako')
class ErrorBlock(
ErrorFields,
XModuleDescriptorToXBlockMixin,
@@ -62,7 +64,7 @@ class ErrorBlock(
"""
Return a fragment that contains the html for the student view.
"""
- fragment = Fragment(self.system.render_template('module-error.html', {
+ fragment = Fragment(self.runtime.service(self, 'mako').render_template('module-error.html', {
'staff_access': True,
'data': self.contents,
'error': self.error_msg,
@@ -209,7 +211,7 @@ class NonStaffErrorBlock(ErrorBlock): # pylint: disable=abstract-method
"""
Return a fragment that contains the html for the student view.
"""
- fragment = Fragment(self.system.render_template('module-error.html', {
+ fragment = Fragment(self.runtime.service(self, 'mako').render_template('module-error.html', {
'staff_access': False,
'data': '',
'error': '',
diff --git a/common/lib/xmodule/xmodule/html_module.py b/common/lib/xmodule/xmodule/html_module.py
index 0329bd0bc2..de22e1a823 100644
--- a/common/lib/xmodule/xmodule/html_module.py
+++ b/common/lib/xmodule/xmodule/html_module.py
@@ -43,6 +43,7 @@ _ = lambda text: text
@XBlock.needs("i18n")
+@XBlock.needs("mako")
@XBlock.needs("user")
class HtmlBlockMixin( # lint-amnesty, pylint: disable=abstract-method
XmlMixin, EditingMixin,
@@ -131,7 +132,7 @@ class HtmlBlockMixin( # lint-amnesty, pylint: disable=abstract-method
Return the studio view.
"""
fragment = Fragment(
- self.system.render_template(self.mako_template, self.get_context())
+ self.runtime.service(self, 'mako').render_template(self.mako_template, self.get_context())
)
add_webpack_to_fragment(fragment, 'HtmlBlockStudio')
shim_xmodule_js(fragment, 'HTMLEditingDescriptor')
@@ -484,7 +485,10 @@ class CourseInfoBlock(CourseInfoFields, HtmlBlockMixin): # lint-amnesty, pylint
'visible_updates': course_updates[:3],
'hidden_updates': course_updates[3:],
}
- return self.system.render_template(f"{self.TEMPLATE_DIR}/course_updates.html", context)
+ return self.runtime.service(self, 'mako').render_template(
+ f"{self.TEMPLATE_DIR}/course_updates.html",
+ context,
+ )
@classmethod
def order_updates(self, updates): # lint-amnesty, pylint: disable=bad-classmethod-argument
diff --git a/common/lib/xmodule/xmodule/library_content_module.py b/common/lib/xmodule/xmodule/library_content_module.py
index 43d9961703..d81cb98048 100644
--- a/common/lib/xmodule/xmodule/library_content_module.py
+++ b/common/lib/xmodule/xmodule/library_content_module.py
@@ -68,6 +68,7 @@ def _get_capa_types():
@XBlock.wants('library_tools') # Only needed in studio
@XBlock.wants('studio_user_permissions') # Only available in studio
@XBlock.wants('user')
+@XBlock.needs('mako')
class LibraryContentBlock(
MakoTemplateBlockBase,
XmlMixin,
@@ -364,7 +365,7 @@ class LibraryContentBlock(
'content': rendered_child.content,
})
- fragment.add_content(self.system.render_template('vert_module.html', {
+ fragment.add_content(self.runtime.service(self, 'mako').render_template('vert_module.html', {
'items': contents,
'xblock_context': context,
'show_bookmark_button': False,
@@ -386,10 +387,11 @@ class LibraryContentBlock(
if is_root:
# User has clicked the "View" link. Show a preview of all possible children:
if self.children: # pylint: disable=no-member
- fragment.add_content(self.system.render_template("library-block-author-preview-header.html", {
- 'max_count': self.max_count,
- 'display_name': self.display_name or self.url_name,
- }))
+ fragment.add_content(self.runtime.service(self, 'mako').render_template(
+ "library-block-author-preview-header.html", {
+ 'max_count': self.max_count,
+ 'display_name': self.display_name or self.url_name,
+ }))
context['can_edit_visibility'] = False
context['can_move'] = False
self.render_children(context, fragment, can_reorder=False, can_add=False)
@@ -406,7 +408,7 @@ class LibraryContentBlock(
Return the studio view.
"""
fragment = Fragment(
- self.system.render_template(self.mako_template, self.get_context())
+ self.runtime.service(self, 'mako').render_template(self.mako_template, self.get_context())
)
add_webpack_to_fragment(fragment, 'LibraryContentBlockStudio')
shim_xmodule_js(fragment, self.studio_js_module_name)
diff --git a/common/lib/xmodule/xmodule/library_root_xblock.py b/common/lib/xmodule/xmodule/library_root_xblock.py
index ed2fc452a3..32581330aa 100644
--- a/common/lib/xmodule/xmodule/library_root_xblock.py
+++ b/common/lib/xmodule/xmodule/library_root_xblock.py
@@ -17,6 +17,7 @@ log = logging.getLogger(__name__)
_ = lambda text: text
+@XBlock.needs('mako')
class LibraryRoot(XBlock):
"""
The LibraryRoot is the root XBlock of a content library. All other blocks in
@@ -103,7 +104,7 @@ class LibraryRoot(XBlock):
})
fragment.add_content(
- self.runtime.render_template("studio_render_paged_children_view.html", {
+ self.runtime.service(self, 'mako').render_template("studio_render_paged_children_view.html", {
'items': contents,
'xblock_context': context,
'can_add': can_add,
diff --git a/common/lib/xmodule/xmodule/lti_module.py b/common/lib/xmodule/xmodule/lti_module.py
index f38cb482e8..29acd2b155 100644
--- a/common/lib/xmodule/xmodule/lti_module.py
+++ b/common/lib/xmodule/xmodule/lti_module.py
@@ -270,6 +270,7 @@ class LTIFields:
@XBlock.needs("i18n")
+@XBlock.needs("mako")
@XBlock.needs("user")
class LTIBlock(
LTIFields,
@@ -401,7 +402,7 @@ class LTIBlock(
# Add our specific template information (the raw data body)
context.update({'data': self.data})
fragment = Fragment(
- self.system.render_template(self.mako_template, context)
+ self.runtime.service(self, 'mako').render_template(self.mako_template, context)
)
add_webpack_to_fragment(fragment, 'LTIBlockStudio')
shim_xmodule_js(fragment, self.studio_js_module_name)
@@ -517,7 +518,7 @@ class LTIBlock(
Return the student view.
"""
fragment = Fragment()
- fragment.add_content(self.system.render_template('lti.html', self.get_context()))
+ fragment.add_content(self.runtime.service(self, 'mako').render_template('lti.html', self.get_context()))
add_webpack_to_fragment(fragment, 'LTIBlockPreview')
shim_xmodule_js(fragment, 'LTI')
return fragment
@@ -527,7 +528,7 @@ class LTIBlock(
"""
This is called to get context with new oauth params to iframe.
"""
- template = self.system.render_template('lti_form.html', self.get_context())
+ template = self.runtime.service(self, 'mako').render_template('lti_form.html', self.get_context())
return Response(template, content_type='text/html')
def get_user_id(self):
diff --git a/common/lib/xmodule/xmodule/mako_module.py b/common/lib/xmodule/xmodule/mako_module.py
index ab1a5ed513..b34e040798 100644
--- a/common/lib/xmodule/xmodule/mako_module.py
+++ b/common/lib/xmodule/xmodule/mako_module.py
@@ -9,11 +9,25 @@ from .x_module import DescriptorSystem, XModuleDescriptor, shim_xmodule_js
class MakoDescriptorSystem(DescriptorSystem): # lint-amnesty, pylint: disable=abstract-method
+ """
+ Descriptor system that renders mako templates.
+ """
def __init__(self, render_template, **kwargs):
super().__init__(**kwargs)
self.render_template = render_template
+ # Add the MakoService to the descriptor system.
+ #
+ # This is not needed by most XBlocks, because they are initialized with a full runtime ModuleSystem that already
+ # has the MakoService.
+ # However, there are a few cases where the XBlock only has the descriptor system instead of the full module
+ # runtime. Specifically:
+ # * in the Instructor Dashboard bulk emails tab, when rendering the HtmlBlock for its WYSIWYG editor.
+ # * during testing, when using the ModuleSystemTestCase to fetch factory-created blocks.
+ from common.djangoapps.edxmako.services import MakoService
+ self._services['mako'] = MakoService()
+
class MakoTemplateBlockBase:
"""
diff --git a/common/lib/xmodule/xmodule/poll_module.py b/common/lib/xmodule/xmodule/poll_module.py
index 6c739f4a91..6ec06009e5 100644
--- a/common/lib/xmodule/xmodule/poll_module.py
+++ b/common/lib/xmodule/xmodule/poll_module.py
@@ -18,6 +18,7 @@ from web_fragments.fragment import Fragment
from lxml import etree
from openedx.core.djangolib.markup import Text, HTML
+from xblock.core import XBlock
from xblock.fields import Boolean, Dict, List, Scope, String # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.mako_module import MakoTemplateBlockBase
from xmodule.stringify import stringify_children
@@ -36,6 +37,7 @@ log = logging.getLogger(__name__)
_ = lambda text: text
+@XBlock.needs('mako')
class PollBlock(
MakoTemplateBlockBase,
XmlMixin,
@@ -162,7 +164,7 @@ class PollBlock(
'ajax_url': self.ajax_url,
'configuration_json': self.dump_poll(),
}
- fragment.add_content(self.system.render_template('poll.html', params))
+ fragment.add_content(self.runtime.service(self, 'mako').render_template('poll.html', params))
add_webpack_to_fragment(fragment, 'PollBlockPreview')
shim_xmodule_js(fragment, 'Poll')
return fragment
diff --git a/common/lib/xmodule/xmodule/seq_module.py b/common/lib/xmodule/xmodule/seq_module.py
index 6ccd4fea8a..c71ffce6b3 100644
--- a/common/lib/xmodule/xmodule/seq_module.py
+++ b/common/lib/xmodule/xmodule/seq_module.py
@@ -244,6 +244,7 @@ class ProctoringFields:
@XBlock.needs('user')
@XBlock.needs('bookmarks')
@XBlock.needs('i18n')
+@XBlock.needs('mako')
@XBlock.wants('content_type_gating')
class SequenceBlock(
SequenceMixin,
@@ -537,7 +538,7 @@ class SequenceBlock(
if not self._can_user_view_content(course):
banner_text = self._hidden_content_banner_text(course)
- hidden_content_html = self.system.render_template(
+ hidden_content_html = self.runtime.service(self, 'mako').render_template(
'hidden_content.html',
{
'self_paced': course.self_paced,
@@ -606,7 +607,7 @@ class SequenceBlock(
fragment = Fragment()
params = self._get_render_metadata(context, display_items, prereq_met, prereq_meta_info, banner_text, view, fragment) # lint-amnesty, pylint: disable=line-too-long
- fragment.add_content(self.system.render_template("seq_module.html", params))
+ fragment.add_content(self.runtime.service(self, 'mako').render_template("seq_module.html", params))
self._capture_full_seq_item_metrics(display_items)
self._capture_current_unit_metrics(display_items)
diff --git a/common/lib/xmodule/xmodule/split_test_module.py b/common/lib/xmodule/xmodule/split_test_module.py
index 734ea19c2c..870f6ea5e0 100644
--- a/common/lib/xmodule/xmodule/split_test_module.py
+++ b/common/lib/xmodule/xmodule/split_test_module.py
@@ -123,6 +123,7 @@ def get_split_user_partitions(user_partitions):
@XBlock.needs("i18n")
@XBlock.needs('user_tags') # pylint: disable=abstract-method
+@XBlock.needs('mako')
@XBlock.needs('partitions')
@XBlock.needs('user')
class SplitTestBlock( # lint-amnesty, pylint: disable=abstract-method
@@ -301,7 +302,7 @@ class SplitTestBlock( # lint-amnesty, pylint: disable=abstract-method
sorted_inactive_contents = sorted(inactive_contents, key=itemgetter('group_name'))
# Use the new template
- fragment.add_content(self.system.render_template('split_test_staff_view.html', {
+ fragment.add_content(self.runtime.service(self, 'mako').render_template('split_test_staff_view.html', {
'items': sorted_active_contents + sorted_inactive_contents,
}))
fragment.add_css('.split-test-child { display: none; }')
@@ -328,7 +329,7 @@ class SplitTestBlock( # lint-amnesty, pylint: disable=abstract-method
fragment, inactive_children, context
)
- fragment.add_content(self.system.render_template('split_test_author_view.html', {
+ fragment.add_content(self.runtime.service(self, 'mako').render_template('split_test_author_view.html', {
'split_test': self,
'is_root': is_root,
'is_configured': self.is_configured,
@@ -367,7 +368,7 @@ class SplitTestBlock( # lint-amnesty, pylint: disable=abstract-method
Return the studio view.
"""
fragment = Fragment(
- self.system.render_template(self.mako_template, self.get_context())
+ self.runtime.service(self, 'mako').render_template(self.mako_template, self.get_context())
)
add_webpack_to_fragment(fragment, 'SplitTestBlockStudio')
shim_xmodule_js(fragment, self.studio_js_module_name)
@@ -386,7 +387,7 @@ class SplitTestBlock( # lint-amnesty, pylint: disable=abstract-method
return self._staff_view(context)
else:
child_fragment = self.child.render(STUDENT_VIEW, context)
- fragment = Fragment(self.system.render_template('split_test_student_view.html', {
+ fragment = Fragment(self.runtime.service(self, 'mako').render_template('split_test_student_view.html', {
'child_content': child_fragment.content,
'child_id': self.child.scope_ids.usage_id,
}))
diff --git a/common/lib/xmodule/xmodule/studio_editable.py b/common/lib/xmodule/xmodule/studio_editable.py
index 8352c781d1..cd62283bc2 100644
--- a/common/lib/xmodule/xmodule/studio_editable.py
+++ b/common/lib/xmodule/xmodule/studio_editable.py
@@ -1,15 +1,20 @@
"""
Mixin to support editing in Studio.
"""
+from xblock.core import XBlock
from xmodule.x_module import AUTHOR_VIEW, STUDENT_VIEW, module_attr
+@XBlock.needs('mako')
class StudioEditableBlock:
"""
Helper methods for supporting Studio editing of XBlocks.
This class is only intended to be used with an XBlock!
"""
+ # Avoids AttributeError caused by the @XBlock.needs decorator.
+ _services_requested = {}
+
has_author_view = True
def render_children(self, context, fragment, can_reorder=False, can_add=False):
@@ -31,7 +36,7 @@ class StudioEditableBlock:
'content': rendered_child.content
})
- fragment.add_content(self.system.render_template("studio_render_children_view.html", { # pylint: disable=no-member
+ fragment.add_content(self.runtime.service(self, 'mako').render_template("studio_render_children_view.html", { # pylint: disable=no-member
'items': contents,
'xblock_context': context,
'can_add': can_add,
diff --git a/common/lib/xmodule/xmodule/template_module.py b/common/lib/xmodule/xmodule/template_module.py
index 8729190a07..51bc6ff2b2 100644
--- a/common/lib/xmodule/xmodule/template_module.py
+++ b/common/lib/xmodule/xmodule/template_module.py
@@ -3,6 +3,7 @@ Template module
"""
from string import Template
+from xblock.core import XBlock
from lxml import etree
from pkg_resources import resource_string
@@ -40,6 +41,7 @@ class CustomTagTemplateBlock( # pylint: disable=abstract-method
"""
+@XBlock.needs('mako')
class CustomTagBlock(CustomTagTemplateBlock): # pylint: disable=abstract-method
"""
This module supports tags of the form
@@ -85,7 +87,7 @@ class CustomTagBlock(CustomTagTemplateBlock): # pylint: disable=abstract-method
Return the studio view.
"""
fragment = Fragment(
- self.system.render_template(self.mako_template, self.get_context())
+ self.runtime.service(self, 'mako').render_template(self.mako_template, self.get_context())
)
add_webpack_to_fragment(fragment, 'CustomTagBlockStudio')
shim_xmodule_js(fragment, 'XMLEditingDescriptor')
diff --git a/common/lib/xmodule/xmodule/tests/test_html_module.py b/common/lib/xmodule/xmodule/tests/test_html_module.py
index 5695941d0b..13fa83d268 100644
--- a/common/lib/xmodule/xmodule/tests/test_html_module.py
+++ b/common/lib/xmodule/xmodule/tests/test_html_module.py
@@ -315,7 +315,7 @@ class CourseInfoBlockTestCase(unittest.TestCase):
template_name = f"{info_module.TEMPLATE_DIR}/course_updates.html"
info_module.get_html()
# Assertion to validate that render function is called with the expected context
- info_module.system.render_template.assert_called_once_with(
+ info_module.runtime.service(info_module, 'mako').render_template.assert_called_once_with(
template_name,
expected_context
)
diff --git a/common/lib/xmodule/xmodule/vertical_block.py b/common/lib/xmodule/xmodule/vertical_block.py
index 4d1c82477b..14baf86784 100644
--- a/common/lib/xmodule/xmodule/vertical_block.py
+++ b/common/lib/xmodule/xmodule/vertical_block.py
@@ -48,7 +48,7 @@ class VerticalFields:
)
-@XBlock.needs('user', 'bookmarks')
+@XBlock.needs('user', 'bookmarks', 'mako')
@XBlock.wants('completion')
@XBlock.wants('call_to_action')
class VerticalBlock(
@@ -151,7 +151,7 @@ class VerticalBlock(
child_context['username'], str(self.location)), # pylint: disable=no-member
})
- fragment.add_content(self.system.render_template('vert_module.html', fragment_context))
+ fragment.add_content(self.runtime.service(self, 'mako').render_template('vert_module.html', fragment_context))
add_webpack_to_fragment(fragment, 'VerticalStudentView')
fragment.initialize_js('VerticalStudentView')
diff --git a/common/lib/xmodule/xmodule/video_module/video_module.py b/common/lib/xmodule/xmodule/video_module/video_module.py
index 8bcccb6306..2216c88488 100644
--- a/common/lib/xmodule/xmodule/video_module/video_module.py
+++ b/common/lib/xmodule/xmodule/video_module/video_module.py
@@ -108,6 +108,7 @@ EXPORT_IMPORT_STATIC_DIR = 'static'
@XBlock.wants('settings', 'completion', 'i18n', 'request_cache')
+@XBlock.needs('mako')
class VideoBlock(
VideoFields, VideoTranscriptsMixin, VideoStudioViewHandlers, VideoStudentViewHandlers,
TabsEditingMixin, EmptyDataRawMixin, XmlMixin, EditingMixin,
@@ -245,7 +246,7 @@ class VideoBlock(
Return the studio view.
"""
fragment = Fragment(
- self.system.render_template(self.mako_template, self.get_context())
+ self.runtime.service(self, 'mako').render_template(self.mako_template, self.get_context())
)
add_webpack_to_fragment(fragment, 'VideoBlockStudio')
shim_xmodule_js(fragment, 'TabsEditingDescriptor')
@@ -468,7 +469,7 @@ class VideoBlock(
'transcript_download_formats_list': self.fields['transcript_download_format'].values, # lint-amnesty, pylint: disable=unsubscriptable-object
'license': getattr(self, "license", None),
}
- return self.system.render_template('video.html', context)
+ return self.runtime.service(self, 'mako').render_template('video.html', context)
def validate(self):
"""
diff --git a/common/lib/xmodule/xmodule/word_cloud_module.py b/common/lib/xmodule/xmodule/word_cloud_module.py
index 8ada5d1436..5fc1c737be 100644
--- a/common/lib/xmodule/xmodule/word_cloud_module.py
+++ b/common/lib/xmodule/xmodule/word_cloud_module.py
@@ -44,6 +44,7 @@ def pretty_bool(value):
return value in bool_dict
+@XBlock.needs('mako')
class WordCloudBlock( # pylint: disable=abstract-method
EmptyDataRawMixin,
XmlMixin,
@@ -279,7 +280,7 @@ class WordCloudBlock( # pylint: disable=abstract-method
Renders the output that a student will see.
"""
fragment = Fragment()
- fragment.add_content(self.system.render_template('word_cloud.html', {
+ fragment.add_content(self.runtime.service(self, 'mako').render_template('word_cloud.html', {
'ajax_url': self.ajax_url,
'display_name': self.display_name,
'instructions': self.instructions,
@@ -304,7 +305,7 @@ class WordCloudBlock( # pylint: disable=abstract-method
Return the studio view.
"""
fragment = Fragment(
- self.system.render_template(self.mako_template, self.get_context())
+ self.runtime.service(self, 'mako').render_template(self.mako_template, self.get_context())
)
add_webpack_to_fragment(fragment, 'WordCloudBlockStudio')
shim_xmodule_js(fragment, self.studio_js_module_name)
diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py
index 53530e0e2c..056528ebd4 100644
--- a/common/lib/xmodule/xmodule/x_module.py
+++ b/common/lib/xmodule/xmodule/x_module.py
@@ -1748,7 +1748,6 @@ class ModuleSystemShim:
"""
@property
-<<<<<<< HEAD
def anonymous_student_id(self):
"""
Returns the anonymous user ID for the current user and course.
diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py
index c409f97ff3..b4acc4c3f6 100644
--- a/lms/djangoapps/courseware/module_render.py
+++ b/lms/djangoapps/courseware/module_render.py
@@ -705,7 +705,7 @@ def get_module_system_for_user(
mako_service = MakoService()
if settings.FEATURES.get("LICENSING", False):
- block_wrappers.append(wrap_with_license)
+ block_wrappers.append(partial(wrap_with_license, mako_service=mako_service))
# Wrap the output display in a single div to allow for the XModule
# javascript to be bound correctly
diff --git a/openedx/core/lib/license/wrapper.py b/openedx/core/lib/license/wrapper.py
index 2d17015408..23fb4f0492 100644
--- a/openedx/core/lib/license/wrapper.py
+++ b/openedx/core/lib/license/wrapper.py
@@ -3,12 +3,12 @@ Code to wrap web fragments with a license.
"""
-def wrap_with_license(block, view, frag, context): # pylint: disable=unused-argument
+def wrap_with_license(block, view, frag, context, mako_service): # pylint: disable=unused-argument
"""
In the LMS, display the custom license underneath the XBlock.
"""
license = getattr(block, "license", None) # pylint: disable=redefined-builtin
if license:
context = {"license": license}
- frag.content += block.runtime.render_template('license_wrapper.html', context)
+ frag.content += mako_service.render_template('license_wrapper.html', context)
return frag
diff --git a/openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py b/openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py
index 079b1765cb..61ad62e25d 100644
--- a/openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py
+++ b/openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py
@@ -32,6 +32,7 @@ def _(text):
@XBlock.needs('user') # pylint: disable=abstract-method
@XBlock.needs('i18n')
+@XBlock.needs('mako')
class DiscussionXBlock(XBlock, StudioEditableXBlockMixin, XmlParserMixin): # lint-amnesty, pylint: disable=abstract-method
"""
Provides a discussion forum that is inline with other content in the courseware.
@@ -202,7 +203,8 @@ class DiscussionXBlock(XBlock, StudioEditableXBlockMixin, XmlParserMixin): # li
'login_msg': login_msg,
}
- fragment.add_content(self.runtime.render_template('discussion/_discussion_inline.html', context))
+ fragment.add_content(self.runtime.service(self, 'mako').render_template('discussion/_discussion_inline.html',
+ context))
fragment.initialize_js('DiscussionInlineBlock')
return fragment
@@ -212,7 +214,7 @@ class DiscussionXBlock(XBlock, StudioEditableXBlockMixin, XmlParserMixin): # li
Renders author view for Studio.
"""
fragment = Fragment()
- fragment.add_content(self.runtime.render_template(
+ fragment.add_content(self.runtime.service(self, 'mako').render_template(
'discussion/_discussion_inline_studio.html',
{'discussion_id': self.discussion_id}
))