Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial support for Jinja2. #3

Merged
merged 3 commits into from
Jun 17, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
Changelog
#########

0.4 (xxxx)
==========

* Initial support for using the `Jinja2 <http://jinja.pocoo.org/>`_ templating
engine. See README for caveats.

0.3.1 (June 1, 2016)
====================

Expand Down
11 changes: 9 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,18 @@ arbitrary template inheritance, even if a block is defined in the child template
but not in the parent. Generally it works like ``render_to_string`` from Django,
but allows you to specify a block to render.

Features
========

* Render a specific block from a template
* Fully supports the Django templating engine
* Partially supports the `Jinja2 <http://jinja.pocoo.org/>`_ engine: it does
not currently process the ``extends`` tag.

Requirements
============

Django Render Block supports Django 1.8 and 1.9. You must use the Django
template rendering engine (the default) to render specific blocks.
Django Render Block supports Django 1.8 and 1.9.

Examples
========
Expand Down
12 changes: 12 additions & 0 deletions render_block/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

from django.template import loader
from django.template.backends.django import Template as DjangoTemplate
try:
from django.template.backends.jinja2 import Template as Jinja2Template
except ImportError:
# Most likely Jinja2 isn't installed, in that case just create a class since
# we always want it to be false anyway.
class Jinja2Template(object):
pass

from render_block.django import django_render_block
from render_block.exceptions import BlockNotFound, UnsupportedEngine
Expand Down Expand Up @@ -30,6 +37,11 @@ def render_block_to_string(template_name, block_name, context=None):
# The Django backend.
if isinstance(t, DjangoTemplate):
return django_render_block(t, block_name, context)

elif isinstance(t, Jinja2Template):
from render_block.jinja2 import jinja2_render_block
return jinja2_render_block(t, block_name, context)

else:
raise UnsupportedEngine(
'Can only render blocks from the Django template backend.')
17 changes: 17 additions & 0 deletions render_block/jinja2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from render_block.base import BlockNotFound

def jinja2_render_block(template, block_name, context):
# Get the underlying jinja2.environment.Template object.
template = template.template

# Create a new Context instance.
context = template.new_context(context)

# Try to find the wanted block.
try:
gen = template.blocks[block_name](context)
except KeyError:
raise BlockNotFound("block with name '%s' does not exist" % block_name)

# The result from above is a generator which yields unicode strings.
return u''.join([s for s in gen])
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@

# Not tested with older versions of Django.
Django==1.8.13
Jinja2==2.8
File renamed without changes.
5 changes: 5 additions & 0 deletions tests/templates/test3_jinja2.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{% extends 'test1.html' %}

{% block block1 %}{% include "include.html" %}{% endblock %}

{% block block2 %}block2 from test3 - {{ super() }}{% endblock %}
75 changes: 72 additions & 3 deletions tests/tests.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
from unittest import skip

from django.template import Context
from django.test import override_settings, TestCase
from django.utils import six

from render_block import render_block_to_string, BlockNotFound, UnsupportedEngine


class TestCases(TestCase):
class TestDjango(TestCase):
"""Test the Django templating engine."""
def assertExceptionMessageEquals(self, exception, expected):
result = exception.message if six.PY2 else exception.args[0]
self.assertEqual(expected, result)
Expand Down Expand Up @@ -38,12 +41,12 @@ def test_no_block(self):

def test_include(self):
"""Ensure that an include tag in a block still works."""
result = render_block_to_string('test3.html', 'block1')
result = render_block_to_string('test3_django.html', 'block1')
self.assertEqual(result, u'included template')

def test_super(self):
"""Test that block.super works."""
result = render_block_to_string('test3.html', 'block2')
result = render_block_to_string('test3_django.html', 'block2')
self.assertEqual(result, u'block2 from test3 - block2 from test1')

def test_subblock(self):
Expand Down Expand Up @@ -76,3 +79,69 @@ def test_different_backend(self):
render_block_to_string('test1.html', 'noblock')
self.assertExceptionMessageEquals(exc.exception,
"Can only render blocks from the Django template backend.")


@override_settings(
TEMPLATES=[{
'BACKEND': 'django.template.backends.jinja2.Jinja2',
'DIRS': ['tests/templates'],
'APP_DIRS': True,
},]
)
class TestJinja2(TestCase):
"""Test the Django templating engine."""
def assertExceptionMessageEquals(self, exception, expected):
result = exception.message if six.PY2 else exception.args[0]
self.assertEqual(expected, result)

def test_block(self):
"""Test rendering an individual block."""
result = render_block_to_string('test1.html', 'block1')
self.assertEqual(result, u'block1 from test1')

# No reason this shouldn't work, but just in case.
result = render_block_to_string('test1.html', 'block2')
self.assertEqual(result, u'block2 from test1')

def test_override(self):
"""This block is overridden in test2."""
result = render_block_to_string('test2.html', 'block1')
self.assertEqual(result, u'block1 from test2')

@skip('Not currently supported.')
def test_inherit(self):
"""This block is inherited from test1."""
result = render_block_to_string('test2.html', 'block2')
self.assertEqual(result, u'block2 from test1')

def test_no_block(self):
"""Check if there's no block available an exception is raised."""
with self.assertRaises(BlockNotFound) as exc:
render_block_to_string('test1.html', 'noblock')
self.assertExceptionMessageEquals(exc.exception,
"block with name 'noblock' does not exist")

def test_include(self):
"""Ensure that an include tag in a block still works."""
result = render_block_to_string('test3_jinja2.html', 'block1')
self.assertEqual(result, u'included template')

@skip('Not currently supported.')
def test_super(self):
"""Test that super() works."""
result = render_block_to_string('test3_jinja2.html', 'block2')
self.assertEqual(result, u'block2 from test3 - block2 from test1')

def test_subblock(self):
"""Test that a block within a block works."""
result = render_block_to_string('test5.html', 'block1')
self.assertEqual(result, u'block3 from test5')

result = render_block_to_string('test5.html', 'block3')
self.assertEqual(result, u'block3 from test5')

def test_context(self):
"""Test that a context is properly rendered in a template."""
data = u'block2 from test5'
result = render_block_to_string('test5.html', 'block2', {'foo': data})
self.assertEqual(result, data)
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ passenv = TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH
commands =
python manage.py test
deps =
Jinja2==2.8
django18: Django>=1.8,<1.9
django19: Django>=1.9,<1.10
django110: https://codeload.github.com/django/django/zip/master