diff --git a/cms/djangoapps/contentstore/views/helpers.py b/cms/djangoapps/contentstore/views/helpers.py
index 424fe764754e..ac114bfd371c 100644
--- a/cms/djangoapps/contentstore/views/helpers.py
+++ b/cms/djangoapps/contentstore/views/helpers.py
@@ -14,6 +14,7 @@
from xmodule.tabs import StaticTab
from cms.djangoapps.models.settings.course_grading import CourseGradingModel
+from common.djangoapps.edxmako.shortcuts import render_to_string
from common.djangoapps.student import auth
from common.djangoapps.student.roles import CourseCreatorRole, OrgContentCreatorRole
from openedx.core.toggles import ENTRANCE_EXAMS
@@ -42,6 +43,13 @@ def event(request):
return HttpResponse(status=204)
+def render_from_lms(template_name, dictionary, namespace='main'):
+ """
+ Render a template using the LMS Mako templates
+ """
+ return render_to_string(template_name, dictionary, namespace="lms." + namespace)
+
+
def get_parent_xblock(xblock):
"""
Returns the xblock that is the parent of the specified xblock, or None if it has no parent.
diff --git a/cms/djangoapps/contentstore/views/item.py b/cms/djangoapps/contentstore/views/item.py
index 800c47456aa1..3ed065eb0bf5 100644
--- a/cms/djangoapps/contentstore/views/item.py
+++ b/cms/djangoapps/contentstore/views/item.py
@@ -32,7 +32,6 @@
from cms.djangoapps.contentstore.config.waffle import SHOW_REVIEW_RULES_FLAG
from cms.djangoapps.models.settings.course_grading import CourseGradingModel
from cms.lib.xblock.authoring_mixin import VISIBILITY_VIEW
-from common.djangoapps.edxmako.services import MakoService
from common.djangoapps.edxmako.shortcuts import render_to_string
from common.djangoapps.static_replace import replace_static_urls
from common.djangoapps.student.auth import has_studio_read_access, has_studio_write_access
@@ -310,8 +309,6 @@ def service(self, block, service_name):
return DjangoXBlockUserService(self._user)
if service_name == "studio_user_permissions":
return StudioPermissionsService(self._user)
- if service_name == "mako":
- return MakoService()
if service_name == "settings":
return SettingsService()
if service_name == "lti-configuration":
diff --git a/cms/djangoapps/contentstore/views/preview.py b/cms/djangoapps/contentstore/views/preview.py
index 5689ef558a19..1abafe5fb9bc 100644
--- a/cms/djangoapps/contentstore/views/preview.py
+++ b/cms/djangoapps/contentstore/views/preview.py
@@ -19,7 +19,6 @@
from cms.lib.xblock.field_data import CmsFieldData
from common.djangoapps import static_replace
from common.djangoapps.edxmako.shortcuts import render_to_string
-from common.djangoapps.edxmako.services import MakoService
from common.djangoapps.xblock_django.user_service import DjangoXBlockUserService
from lms.djangoapps.lms_xblock.field_data import LmsFieldData
from openedx.core.lib.license import wrap_with_license
@@ -44,6 +43,7 @@
from ..utils import get_visibility_partition_info
from .access import get_user_role
+from .helpers import render_from_lms
from .session_kv_store import SessionKeyValueStore
__all__ = ['preview_handler']
@@ -185,10 +185,9 @@ 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, partial(wrap_with_license, mako_service=mako_service))
+ wrappers.insert(0, wrap_with_license)
return PreviewModuleSystem(
static_url=settings.STATIC_URL,
@@ -196,6 +195,7 @@ def _preview_module_system(request, descriptor, field_data):
track_function=lambda event_type, event: None,
filestore=descriptor.runtime.resources_fs,
get_module=partial(_load_preview_module, request),
+ render_template=render_from_lms,
debug=True,
replace_urls=partial(static_replace.replace_static_urls, data_directory=None, course_id=course_id),
can_execute_unsafe_code=(lambda: can_execute_unsafe_code(course_id)),
@@ -213,7 +213,6 @@ def _preview_module_system(request, descriptor, field_data):
services={
"field-data": field_data,
"i18n": ModuleI18nService,
- 'mako': mako_service,
"settings": SettingsService(),
"user": DjangoXBlockUserService(request.user, anonymous_user_id='student'),
"partitions": StudioPartitionService(course_id=course_id),
diff --git a/cms/djangoapps/contentstore/views/tests/test_preview.py b/cms/djangoapps/contentstore/views/tests/test_preview.py
index 18f9da6fce83..07bfc854211c 100644
--- a/cms/djangoapps/contentstore/views/tests/test_preview.py
+++ b/cms/djangoapps/contentstore/views/tests/test_preview.py
@@ -8,7 +8,6 @@
import ddt
from django.test.client import Client, RequestFactory
-from web_fragments.fragment import Fragment
from xblock.core import XBlock, XBlockAside
from cms.djangoapps.contentstore.utils import reverse_usage_url
@@ -169,20 +168,13 @@ def test_block_branch_not_changed_by_preview_handler(self, default_store):
@XBlock.needs("field-data")
@XBlock.needs("i18n")
-@XBlock.needs("mako")
@XBlock.needs("user")
@XBlock.needs("teams_configuration")
class PureXBlock(XBlock):
"""
Pure XBlock to use in tests.
"""
- def student_view(self, context):
- """
- Renders the output that a student will see.
- """
- fragment = Fragment()
- fragment.add_content(self.runtime.service(self, 'mako').render_template('edxmako.html', context))
- return fragment
+ pass # lint-amnesty, pylint: disable=unnecessary-pass
@ddt.ddt
@@ -214,25 +206,3 @@ def test_expected_services_exist(self, expected_service):
)
service = runtime.service(descriptor, expected_service)
self.assertIsNotNone(service)
-
-
-class CmsModuleSystemShimTest(ModuleStoreTestCase):
- """
- Tests that the deprecated attributes in the Module System (XBlock Runtime) return the expected values.
- """
- def setUp(self):
- """
- Set up the user and other fields that will be used to instantiate the runtime.
- """
- super().setUp()
- self.course = CourseFactory.create()
- self.user = UserFactory()
- self.request = RequestFactory().get('/dummy-url')
- self.request.user = self.user
- self.request.session = {}
-
- @XBlock.register_temp_plugin(PureXBlock, identifier='pure')
- def test_render_template(self):
- descriptor = ItemFactory(category="pure", parent=self.course)
- html = get_preview_fragment(self.request, descriptor, {'element_id': 142}).content
- assert '
Testing the MakoService
' in html
diff --git a/cms/lib/xblock/authoring_mixin.py b/cms/lib/xblock/authoring_mixin.py
index 342c5ff05486..39f8f1062825 100644
--- a/cms/lib/xblock/authoring_mixin.py
+++ b/cms/lib/xblock/authoring_mixin.py
@@ -39,7 +39,7 @@ def visibility_view(self, _context=None):
"""
fragment = Fragment()
from cms.djangoapps.contentstore.utils import reverse_course_url
- fragment.add_content(self.runtime.service(self, 'mako').render_template('visibility_editor.html', {
+ fragment.add_content(self.system.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/djangoapps/edxmako/services.py b/common/djangoapps/edxmako/services.py
deleted file mode 100644
index 6ee2b096d63e..000000000000
--- a/common/djangoapps/edxmako/services.py
+++ /dev/null
@@ -1,30 +0,0 @@
-"""
-Supports rendering an XBlock to HTML using mako templates.
-"""
-
-from xblock.reference.plugins import Service
-
-from common.djangoapps.edxmako.shortcuts import render_to_string
-
-
-class MakoService(Service):
- """
- A service for rendering XBlocks to HTML using mako templates.
-
- Args:
- namespace_prefix(string): optional prefix to the mako namespace used to find the template file.
- e.g to access LMS templates from within Studio code, pass namespace_prefix='lms.'
- """
- def __init__(
- self,
- namespace_prefix='',
- **kwargs
- ):
- super().__init__(**kwargs)
- self.namespace_prefix = namespace_prefix
-
- def render_template(self, template_file, dictionary, namespace='main'):
- """
- Takes (template_file, dictionary) and returns rendered HTML.
- """
- return render_to_string(template_file, dictionary, namespace=self.namespace_prefix + namespace)
diff --git a/common/djangoapps/edxmako/tests.py b/common/djangoapps/edxmako/tests.py
index 69d350cf44d3..2e0bf2e48e60 100644
--- a/common/djangoapps/edxmako/tests.py
+++ b/common/djangoapps/edxmako/tests.py
@@ -14,7 +14,6 @@
from common.djangoapps.edxmako import LOOKUP, add_lookup
from common.djangoapps.edxmako.request_context import get_template_request_context
-from common.djangoapps.edxmako.services import MakoService
from common.djangoapps.edxmako.shortcuts import (
is_any_marketing_link_set,
is_marketing_link_set,
@@ -209,23 +208,3 @@ def test_render_to_string_when_no_global_context_cms(self):
the threadlocal REQUEST_CONTEXT.context. This is meant to run in CMS.
"""
assert "We're having trouble rendering your component" in render_to_string('html_error.html', None)
-
-
-@ddt.ddt
-class MakoServiceTestCase(TestCase):
- """
- Tests for the MakoService
- """
- @ddt.data(
- (MakoService(),
- 'Testing the MakoService
\n'),
- (MakoService(namespace_prefix='lms.'),
- 'Testing the MakoService
\n'),
- )
- @ddt.unpack
- def test_render_template(self, service, expected_html):
- """
- Tests MakoService.render_template returns the expected rendered content.
- """
- html = service.render_template('templates/edxmako.html', {'element_id': 'mako_id'})
- assert html == expected_html
diff --git a/common/lib/xmodule/xmodule/annotatable_module.py b/common/lib/xmodule/xmodule/annotatable_module.py
index e07f81231d66..1c7a80122bdf 100644
--- a/common/lib/xmodule/xmodule/annotatable_module.py
+++ b/common/lib/xmodule/xmodule/annotatable_module.py
@@ -6,7 +6,6 @@
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
@@ -30,7 +29,6 @@
_ = lambda text: text
-@XBlock.needs('mako')
class AnnotatableBlock(
RawMixin,
XmlMixin,
@@ -203,7 +201,7 @@ def get_html(self):
'content_html': self._render_content()
}
- return self.runtime.service(self, 'mako').render_template('annotatable.html', context)
+ return self.system.render_template('annotatable.html', context)
def student_view(self, context): # lint-amnesty, pylint: disable=unused-argument
"""
@@ -221,7 +219,7 @@ def studio_view(self, _context):
Return the studio view.
"""
fragment = Fragment(
- self.runtime.service(self, 'mako').render_template(self.mako_template, self.get_context())
+ self.system.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 26a42d59d6a6..25a133d19e1c 100644
--- a/common/lib/xmodule/xmodule/capa_module.py
+++ b/common/lib/xmodule/xmodule/capa_module.py
@@ -120,7 +120,6 @@ def from_json(self, value):
@XBlock.needs('user')
@XBlock.needs('i18n')
-@XBlock.needs('mako')
@XBlock.wants('call_to_action')
class ProblemBlock(
ScorableXBlockMixin,
@@ -393,7 +392,7 @@ def studio_view(self, _context):
Return the studio view.
"""
fragment = Fragment(
- self.runtime.service(self, 'mako').render_template(self.mako_template, self.get_context())
+ self.system.render_template(self.mako_template, self.get_context())
)
add_webpack_to_fragment(fragment, 'ProblemBlockStudio')
shim_xmodule_js(fragment, 'MarkdownEditingDescriptor')
@@ -822,7 +821,7 @@ def new_lcp(self, state, text=None):
filestore=self.runtime.filestore,
i18n=self.runtime.service(self, "i18n"),
node_path=self.runtime.node_path,
- render_template=self.runtime.service(self, 'mako').render_template,
+ render_template=self.runtime.render_template,
seed=seed, # Why do we do this if we have self.seed?
STATIC_URL=self.runtime.STATIC_URL,
xqueue=self.runtime.xqueue,
@@ -916,7 +915,7 @@ def get_html(self):
"""
curr_score, total_possible = self.get_display_progress()
- return self.runtime.service(self, 'mako').render_template('problem_ajax.html', {
+ return self.runtime.render_template('problem_ajax.html', {
'element_id': self.location.html_id(),
'id': str(self.location),
'ajax_url': self.ajax_url,
@@ -1264,7 +1263,7 @@ def get_problem_html(self, encapsulate=True, submit_notification=False):
'submit_disabled_cta': submit_disabled_ctas[0] if submit_disabled_ctas else None,
}
- html = self.runtime.service(self, 'mako').render_template('problem.html', context)
+ html = self.runtime.render_template('problem.html', context)
if encapsulate:
html = HTML('{html}
').format(
@@ -1574,7 +1573,7 @@ def get_answer(self, _data):
return {
'answers': new_answers,
- 'correct_status_html': self.runtime.service(self, 'mako').render_template(
+ 'correct_status_html': self.runtime.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 3605f36bf828..8a2d50c63bc1 100644
--- a/common/lib/xmodule/xmodule/conditional_module.py
+++ b/common/lib/xmodule/xmodule/conditional_module.py
@@ -11,7 +11,6 @@
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
@@ -39,7 +38,6 @@
_ = lambda text: text
-@XBlock.needs('mako')
class ConditionalBlock(
SequenceMixin,
MakoTemplateBlockBase,
@@ -247,7 +245,7 @@ def student_view(self, _context):
def get_html(self):
required_html_ids = [descriptor.location.html_id() for descriptor in self.get_required_blocks]
- return self.runtime.service(self, 'mako').render_template('conditional_ajax.html', {
+ return self.system.render_template('conditional_ajax.html', {
'element_id': self.location.html_id(),
'ajax_url': self.ajax_url,
'depends': ';'.join(required_html_ids)
@@ -273,7 +271,7 @@ def studio_view(self, _context):
Return the studio view.
"""
fragment = Fragment(
- self.runtime.service(self, 'mako').render_template(self.mako_template, self.get_context())
+ self.system.render_template(self.mako_template, self.get_context())
)
add_webpack_to_fragment(fragment, 'ConditionalBlockStudio')
shim_xmodule_js(fragment, self.studio_js_module_name)
@@ -286,7 +284,8 @@ def handle_ajax(self, _dispatch, _data):
if not self.is_condition_satisfied():
context = {'module': self,
'message': self.conditional_message}
- html = self.runtime.service(self, 'mako').render_template('conditional_module.html', context)
+ html = self.system.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 a96631954e1d..2cefcc9da9a9 100644
--- a/common/lib/xmodule/xmodule/error_module.py
+++ b/common/lib/xmodule/xmodule/error_module.py
@@ -11,7 +11,6 @@
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
@@ -44,7 +43,6 @@ class ErrorFields:
display_name = String(scope=Scope.settings)
-@XBlock.needs('mako')
class ErrorBlock(
ErrorFields,
XModuleDescriptorToXBlockMixin,
@@ -64,7 +62,7 @@ def student_view(self, _context):
"""
Return a fragment that contains the html for the student view.
"""
- fragment = Fragment(self.runtime.service(self, 'mako').render_template('module-error.html', {
+ fragment = Fragment(self.system.render_template('module-error.html', {
'staff_access': True,
'data': self.contents,
'error': self.error_msg,
@@ -211,7 +209,7 @@ def student_view(self, _context):
"""
Return a fragment that contains the html for the student view.
"""
- fragment = Fragment(self.runtime.service(self, 'mako').render_template('module-error.html', {
+ fragment = Fragment(self.system.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 de22e1a823d6..0329bd0bc2c0 100644
--- a/common/lib/xmodule/xmodule/html_module.py
+++ b/common/lib/xmodule/xmodule/html_module.py
@@ -43,7 +43,6 @@
@XBlock.needs("i18n")
-@XBlock.needs("mako")
@XBlock.needs("user")
class HtmlBlockMixin( # lint-amnesty, pylint: disable=abstract-method
XmlMixin, EditingMixin,
@@ -132,7 +131,7 @@ def studio_view(self, _context):
Return the studio view.
"""
fragment = Fragment(
- self.runtime.service(self, 'mako').render_template(self.mako_template, self.get_context())
+ self.system.render_template(self.mako_template, self.get_context())
)
add_webpack_to_fragment(fragment, 'HtmlBlockStudio')
shim_xmodule_js(fragment, 'HTMLEditingDescriptor')
@@ -485,10 +484,7 @@ def get_html(self):
'visible_updates': course_updates[:3],
'hidden_updates': course_updates[3:],
}
- return self.runtime.service(self, 'mako').render_template(
- f"{self.TEMPLATE_DIR}/course_updates.html",
- context,
- )
+ return self.system.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 d3bce47bb8af..18dbb9ae11b6 100644
--- a/common/lib/xmodule/xmodule/library_content_module.py
+++ b/common/lib/xmodule/xmodule/library_content_module.py
@@ -69,7 +69,6 @@ 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,
@@ -366,7 +365,7 @@ def student_view(self, context): # lint-amnesty, pylint: disable=missing-functi
'content': rendered_child.content,
})
- fragment.add_content(self.runtime.service(self, 'mako').render_template('vert_module.html', {
+ fragment.add_content(self.system.render_template('vert_module.html', {
'items': contents,
'xblock_context': context,
'show_bookmark_button': False,
@@ -388,11 +387,10 @@ def author_view(self, context):
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.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,
- }))
+ 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,
+ }))
context['can_edit_visibility'] = False
context['can_move'] = False
self.render_children(context, fragment, can_reorder=False, can_add=False)
@@ -409,7 +407,7 @@ def studio_view(self, _context):
Return the studio view.
"""
fragment = Fragment(
- self.runtime.service(self, 'mako').render_template(self.mako_template, self.get_context())
+ self.system.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 32581330aa0b..ed2fc452a33e 100644
--- a/common/lib/xmodule/xmodule/library_root_xblock.py
+++ b/common/lib/xmodule/xmodule/library_root_xblock.py
@@ -17,7 +17,6 @@
_ = lambda text: text
-@XBlock.needs('mako')
class LibraryRoot(XBlock):
"""
The LibraryRoot is the root XBlock of a content library. All other blocks in
@@ -104,7 +103,7 @@ def render_children(self, context, fragment, can_reorder=False, can_add=False):
})
fragment.add_content(
- self.runtime.service(self, 'mako').render_template("studio_render_paged_children_view.html", {
+ self.runtime.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 29acd2b155d5..f38cb482e8ee 100644
--- a/common/lib/xmodule/xmodule/lti_module.py
+++ b/common/lib/xmodule/xmodule/lti_module.py
@@ -270,7 +270,6 @@ class LTIFields:
@XBlock.needs("i18n")
-@XBlock.needs("mako")
@XBlock.needs("user")
class LTIBlock(
LTIFields,
@@ -402,7 +401,7 @@ def studio_view(self, _context):
# Add our specific template information (the raw data body)
context.update({'data': self.data})
fragment = Fragment(
- self.runtime.service(self, 'mako').render_template(self.mako_template, context)
+ self.system.render_template(self.mako_template, context)
)
add_webpack_to_fragment(fragment, 'LTIBlockStudio')
shim_xmodule_js(fragment, self.studio_js_module_name)
@@ -518,7 +517,7 @@ def student_view(self, _context):
Return the student view.
"""
fragment = Fragment()
- fragment.add_content(self.runtime.service(self, 'mako').render_template('lti.html', self.get_context()))
+ fragment.add_content(self.system.render_template('lti.html', self.get_context()))
add_webpack_to_fragment(fragment, 'LTIBlockPreview')
shim_xmodule_js(fragment, 'LTI')
return fragment
@@ -528,7 +527,7 @@ def preview_handler(self, _, __):
"""
This is called to get context with new oauth params to iframe.
"""
- template = self.runtime.service(self, 'mako').render_template('lti_form.html', self.get_context())
+ template = self.system.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 b34e040798ff..ab1a5ed51399 100644
--- a/common/lib/xmodule/xmodule/mako_module.py
+++ b/common/lib/xmodule/xmodule/mako_module.py
@@ -9,25 +9,11 @@
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 6ec06009e5d8..6c739f4a91f6 100644
--- a/common/lib/xmodule/xmodule/poll_module.py
+++ b/common/lib/xmodule/xmodule/poll_module.py
@@ -18,7 +18,6 @@
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
@@ -37,7 +36,6 @@
_ = lambda text: text
-@XBlock.needs('mako')
class PollBlock(
MakoTemplateBlockBase,
XmlMixin,
@@ -164,7 +162,7 @@ def student_view(self, _context):
'ajax_url': self.ajax_url,
'configuration_json': self.dump_poll(),
}
- fragment.add_content(self.runtime.service(self, 'mako').render_template('poll.html', params))
+ fragment.add_content(self.system.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 c71ffce6b346..6ccd4fea8a39 100644
--- a/common/lib/xmodule/xmodule/seq_module.py
+++ b/common/lib/xmodule/xmodule/seq_module.py
@@ -244,7 +244,6 @@ def is_proctored_exam(self, value):
@XBlock.needs('user')
@XBlock.needs('bookmarks')
@XBlock.needs('i18n')
-@XBlock.needs('mako')
@XBlock.wants('content_type_gating')
class SequenceBlock(
SequenceMixin,
@@ -538,7 +537,7 @@ def _hidden_content_student_view(self, context):
if not self._can_user_view_content(course):
banner_text = self._hidden_content_banner_text(course)
- hidden_content_html = self.runtime.service(self, 'mako').render_template(
+ hidden_content_html = self.system.render_template(
'hidden_content.html',
{
'self_paced': course.self_paced,
@@ -607,7 +606,7 @@ def _student_or_public_view(self, context, prereq_met, prereq_meta_info, banner_
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.runtime.service(self, 'mako').render_template("seq_module.html", params))
+ fragment.add_content(self.system.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 870f6ea5e0d6..734ea19c2c18 100644
--- a/common/lib/xmodule/xmodule/split_test_module.py
+++ b/common/lib/xmodule/xmodule/split_test_module.py
@@ -123,7 +123,6 @@ 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
@@ -302,7 +301,7 @@ def _staff_view(self, context):
sorted_inactive_contents = sorted(inactive_contents, key=itemgetter('group_name'))
# Use the new template
- fragment.add_content(self.runtime.service(self, 'mako').render_template('split_test_staff_view.html', {
+ fragment.add_content(self.system.render_template('split_test_staff_view.html', {
'items': sorted_active_contents + sorted_inactive_contents,
}))
fragment.add_css('.split-test-child { display: none; }')
@@ -329,7 +328,7 @@ def author_view(self, context):
fragment, inactive_children, context
)
- fragment.add_content(self.runtime.service(self, 'mako').render_template('split_test_author_view.html', {
+ fragment.add_content(self.system.render_template('split_test_author_view.html', {
'split_test': self,
'is_root': is_root,
'is_configured': self.is_configured,
@@ -368,7 +367,7 @@ def studio_view(self, context):
Return the studio view.
"""
fragment = Fragment(
- self.runtime.service(self, 'mako').render_template(self.mako_template, self.get_context())
+ self.system.render_template(self.mako_template, self.get_context())
)
add_webpack_to_fragment(fragment, 'SplitTestBlockStudio')
shim_xmodule_js(fragment, self.studio_js_module_name)
@@ -387,7 +386,7 @@ def student_view(self, context):
return self._staff_view(context)
else:
child_fragment = self.child.render(STUDENT_VIEW, context)
- fragment = Fragment(self.runtime.service(self, 'mako').render_template('split_test_student_view.html', {
+ fragment = Fragment(self.system.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 cd62283bc250..8352c781d14e 100644
--- a/common/lib/xmodule/xmodule/studio_editable.py
+++ b/common/lib/xmodule/xmodule/studio_editable.py
@@ -1,20 +1,15 @@
"""
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):
@@ -36,7 +31,7 @@ def render_children(self, context, fragment, can_reorder=False, can_add=False):
'content': rendered_child.content
})
- fragment.add_content(self.runtime.service(self, 'mako').render_template("studio_render_children_view.html", { # pylint: disable=no-member
+ fragment.add_content(self.system.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 51bc6ff2b209..8729190a073f 100644
--- a/common/lib/xmodule/xmodule/template_module.py
+++ b/common/lib/xmodule/xmodule/template_module.py
@@ -3,7 +3,6 @@
"""
from string import Template
-from xblock.core import XBlock
from lxml import etree
from pkg_resources import resource_string
@@ -41,7 +40,6 @@ class CustomTagTemplateBlock( # pylint: disable=abstract-method
"""
-@XBlock.needs('mako')
class CustomTagBlock(CustomTagTemplateBlock): # pylint: disable=abstract-method
"""
This module supports tags of the form
@@ -87,7 +85,7 @@ def studio_view(self, _context):
Return the studio view.
"""
fragment = Fragment(
- self.runtime.service(self, 'mako').render_template(self.mako_template, self.get_context())
+ self.system.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/__init__.py b/common/lib/xmodule/xmodule/tests/__init__.py
index 533bff5c6952..c91da247d8da 100644
--- a/common/lib/xmodule/xmodule/tests/__init__.py
+++ b/common/lib/xmodule/xmodule/tests/__init__.py
@@ -11,6 +11,7 @@
import inspect
import json
import os
+import pprint
import sys
import traceback
import unittest
@@ -33,7 +34,7 @@
from xmodule.modulestore.draft_and_published import ModuleStoreDraftAndPublished
from xmodule.modulestore.inheritance import InheritanceMixin
from xmodule.modulestore.xml import CourseLocationManager
-from xmodule.tests.helpers import mock_render_template, StubMakoService, StubUserService
+from xmodule.tests.helpers import StubUserService
from xmodule.x_module import ModuleSystem, XModuleDescriptor, XModuleMixin
@@ -92,13 +93,18 @@ def get_test_system(
course_id=CourseKey.from_string('/'.join(['org', 'course', 'run'])),
user=None,
user_is_staff=False,
- render_template=None,
):
"""
Construct a test ModuleSystem instance.
- By default, the descriptor system's render_template() method simply returns the repr of the
- context it is passed. You can override this by passing in a different render_template argument.
+ By default, the render_template() method simply returns the repr of the
+ context it is passed. You can override this behavior by monkey patching::
+
+ system = get_test_system()
+ system.render_template = my_render_func
+
+ where `my_render_func` is a function of the form my_render_func(template, context).
+
"""
if not user:
user = Mock(name='get_test_system.user', is_staff=False)
@@ -108,8 +114,6 @@ def get_test_system(
user_is_staff=user_is_staff,
)
- mako_service = StubMakoService(render_template=render_template)
-
descriptor_system = get_test_descriptor_system()
def get_module(descriptor):
@@ -132,6 +136,7 @@ def get_module(descriptor):
static_url='/static',
track_function=Mock(name='get_test_system.track_function'),
get_module=get_module,
+ render_template=mock_render_template,
replace_urls=str,
get_real_user=lambda __: user,
filestore=Mock(name='get_test_system.filestore', root_path='.'),
@@ -139,7 +144,6 @@ def get_module(descriptor):
hostname="edx.org",
services={
'user': user_service,
- 'mako': mako_service,
},
xqueue={
'interface': None,
@@ -157,7 +161,7 @@ def get_module(descriptor):
)
-def get_test_descriptor_system(render_template=None):
+def get_test_descriptor_system():
"""
Construct a test DescriptorSystem instance.
"""
@@ -167,7 +171,7 @@ def get_test_descriptor_system(render_template=None):
load_item=Mock(name='get_test_descriptor_system.load_item'),
resources_fs=Mock(name='get_test_descriptor_system.resources_fs'),
error_tracker=Mock(name='get_test_descriptor_system.error_tracker'),
- render_template=render_template or mock_render_template,
+ render_template=mock_render_template,
mixins=(InheritanceMixin, XModuleMixin),
field_data=field_data,
services={'field-data': field_data},
@@ -176,6 +180,16 @@ def get_test_descriptor_system(render_template=None):
return descriptor_system
+def mock_render_template(*args, **kwargs):
+ """
+ Pretty-print the args and kwargs.
+
+ Allows us to not depend on any actual template rendering mechanism,
+ while still returning a unicode object
+ """
+ return pprint.pformat((args, kwargs)).encode().decode()
+
+
class ModelsTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-class-docstring
def test_load_class(self):
diff --git a/common/lib/xmodule/xmodule/tests/helpers.py b/common/lib/xmodule/xmodule/tests/helpers.py
index 22dc86892431..4e9e9d1d14db 100644
--- a/common/lib/xmodule/xmodule/tests/helpers.py
+++ b/common/lib/xmodule/xmodule/tests/helpers.py
@@ -5,7 +5,6 @@
import filecmp
from unittest.mock import Mock
-import pprint
from path import Path as path
from xblock.reference.user_service import UserService, XBlockUser
@@ -31,31 +30,6 @@ def compare_dirs(dir1, dir2):
return compare_dirs(path(directory1), path(directory2))
-def mock_render_template(*args, **kwargs):
- """
- Pretty-print the args and kwargs.
-
- Allows us to not depend on any actual template rendering mechanism,
- while still returning a unicode object
- """
- return pprint.pformat((args, kwargs)).encode().decode()
-
-
-class StubMakoService:
- """
- Stub MakoService for testing modules that use mako templates.
- """
-
- def __init__(self, render_template=None):
- self._render_template = render_template or mock_render_template
-
- def render_template(self, *args, **kwargs):
- """
- Invokes the configured render_template method.
- """
- return self._render_template(*args, **kwargs)
-
-
class StubUserService(UserService):
"""
Stub UserService for testing the sequence module.
diff --git a/common/lib/xmodule/xmodule/tests/test_capa_module.py b/common/lib/xmodule/xmodule/tests/test_capa_module.py
index 4121cac007c8..58de4adc261e 100644
--- a/common/lib/xmodule/xmodule/tests/test_capa_module.py
+++ b/common/lib/xmodule/xmodule/tests/test_capa_module.py
@@ -79,8 +79,7 @@ def answer_key(cls, response_num=2, input_num=1):
response_num, input_num))
@classmethod
- def create(cls, attempts=None, problem_state=None, correct=False, xml=None, override_get_score=True,
- render_template=None, **kwargs):
+ def create(cls, attempts=None, problem_state=None, correct=False, xml=None, override_get_score=True, **kwargs):
"""
All parameters are optional, and are added to the created problem if specified.
@@ -96,8 +95,6 @@ def create(cls, attempts=None, problem_state=None, correct=False, xml=None, over
module.
attempts: also added to instance state. Will be converted to an int.
-
- render_template: pass function or Mock for testing
"""
location = BlockUsageLocator(
CourseLocator("edX", "capa_test", "2012_Fall", deprecated=True),
@@ -116,11 +113,8 @@ def create(cls, attempts=None, problem_state=None, correct=False, xml=None, over
# since everything else is a string.
field_data['attempts'] = int(attempts)
- system = get_test_system(
- course_id=location.course_key,
- user_is_staff=kwargs.get('user_is_staff', False),
- render_template=render_template or Mock(return_value="Test Template HTML
"),
- )
+ system = get_test_system(course_id=location.course_key, user_is_staff=kwargs.get('user_is_staff', False))
+ system.render_template = Mock(return_value="Test Template HTML
")
module = ProblemBlock(
system,
DictFieldData(field_data),
@@ -1526,8 +1520,7 @@ def test_no_max_attempts(self):
# assert that we got here without exploding
def test_get_problem_html(self):
- render_template = Mock(return_value="Test Template HTML
")
- module = CapaFactory.create(render_template=render_template)
+ module = CapaFactory.create()
# We've tested the show/hide button logic in other tests,
# so here we hard-wire the values
@@ -1539,6 +1532,9 @@ def test_get_problem_html(self):
module.should_show_reset_button = Mock(return_value=show_reset_button)
module.should_show_save_button = Mock(return_value=show_save_button)
+ # Mock the system rendering function
+ module.system.render_template = Mock(return_value="Test Template HTML
")
+
# Patch the capa problem's HTML rendering
with patch('capa.capa_problem.LoncapaProblem.get_html') as mock_html:
mock_html.return_value = "Test Problem HTML
"
@@ -1553,7 +1549,7 @@ def test_get_problem_html(self):
assert html == 'Test Template HTML
'
# Check the rendering context
- render_args, _ = render_template.call_args
+ render_args, _ = module.system.render_template.call_args
assert len(render_args) == 2
template_name = render_args[0]
@@ -1588,10 +1584,9 @@ def test_get_problem_html(self):
def test_demand_hint(self):
# HTML generation is mocked out to be meaningless here, so instead we check
# the context dict passed into HTML generation.
- render_template = Mock(return_value="Test Template HTML
")
- module = CapaFactory.create(xml=self.demand_xml, render_template=render_template)
+ module = CapaFactory.create(xml=self.demand_xml)
module.get_problem_html() # ignoring html result
- context = render_template.call_args[0][1]
+ context = module.system.render_template.call_args[0][1]
assert context['demand_hint_possible']
assert context['should_enable_next_hint']
@@ -1626,10 +1621,9 @@ def test_single_demand_hint(self):
Only demand hint
"""
- render_template = Mock(return_value="Test Template HTML
")
- module = CapaFactory.create(xml=test_xml, render_template=render_template)
+ module = CapaFactory.create(xml=test_xml)
module.get_problem_html() # ignoring html result
- context = render_template.call_args[0][1]
+ context = module.system.render_template.call_args[0][1]
assert context['demand_hint_possible']
assert context['should_enable_next_hint']
@@ -1658,10 +1652,9 @@ def test_image_hint(self):
You can add an optional hint like this. Problems that have a hint include a hint button, and this text appears the first time learners select the button.
"""
- render_template = Mock(return_value="Test Template HTML
")
- module = CapaFactory.create(xml=test_xml, render_template=render_template)
+ module = CapaFactory.create(xml=test_xml)
module.get_problem_html() # ignoring html result
- context = render_template.call_args[0][1]
+ context = module.system.render_template.call_args[0][1]
assert context['demand_hint_possible']
assert context['should_enable_next_hint']
@@ -1703,8 +1696,7 @@ def test_get_problem_html_error(self):
rendering, a "dummy" problem is created with an error
message to display to the user.
"""
- render_template = Mock(return_value="Test Template HTML
")
- module = CapaFactory.create(render_template=render_template)
+ module = CapaFactory.create()
# Save the original problem so we can compare it later
original_problem = module.lcp
@@ -1713,6 +1705,9 @@ def test_get_problem_html_error(self):
# is asked to render itself as HTML
module.lcp.get_html = Mock(side_effect=Exception("Test"))
+ # Stub out the get_test_system rendering function
+ module.system.render_template = Mock(return_value="Test Template HTML
")
+
# Turn off DEBUG
module.system.DEBUG = False
@@ -1722,7 +1717,7 @@ def test_get_problem_html_error(self):
assert html is not None
# Check the rendering context
- render_args, _ = render_template.call_args
+ render_args, _ = module.system.render_template.call_args
context = render_args[1]
assert 'error' in context['problem']['html']
@@ -1733,14 +1728,16 @@ def test_get_problem_html_error_w_debug(self):
"""
Test the html response when an error occurs with DEBUG on
"""
- render_template = Mock(return_value="Test Template HTML
")
- module = CapaFactory.create(render_template=render_template)
+ module = CapaFactory.create()
# Simulate throwing an exception when the capa problem
# is asked to render itself as HTML
error_msg = "Superterrible error happened: ☠"
module.lcp.get_html = Mock(side_effect=Exception(error_msg))
+ # Stub out the get_test_system rendering function
+ module.system.render_template = Mock(return_value="Test Template HTML
")
+
# Make sure DEBUG is on
module.system.DEBUG = True
@@ -1750,7 +1747,7 @@ def test_get_problem_html_error_w_debug(self):
assert html is not None
# Check the rendering context
- render_args, _ = render_template.call_args
+ render_args, _ = module.system.render_template.call_args
context = render_args[1]
assert error_msg in context['problem']['html']
@@ -2114,10 +2111,9 @@ def test_problem_no_display_name(self, display_name):
"""
Verify that if problem display name is not provided then a default name is used.
"""
- render_template = Mock(return_value="Test Template HTML
")
- module = CapaFactory.create(display_name=display_name, render_template=render_template)
+ module = CapaFactory.create(display_name=display_name)
module.get_problem_html()
- render_args, _ = render_template.call_args
+ render_args, _ = module.system.render_template.call_args
context = render_args[1]
assert context['problem']['name'] == module.location.block_type
diff --git a/common/lib/xmodule/xmodule/tests/test_conditional.py b/common/lib/xmodule/xmodule/tests/test_conditional.py
index ac862add812c..13f2dc6a9504 100644
--- a/common/lib/xmodule/xmodule/tests/test_conditional.py
+++ b/common/lib/xmodule/xmodule/tests/test_conditional.py
@@ -166,8 +166,7 @@ def test_get_html(self):
# because get_test_system returns the repr of the context dict passed to render_template,
# we reverse it here
html = modules['cond_module'].render(STUDENT_VIEW).content
- mako_service = modules['cond_module'].xmodule_runtime.service(modules['cond_module'], 'mako')
- expected = mako_service.render_template('conditional_ajax.html', {
+ expected = modules['cond_module'].xmodule_runtime.render_template('conditional_ajax.html', {
'ajax_url': modules['cond_module'].ajax_url,
'element_id': 'i4x-edX-conditional_test-conditional-SampleConditional',
'depends': 'i4x-edX-conditional_test-problem-SampleProblem',
@@ -242,8 +241,7 @@ def test_conditional_module(self, _):
module = self.get_module_for_location(location)
html = module.render(STUDENT_VIEW).content
- mako_service = module.xmodule_runtime.service(module, 'mako')
- html_expect = mako_service.render_template(
+ html_expect = module.xmodule_runtime.render_template(
'conditional_ajax.html',
{
# Test ajax url is just usage-id / handler_name
diff --git a/common/lib/xmodule/xmodule/tests/test_delay_between_attempts.py b/common/lib/xmodule/xmodule/tests/test_delay_between_attempts.py
index fd1afccdb849..480437a1c82f 100644
--- a/common/lib/xmodule/xmodule/tests/test_delay_between_attempts.py
+++ b/common/lib/xmodule/xmodule/tests/test_delay_between_attempts.py
@@ -103,7 +103,8 @@ def create(
# since everything else is a string.
field_data['attempts'] = int(attempts)
- system = get_test_system(render_template=Mock(return_value="Test Template HTML
"))
+ system = get_test_system()
+ system.render_template = Mock(return_value="Test Template HTML
")
module = ProblemBlock(
system,
DictFieldData(field_data),
diff --git a/common/lib/xmodule/xmodule/tests/test_editing_module.py b/common/lib/xmodule/xmodule/tests/test_editing_module.py
index 0f29595be6a0..2515adf11931 100644
--- a/common/lib/xmodule/xmodule/tests/test_editing_module.py
+++ b/common/lib/xmodule/xmodule/tests/test_editing_module.py
@@ -22,7 +22,8 @@ class TabsEditingDescriptorTestCase(unittest.TestCase):
def setUp(self):
super().setUp()
- system = get_test_descriptor_system(render_template=Mock())
+ system = get_test_descriptor_system()
+ system.render_template = Mock(return_value="Test Template HTML
")
self.tabs = [
{
'name': "Test_css",
diff --git a/common/lib/xmodule/xmodule/tests/test_html_module.py b/common/lib/xmodule/xmodule/tests/test_html_module.py
index 13fa83d268f9..5695941d0b3e 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 @@ def test_updates_order(self):
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.runtime.service(info_module, 'mako').render_template.assert_called_once_with(
+ info_module.system.render_template.assert_called_once_with(
template_name,
expected_context
)
diff --git a/common/lib/xmodule/xmodule/tests/test_xml_module.py b/common/lib/xmodule/xmodule/tests/test_xml_module.py
index 9b4d4fc9103c..2776c52a6bb0 100644
--- a/common/lib/xmodule/xmodule/tests/test_xml_module.py
+++ b/common/lib/xmodule/xmodule/tests/test_xml_module.py
@@ -347,7 +347,8 @@ def non_editable_metadata_fields(self):
non_editable_fields.append(TestModuleDescriptor.due)
return non_editable_fields
- system = get_test_descriptor_system(render_template=Mock())
+ system = get_test_descriptor_system()
+ system.render_template = Mock(return_value="Test Template HTML
")
return system.construct_xblock_from_class(TestModuleDescriptor, field_data=field_data, scope_ids=Mock())
def assert_field_values(self, editable_fields, name, field, explicitly_set, value, default_value, # lint-amnesty, pylint: disable=dangerous-default-value
diff --git a/common/lib/xmodule/xmodule/vertical_block.py b/common/lib/xmodule/xmodule/vertical_block.py
index 14baf8678466..4d1c82477b5f 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', 'mako')
+@XBlock.needs('user', 'bookmarks')
@XBlock.wants('completion')
@XBlock.wants('call_to_action')
class VerticalBlock(
@@ -151,7 +151,7 @@ def _student_or_public_view(self, context, view):
child_context['username'], str(self.location)), # pylint: disable=no-member
})
- fragment.add_content(self.runtime.service(self, 'mako').render_template('vert_module.html', fragment_context))
+ fragment.add_content(self.system.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 2216c88488ca..8bcccb630672 100644
--- a/common/lib/xmodule/xmodule/video_module/video_module.py
+++ b/common/lib/xmodule/xmodule/video_module/video_module.py
@@ -108,7 +108,6 @@
@XBlock.wants('settings', 'completion', 'i18n', 'request_cache')
-@XBlock.needs('mako')
class VideoBlock(
VideoFields, VideoTranscriptsMixin, VideoStudioViewHandlers, VideoStudentViewHandlers,
TabsEditingMixin, EmptyDataRawMixin, XmlMixin, EditingMixin,
@@ -246,7 +245,7 @@ def studio_view(self, _context):
Return the studio view.
"""
fragment = Fragment(
- self.runtime.service(self, 'mako').render_template(self.mako_template, self.get_context())
+ self.system.render_template(self.mako_template, self.get_context())
)
add_webpack_to_fragment(fragment, 'VideoBlockStudio')
shim_xmodule_js(fragment, 'TabsEditingDescriptor')
@@ -469,7 +468,7 @@ def get_html(self, view=STUDENT_VIEW): # lint-amnesty, pylint: disable=argument
'transcript_download_formats_list': self.fields['transcript_download_format'].values, # lint-amnesty, pylint: disable=unsubscriptable-object
'license': getattr(self, "license", None),
}
- return self.runtime.service(self, 'mako').render_template('video.html', context)
+ return self.system.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 5fc1c737be65..8ada5d143655 100644
--- a/common/lib/xmodule/xmodule/word_cloud_module.py
+++ b/common/lib/xmodule/xmodule/word_cloud_module.py
@@ -44,7 +44,6 @@ def pretty_bool(value):
return value in bool_dict
-@XBlock.needs('mako')
class WordCloudBlock( # pylint: disable=abstract-method
EmptyDataRawMixin,
XmlMixin,
@@ -280,7 +279,7 @@ def student_view(self, context): # lint-amnesty, pylint: disable=unused-argumen
Renders the output that a student will see.
"""
fragment = Fragment()
- fragment.add_content(self.runtime.service(self, 'mako').render_template('word_cloud.html', {
+ fragment.add_content(self.system.render_template('word_cloud.html', {
'ajax_url': self.ajax_url,
'display_name': self.display_name,
'instructions': self.instructions,
@@ -305,7 +304,7 @@ def studio_view(self, _context):
Return the studio view.
"""
fragment = Fragment(
- self.runtime.service(self, 'mako').render_template(self.mako_template, self.get_context())
+ self.system.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 056528ebd4ba..593d8f117665 100644
--- a/common/lib/xmodule/xmodule/x_module.py
+++ b/common/lib/xmodule/xmodule/x_module.py
@@ -1809,23 +1809,6 @@ def user_is_staff(self):
return self._services['user'].get_current_user().opt_attrs.get(ATTR_KEY_USER_IS_STAFF)
return None
- @property
- def render_template(self):
- """
- Returns a function that takes (template_file, context), and returns rendered html.
-
- Deprecated in favor of the mako service.
- """
- warnings.warn(
- 'Use of runtime.render_template is deprecated. '
- 'Use MakoService.render_template or a JavaScript-based template instead.',
- DeprecationWarning, stacklevel=2,
- )
- render_service = self._services.get('mako')
- if render_service:
- return render_service.render_template
- return None
-
class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, ModuleSystemShim, Runtime):
"""
@@ -1841,7 +1824,7 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, ModuleSystemShim,
"""
def __init__(
- self, static_url, track_function, get_module,
+ self, static_url, track_function, get_module, render_template,
replace_urls, descriptor_runtime, filestore=None,
debug=False, hostname="", xqueue=None, publish=None, node_path="",
course_id=None,
@@ -1863,6 +1846,9 @@ def __init__(
module instance object. If the current user does not have
access to that location, returns None.
+ render_template - a function that takes (template_file, context), and
+ returns rendered html.
+
filestore - A filestore ojbect. Defaults to an instance of OSFS based
at settings.DATA_DIR.
@@ -1918,6 +1904,7 @@ def __init__(
self.track_function = track_function
self.filestore = filestore
self.get_module = get_module
+ self.render_template = render_template
self.DEBUG = self.debug = debug
self.HOSTNAME = self.hostname = hostname
self.replace_urls = replace_urls
diff --git a/common/test/templates/edxmako.html b/common/test/templates/edxmako.html
deleted file mode 100644
index fd95201801c2..000000000000
--- a/common/test/templates/edxmako.html
+++ /dev/null
@@ -1 +0,0 @@
-<%page expression_filter="h"/>Testing the MakoService
diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py
index b4acc4c3f680..d6ac518e9519 100644
--- a/lms/djangoapps/courseware/module_render.py
+++ b/lms/djangoapps/courseware/module_render.py
@@ -52,6 +52,7 @@
setup_masquerade
)
from lms.djangoapps.courseware.model_data import DjangoKeyValueStore, FieldDataCache
+from common.djangoapps.edxmako.shortcuts import render_to_string
from lms.djangoapps.courseware.field_overrides import OverrideFieldData
from lms.djangoapps.courseware.services import UserStateService
from lms.djangoapps.grades.api import GradesUtilService
@@ -89,7 +90,6 @@
from common.djangoapps.track import contexts
from common.djangoapps.util import milestones_helpers
from common.djangoapps.util.json_request import JsonResponse
-from common.djangoapps.edxmako.services import MakoService
from common.djangoapps.xblock_django.user_service import DjangoXBlockUserService
from xmodule.contentstore.django import contentstore
from xmodule.error_module import ErrorBlock, NonStaffErrorBlock
@@ -703,9 +703,8 @@ def rebind_noauth_module_to_user(module, real_user):
if is_masquerading_as_specific_student(user, course_id):
block_wrappers.append(filter_displayed_blocks)
- mako_service = MakoService()
if settings.FEATURES.get("LICENSING", False):
- block_wrappers.append(partial(wrap_with_license, mako_service=mako_service))
+ block_wrappers.append(wrap_with_license)
# Wrap the output display in a single div to allow for the XModule
# javascript to be bound correctly
@@ -771,6 +770,7 @@ def rebind_noauth_module_to_user(module, real_user):
system = LmsModuleSystem(
track_function=track_function,
+ render_template=render_to_string,
static_url=settings.STATIC_URL,
xqueue=xqueue,
# TODO (cpennington): Figure out how to share info between systems
@@ -810,7 +810,6 @@ def rebind_noauth_module_to_user(module, real_user):
services={
'fs': FSService(),
'field-data': field_data,
- 'mako': mako_service,
'user': user_service,
'verification': XBlockVerificationService(),
'proctoring': ProctoringService(),
diff --git a/lms/djangoapps/courseware/tests/helpers.py b/lms/djangoapps/courseware/tests/helpers.py
index 83a27122bb44..d500bf5bbf7e 100644
--- a/lms/djangoapps/courseware/tests/helpers.py
+++ b/lms/djangoapps/courseware/tests/helpers.py
@@ -7,7 +7,6 @@
import json
from collections import OrderedDict
from datetime import timedelta
-from unittest.mock import Mock
from django.contrib import messages
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
@@ -64,11 +63,11 @@ class BaseTestXmodule(ModuleStoreTestCase):
METADATA = {}
MODEL_DATA = {'data': ''}
- def new_module_runtime(self, render_template=None):
+ def new_module_runtime(self):
"""
Generate a new ModuleSystem that is minimally set up for testing
"""
- return get_test_system(course_id=self.course.id, render_template=render_template)
+ return get_test_system(course_id=self.course.id)
def new_descriptor_runtime(self):
runtime = get_test_descriptor_system()
@@ -144,14 +143,12 @@ def get_url(self, dispatch):
class XModuleRenderingTestBase(BaseTestXmodule): # lint-amnesty, pylint: disable=missing-class-docstring
- def new_module_runtime(self, render_template=None):
+ def new_module_runtime(self):
"""
Create a runtime that actually does html rendering
"""
- if not render_template:
- render_template = render_to_string
- runtime = super().new_module_runtime(render_template=render_template)
- runtime.modulestore = Mock()
+ runtime = super().new_module_runtime()
+ runtime.render_template = render_to_string
return runtime
diff --git a/lms/djangoapps/courseware/tests/test_discussion_xblock.py b/lms/djangoapps/courseware/tests/test_discussion_xblock.py
index b268f7c87824..e48973570a6d 100644
--- a/lms/djangoapps/courseware/tests/test_discussion_xblock.py
+++ b/lms/djangoapps/courseware/tests/test_discussion_xblock.py
@@ -42,6 +42,7 @@ def setUp(self):
self.patchers = []
self.course_id = "test_course"
self.runtime = self.new_module_runtime()
+ self.runtime.modulestore = mock.Mock()
self.discussion_id = str(uuid.uuid4())
self.data = DictFieldData({
@@ -130,8 +131,7 @@ def setUp(self):
self.template_canary = 'canary'
self.render_template = mock.Mock()
self.render_template.return_value = self.template_canary
- self.runtime = self.new_module_runtime(render_template=self.render_template)
- self.block.runtime = self.runtime
+ self.block.runtime.render_template = self.render_template
self.has_permission_mock = mock.Mock()
self.has_permission_mock.return_value = False
self.block.has_permission = self.has_permission_mock
diff --git a/lms/djangoapps/courseware/tests/test_module_render.py b/lms/djangoapps/courseware/tests/test_module_render.py
index 1ea9b2908cc3..bc19f06e8353 100644
--- a/lms/djangoapps/courseware/tests/test_module_render.py
+++ b/lms/djangoapps/courseware/tests/test_module_render.py
@@ -2687,17 +2687,3 @@ def test_user_service_with_anonymous_user(self):
assert runtime.seed == 0
assert runtime.user_id is None
assert not runtime.user_is_staff
-
- def test_render_template(self):
- runtime, _ = render.get_module_system_for_user(
- self.user,
- self.student_data,
- self.descriptor,
- self.course.id,
- self.track_function,
- self.xqueue_callback_url_prefix,
- self.request_token,
- course=self.course,
- )
- rendered = runtime.render_template('templates/edxmako.html', {'element_id': 'hi'}) # pylint: disable=not-callable
- assert rendered == 'Testing the MakoService
\n'
diff --git a/lms/djangoapps/courseware/tests/test_video_mongo.py b/lms/djangoapps/courseware/tests/test_video_mongo.py
index bb3a94be2976..8c487a1902a3 100644
--- a/lms/djangoapps/courseware/tests/test_video_mongo.py
+++ b/lms/djangoapps/courseware/tests/test_video_mongo.py
@@ -130,9 +130,9 @@ def test_video_constructor(self):
'poster': 'null',
}
- mako_service = self.item_descriptor.xmodule_runtime.service(self.item_descriptor, 'mako')
assert get_context_dict_from_string(context) ==\
- get_context_dict_from_string(mako_service.render_template('video.html', expected_context))
+ get_context_dict_from_string(self.item_descriptor.xmodule_runtime.render_template('video.html',
+ expected_context))
class TestVideoNonYouTube(TestVideo): # pylint: disable=test-inherits-tests
@@ -211,9 +211,8 @@ def test_video_constructor(self):
'poster': 'null',
}
- mako_service = self.item_descriptor.xmodule_runtime.service(self.item_descriptor, 'mako')
expected_result = get_context_dict_from_string(
- mako_service.render_template('video.html', expected_context)
+ self.item_descriptor.xmodule_runtime.render_template('video.html', expected_context)
)
assert get_context_dict_from_string(context) == expected_result
assert expected_result['download_video_link'] == 'example.mp4'
@@ -384,9 +383,9 @@ def test_get_html_track(self):
'metadata': json.dumps(metadata)
})
- mako_service = self.item_descriptor.xmodule_runtime.service(self.item_descriptor, 'mako')
assert get_context_dict_from_string(context) ==\
- get_context_dict_from_string(mako_service.render_template('video.html', expected_context))
+ get_context_dict_from_string(self.item_descriptor.xmodule_runtime.render_template('video.html',
+ expected_context))
def test_get_html_source(self):
# lint-amnesty, pylint: disable=invalid-name, redefined-outer-name
@@ -492,9 +491,9 @@ def test_get_html_source(self):
'metadata': json.dumps(expected_context['metadata'])
})
- mako_service = self.item_descriptor.xmodule_runtime.service(self.item_descriptor, 'mako')
assert get_context_dict_from_string(context) ==\
- get_context_dict_from_string(mako_service.render_template('video.html', expected_context))
+ get_context_dict_from_string(self.item_descriptor.xmodule_runtime.render_template('video.html',
+ expected_context))
def test_get_html_with_non_existent_edx_video_id(self):
"""
@@ -632,9 +631,9 @@ def test_get_html_with_mocked_edx_video_id(self):
'metadata': json.dumps(expected_context['metadata'])
})
- mako_service = self.item_descriptor.xmodule_runtime.service(self.item_descriptor, 'mako')
assert get_context_dict_from_string(context) ==\
- get_context_dict_from_string(mako_service.render_template('video.html', expected_context))
+ get_context_dict_from_string(self.item_descriptor.xmodule_runtime.render_template('video.html',
+ expected_context))
def test_get_html_with_existing_edx_video_id(self):
"""
@@ -660,9 +659,9 @@ def test_get_html_with_existing_edx_video_id(self):
# context returned by get_html when provided with above data
# expected_context, a dict to assert with context
context, expected_context = self.helper_get_html_with_edx_video_id(data)
- mako_service = self.item_descriptor.xmodule_runtime.service(self.item_descriptor, 'mako')
assert get_context_dict_from_string(context) ==\
- get_context_dict_from_string(mako_service.render_template('video.html', expected_context))
+ get_context_dict_from_string(self.item_descriptor.xmodule_runtime.render_template('video.html',
+ expected_context))
def test_get_html_with_existing_unstripped_edx_video_id(self):
"""
@@ -691,9 +690,9 @@ def test_get_html_with_existing_unstripped_edx_video_id(self):
# expected_context, a dict to assert with context
context, expected_context = self.helper_get_html_with_edx_video_id(data)
- mako_service = self.item_descriptor.xmodule_runtime.service(self.item_descriptor, 'mako')
assert get_context_dict_from_string(context) ==\
- get_context_dict_from_string(mako_service.render_template('video.html', expected_context))
+ get_context_dict_from_string(self.item_descriptor.xmodule_runtime.render_template('video.html',
+ expected_context))
def encode_and_create_video(self, edx_video_id):
"""
@@ -900,9 +899,9 @@ def side_effect(*args, **kwargs): # lint-amnesty, pylint: disable=unused-argume
'metadata': json.dumps(expected_context['metadata'])
})
- mako_service = self.item_descriptor.xmodule_runtime.service(self.item_descriptor, 'mako')
assert get_context_dict_from_string(context) ==\
- get_context_dict_from_string(mako_service.render_template('video.html', expected_context))
+ get_context_dict_from_string(self.item_descriptor.xmodule_runtime.render_template('video.html',
+ expected_context))
# pylint: disable=invalid-name
def test_get_html_cdn_source_external_video(self):
@@ -1002,9 +1001,9 @@ def test_get_html_cdn_source_external_video(self):
'metadata': json.dumps(expected_context['metadata'])
})
- mako_service = self.item_descriptor.xmodule_runtime.service(self.item_descriptor, 'mako')
assert get_context_dict_from_string(context) ==\
- get_context_dict_from_string(mako_service.render_template('video.html', expected_context))
+ get_context_dict_from_string(self.item_descriptor.xmodule_runtime.render_template('video.html',
+ expected_context))
@ddt.data(
(True, ['youtube', 'desktop_webm', 'desktop_mp4', 'hls']),
@@ -2235,8 +2234,7 @@ def test_bumper_metadata(self, get_url_for_profiles, get_bumper_settings, is_bum
}))
}
- mako_service = self.item_descriptor.xmodule_runtime.service(self.item_descriptor, 'mako')
- expected_content = mako_service.render_template('video.html', expected_context)
+ expected_content = self.item_descriptor.xmodule_runtime.render_template('video.html', expected_context)
assert get_context_dict_from_string(content) == get_context_dict_from_string(expected_content)
@@ -2327,9 +2325,8 @@ def assert_content_matches_expectations(self, autoadvanceenabled_must_be, autoad
autoadvance_flag=autoadvance_must_be,
)
- mako_service = self.item_descriptor.xmodule_runtime.service(self.item_descriptor, 'mako')
with override_settings(FEATURES=self.FEATURES):
- expected_content = mako_service.render_template('video.html', expected_context)
+ expected_content = self.item_descriptor.xmodule_runtime.render_template('video.html', expected_context)
assert get_context_dict_from_string(content) == get_context_dict_from_string(expected_content)
diff --git a/lms/djangoapps/lms_xblock/test/test_runtime.py b/lms/djangoapps/lms_xblock/test/test_runtime.py
index 3e74f82f8c75..42c20de05b71 100644
--- a/lms/djangoapps/lms_xblock/test/test_runtime.py
+++ b/lms/djangoapps/lms_xblock/test/test_runtime.py
@@ -63,6 +63,7 @@ def setUp(self):
static_url='/static',
track_function=Mock(),
get_module=Mock(),
+ render_template=Mock(),
replace_urls=str,
course_id=self.course_key,
user=Mock(),
@@ -129,6 +130,7 @@ def setUp(self):
static_url='/static',
track_function=Mock(),
get_module=Mock(),
+ render_template=Mock(),
replace_urls=str,
user=self.user,
course_id=self.course_id,
@@ -184,6 +186,7 @@ def mock_get_real_user(_anon_id):
static_url='/static',
track_function=Mock(),
get_module=Mock(),
+ render_template=Mock(),
replace_urls=str,
course_id=self.course_id,
user=self.user,
@@ -239,6 +242,7 @@ def setUp(self):
static_url='/static',
track_function=Mock(),
get_module=Mock(),
+ render_template=Mock(),
replace_urls=str,
course_id=self.course.id,
user=Mock(),
diff --git a/lms/envs/test.py b/lms/envs/test.py
index 43286bfb6edd..d43db2672cfe 100644
--- a/lms/envs/test.py
+++ b/lms/envs/test.py
@@ -495,20 +495,6 @@
ACTIVATION_EMAIL_FROM_ADDRESS = 'test_activate@edx.org'
TEMPLATES[0]['OPTIONS']['debug'] = True
-TEMPLATES.append(
- {
- # This separate copy of the Mako backend is used to test rendering previews in the 'lms.main' namespace
- 'NAME': 'preview',
- 'BACKEND': 'common.djangoapps.edxmako.backend.Mako',
- 'APP_DIRS': False,
- 'DIRS': MAKO_TEMPLATE_DIRS_BASE,
- 'OPTIONS': {
- 'context_processors': CONTEXT_PROCESSORS,
- 'debug': False,
- 'namespace': 'lms.main',
- }
- }
-)
########################## VIDEO TRANSCRIPTS STORAGE ############################
VIDEO_TRANSCRIPTS_SETTINGS = dict(
diff --git a/openedx/core/djangoapps/xblock/runtime/runtime.py b/openedx/core/djangoapps/xblock/runtime/runtime.py
index 93984037c82f..558259d99842 100644
--- a/openedx/core/djangoapps/xblock/runtime/runtime.py
+++ b/openedx/core/djangoapps/xblock/runtime/runtime.py
@@ -19,7 +19,6 @@
from xblock.fields import Scope
from xblock.runtime import KvsFieldData, MemoryIdManager, Runtime
-from common.djangoapps.edxmako.services import MakoService
from common.djangoapps.track import contexts as track_contexts
from common.djangoapps.track import views as track_views
from common.djangoapps.xblock_django.user_service import DjangoXBlockUserService
@@ -236,8 +235,6 @@ def service(self, block, service_name):
user_is_staff=self.user.is_staff,
anonymous_user_id=self.anonymous_student_id,
)
- elif service_name == "mako":
- return MakoService()
elif service_name == "i18n":
return ModuleI18nService(block=block)
# Check if the XBlockRuntimeSystem wants to handle this:
diff --git a/openedx/core/lib/license/wrapper.py b/openedx/core/lib/license/wrapper.py
index 23fb4f04926a..2d1701540820 100644
--- a/openedx/core/lib/license/wrapper.py
+++ b/openedx/core/lib/license/wrapper.py
@@ -3,12 +3,12 @@
"""
-def wrap_with_license(block, view, frag, context, mako_service): # pylint: disable=unused-argument
+def wrap_with_license(block, view, frag, context): # 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 += mako_service.render_template('license_wrapper.html', context)
+ frag.content += block.runtime.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 61ad62e25d58..079b1765cbb4 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,7 +32,6 @@ 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.
@@ -203,8 +202,7 @@ def student_view(self, context=None):
'login_msg': login_msg,
}
- fragment.add_content(self.runtime.service(self, 'mako').render_template('discussion/_discussion_inline.html',
- context))
+ fragment.add_content(self.runtime.render_template('discussion/_discussion_inline.html', context))
fragment.initialize_js('DiscussionInlineBlock')
return fragment
@@ -214,7 +212,7 @@ def author_view(self, context=None): # pylint: disable=unused-argument
Renders author view for Studio.
"""
fragment = Fragment()
- fragment.add_content(self.runtime.service(self, 'mako').render_template(
+ fragment.add_content(self.runtime.render_template(
'discussion/_discussion_inline_studio.html',
{'discussion_id': self.discussion_id}
))