Merge pull request #2288 from jazkarta/pluggable-mako-templates
Make mako template lookups pluggable.
This commit is contained in:
@@ -11,5 +11,6 @@
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
LOOKUP = {}
|
||||
|
||||
lookup = None
|
||||
from .paths import add_lookup, lookup_template
|
||||
|
||||
51
common/djangoapps/edxmako/paths.py
Normal file
51
common/djangoapps/edxmako/paths.py
Normal file
@@ -0,0 +1,51 @@
|
||||
"""
|
||||
Set up lookup paths for mako templates.
|
||||
"""
|
||||
import os
|
||||
import pkg_resources
|
||||
|
||||
from django.conf import settings
|
||||
from mako.lookup import TemplateLookup
|
||||
|
||||
from . import LOOKUP
|
||||
|
||||
|
||||
class DynamicTemplateLookup(TemplateLookup):
|
||||
"""
|
||||
A specialization of the standard mako `TemplateLookup` class which allows
|
||||
for adding directories progressively.
|
||||
"""
|
||||
def add_directory(self, directory):
|
||||
"""
|
||||
Add a new directory to the template lookup path.
|
||||
"""
|
||||
self.directories.append(os.path.normpath(directory))
|
||||
|
||||
|
||||
def add_lookup(namespace, directory, package=None):
|
||||
"""
|
||||
Adds a new mako template lookup directory to the given namespace.
|
||||
|
||||
If `package` is specified, `pkg_resources` is used to look up the directory
|
||||
inside the given package. Otherwise `directory` is assumed to be a path
|
||||
in the filesystem.
|
||||
"""
|
||||
templates = LOOKUP.get(namespace)
|
||||
if not templates:
|
||||
LOOKUP[namespace] = templates = DynamicTemplateLookup(
|
||||
module_directory=settings.MAKO_MODULE_DIR,
|
||||
output_encoding='utf-8',
|
||||
input_encoding='utf-8',
|
||||
default_filters=['decode.utf8'],
|
||||
encoding_errors='replace',
|
||||
)
|
||||
if package:
|
||||
directory = pkg_resources.resource_filename(package, directory)
|
||||
templates.add_directory(directory)
|
||||
|
||||
|
||||
def lookup_template(namespace, name):
|
||||
"""
|
||||
Look up a Mako template by namespace and name.
|
||||
"""
|
||||
return LOOKUP[namespace].get_template(name)
|
||||
@@ -18,7 +18,7 @@ import logging
|
||||
|
||||
from microsite_configuration.middleware import MicrositeConfiguration
|
||||
|
||||
import edxmako
|
||||
from edxmako import lookup_template
|
||||
import edxmako.middleware
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
@@ -100,7 +100,7 @@ def render_to_string(template_name, dictionary, context=None, namespace='main'):
|
||||
if context:
|
||||
context_dictionary.update(context)
|
||||
# fetch and render template
|
||||
template = edxmako.lookup[namespace].get_template(template_name)
|
||||
template = lookup_template(namespace, template_name)
|
||||
return template.render_unicode(**context_dictionary)
|
||||
|
||||
|
||||
|
||||
@@ -1,33 +1,15 @@
|
||||
"""
|
||||
Initialize the mako template lookup
|
||||
"""
|
||||
|
||||
import tempdir
|
||||
from django.conf import settings
|
||||
from mako.lookup import TemplateLookup
|
||||
|
||||
import edxmako
|
||||
from . import add_lookup
|
||||
|
||||
|
||||
def run():
|
||||
"""Setup mako variables and lookup object"""
|
||||
# Set all mako variables based on django settings
|
||||
"""
|
||||
Setup mako lookup directories.
|
||||
"""
|
||||
template_locations = settings.MAKO_TEMPLATES
|
||||
module_directory = getattr(settings, 'MAKO_MODULE_DIR', None)
|
||||
|
||||
if module_directory is None:
|
||||
module_directory = tempdir.mkdtemp_clean()
|
||||
|
||||
lookup = {}
|
||||
|
||||
for location in template_locations:
|
||||
lookup[location] = TemplateLookup(
|
||||
directories=template_locations[location],
|
||||
module_directory=module_directory,
|
||||
output_encoding='utf-8',
|
||||
input_encoding='utf-8',
|
||||
default_filters=['decode.utf8'],
|
||||
encoding_errors='replace',
|
||||
)
|
||||
|
||||
edxmako.lookup = lookup
|
||||
for namespace, directories in template_locations.items():
|
||||
for directory in directories:
|
||||
add_lookup(namespace, directory)
|
||||
|
||||
@@ -19,7 +19,7 @@ from edxmako.shortcuts import marketing_link
|
||||
import edxmako
|
||||
import edxmako.middleware
|
||||
|
||||
django_variables = ['lookup', 'output_encoding', 'encoding_errors']
|
||||
DJANGO_VARIABLES = ['output_encoding', 'encoding_errors']
|
||||
|
||||
# TODO: We should make this a Django Template subclass that simply has the MakoTemplate inside of it? (Intead of inheriting from MakoTemplate)
|
||||
|
||||
@@ -34,8 +34,8 @@ class Template(MakoTemplate):
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Overrides base __init__ to provide django variable overrides"""
|
||||
if not kwargs.get('no_django', False):
|
||||
overrides = dict([(k, getattr(edxmako, k, None),) for k in django_variables])
|
||||
overrides['lookup'] = overrides['lookup']['main']
|
||||
overrides = {k: getattr(edxmako, k, None) for k in DJANGO_VARIABLES}
|
||||
overrides['lookup'] = edxmako.LOOKUP['main']
|
||||
kwargs.update(overrides)
|
||||
super(Template, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from django.test import TestCase
|
||||
from django.test.utils import override_settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from edxmako import add_lookup, LOOKUP
|
||||
from edxmako.shortcuts import marketing_link
|
||||
from mock import patch
|
||||
from util.testing import UrlResetMixin
|
||||
@@ -24,3 +25,15 @@ class ShortcutsTests(UrlResetMixin, TestCase):
|
||||
expected_link = reverse('login')
|
||||
link = marketing_link('ABOUT')
|
||||
self.assertEquals(link, expected_link)
|
||||
|
||||
|
||||
class AddLookupTests(TestCase):
|
||||
"""
|
||||
Test the `add_lookup` function.
|
||||
"""
|
||||
@patch('edxmako.LOOKUP', {})
|
||||
def test_with_package(self):
|
||||
add_lookup('test', 'management', __name__)
|
||||
dirs = LOOKUP['test'].directories
|
||||
self.assertEqual(len(dirs), 1)
|
||||
self.assertTrue(dirs[0].endswith('management'))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
import edxmako
|
||||
from edxmako import lookup_template
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
@@ -15,8 +15,8 @@ body, and an _subject.txt for the subject. '''
|
||||
#text = open(args[0]).read()
|
||||
#subject = open(args[1]).read()
|
||||
users = User.objects.all()
|
||||
text = edxmako.lookup['main'].get_template('email/' + args[0] + ".txt").render()
|
||||
subject = edxmako.lookup['main'].get_template('email/' + args[0] + "_subject.txt").render().strip()
|
||||
text = lookup_template('main', 'email/' + args[0] + ".txt").render()
|
||||
subject = lookup_template('main', 'email/' + args[0] + "_subject.txt").render().strip()
|
||||
for user in users:
|
||||
if user.is_active:
|
||||
user.email_user(subject, text)
|
||||
|
||||
@@ -4,7 +4,7 @@ import time
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.conf import settings
|
||||
|
||||
import edxmako
|
||||
from edxmako import lookup_template
|
||||
|
||||
from django.core.mail import send_mass_mail
|
||||
import sys
|
||||
@@ -39,8 +39,8 @@ rate -- messages per second
|
||||
|
||||
users = [u.strip() for u in open(user_file).readlines()]
|
||||
|
||||
message = edxmako.lookup['main'].get_template('emails/' + message_base + "_body.txt").render()
|
||||
subject = edxmako.lookup['main'].get_template('emails/' + message_base + "_subject.txt").render().strip()
|
||||
message = lookup_template('main', 'emails/' + message_base + "_body.txt").render()
|
||||
subject = lookup_template('main', 'emails/' + message_base + "_subject.txt").render().strip()
|
||||
rate = int(ratestr)
|
||||
|
||||
self.log_file = open(logfilename, "a+", buffering=0)
|
||||
|
||||
1
common/djangoapps/student/tests/email/test.txt
Normal file
1
common/djangoapps/student/tests/email/test.txt
Normal file
@@ -0,0 +1 @@
|
||||
Test body.
|
||||
1
common/djangoapps/student/tests/email/test_subject.txt
Normal file
1
common/djangoapps/student/tests/email/test_subject.txt
Normal file
@@ -0,0 +1 @@
|
||||
Test subject.
|
||||
1
common/djangoapps/student/tests/emails/test_body.txt
Normal file
1
common/djangoapps/student/tests/emails/test_body.txt
Normal file
@@ -0,0 +1 @@
|
||||
Test body.
|
||||
1
common/djangoapps/student/tests/emails/test_subject.txt
Normal file
1
common/djangoapps/student/tests/emails/test_subject.txt
Normal file
@@ -0,0 +1 @@
|
||||
Test subject.
|
||||
50
common/djangoapps/student/tests/test_massemail.py
Normal file
50
common/djangoapps/student/tests/test_massemail.py
Normal file
@@ -0,0 +1,50 @@
|
||||
"""
|
||||
Test `massemail` and `massemailtxt` commands.
|
||||
"""
|
||||
import mock
|
||||
import pkg_resources
|
||||
|
||||
from django.core import mail
|
||||
from django.test import TestCase
|
||||
|
||||
from edxmako import add_lookup
|
||||
from ..management.commands import massemail
|
||||
from ..management.commands import massemailtxt
|
||||
|
||||
|
||||
class TestMassEmailCommands(TestCase):
|
||||
"""
|
||||
Test `massemail` and `massemailtxt` commands.
|
||||
"""
|
||||
|
||||
@mock.patch('edxmako.LOOKUP', {})
|
||||
def test_massemailtxt(self):
|
||||
"""
|
||||
Test the `massemailtext` command.
|
||||
"""
|
||||
add_lookup('main', '', package=__name__)
|
||||
userfile = pkg_resources.resource_filename(__name__, 'test_massemail_users.txt')
|
||||
command = massemailtxt.Command()
|
||||
command.handle(userfile, 'test', '/dev/null', 10)
|
||||
self.assertEqual(len(mail.outbox), 2)
|
||||
self.assertEqual(mail.outbox[0].to, ["Fred"])
|
||||
self.assertEqual(mail.outbox[0].subject, "Test subject.")
|
||||
self.assertEqual(mail.outbox[0].body.strip(), "Test body.")
|
||||
self.assertEqual(mail.outbox[1].to, ["Barney"])
|
||||
self.assertEqual(mail.outbox[1].subject, "Test subject.")
|
||||
self.assertEqual(mail.outbox[1].body.strip(), "Test body.")
|
||||
|
||||
@mock.patch('edxmako.LOOKUP', {})
|
||||
@mock.patch('student.management.commands.massemail.User')
|
||||
def test_massemail(self, usercls):
|
||||
"""
|
||||
Test the `massemail` command.
|
||||
"""
|
||||
add_lookup('main', '', package=__name__)
|
||||
fred = mock.Mock()
|
||||
barney = mock.Mock()
|
||||
usercls.objects.all.return_value = [fred, barney]
|
||||
command = massemail.Command()
|
||||
command.handle('test')
|
||||
fred.email_user.assert_called_once_with('Test subject.', 'Test body.\n')
|
||||
barney.email_user.assert_called_once_with('Test subject.', 'Test body.\n')
|
||||
2
common/djangoapps/student/tests/test_massemail_users.txt
Normal file
2
common/djangoapps/student/tests/test_massemail_users.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
Fred
|
||||
Barney
|
||||
1
lms/djangoapps/django_comment_client/tests/test.mustache
Normal file
1
lms/djangoapps/django_comment_client/tests/test.mustache
Normal file
@@ -0,0 +1 @@
|
||||
Testing 1 2 3.
|
||||
@@ -1,4 +1,5 @@
|
||||
import json
|
||||
import mock
|
||||
from datetime import datetime
|
||||
from pytz import UTC
|
||||
from django.core.urlresolvers import reverse
|
||||
@@ -11,6 +12,7 @@ import django_comment_client.utils as utils
|
||||
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE
|
||||
from edxmako import add_lookup
|
||||
|
||||
|
||||
class DictionaryTestCase(TestCase):
|
||||
@@ -505,3 +507,17 @@ class JsonResponseTestCase(TestCase, UnicodeTestMixin):
|
||||
response = utils.JsonResponse(text)
|
||||
reparsed = json.loads(response.content)
|
||||
self.assertEqual(reparsed, text)
|
||||
|
||||
|
||||
class RenderMustacheTests(TestCase):
|
||||
"""
|
||||
Test the `render_mustache` utility function.
|
||||
"""
|
||||
|
||||
@mock.patch('edxmako.LOOKUP', {})
|
||||
def test_it(self):
|
||||
"""
|
||||
Basic test.
|
||||
"""
|
||||
add_lookup('main', '', package=__name__)
|
||||
self.assertEqual(utils.render_mustache('test.mustache', {}), 'Testing 1 2 3.\n')
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import pytz
|
||||
from collections import defaultdict
|
||||
import logging
|
||||
import urllib
|
||||
from datetime import datetime
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
@@ -12,7 +11,7 @@ from django.utils import simplejson
|
||||
from django_comment_common.models import Role, FORUM_ROLE_STUDENT
|
||||
from django_comment_client.permissions import check_permissions_by_view
|
||||
|
||||
import edxmako
|
||||
from edxmako import lookup_template
|
||||
import pystache_custom as pystache
|
||||
|
||||
from xmodule.modulestore.django import modulestore
|
||||
@@ -307,7 +306,7 @@ def get_metadata_for_threads(course_id, threads, user, user_info):
|
||||
|
||||
|
||||
def render_mustache(template_name, dictionary, *args, **kwargs):
|
||||
template = edxmako.lookup['main'].get_template(template_name).source
|
||||
template = lookup_template('main', template_name).source
|
||||
return pystache.render(template, dictionary)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user