Opened 8 years ago

Closed 6 years ago

Last modified 6 years ago

#17529 closed Bug (fixed)

get_template_from_string default arguments break assertTemplateUsed

Reported by: Ian Clelland Owned by: Unai Zalakain
Component: Template system Version: master
Severity: Normal Keywords: assertTemplateUsed get_template_from_string template testing
Cc: claude@… Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


django.template.loader.get_template_from_string only requires a single argument -- the template source string. The origin and name parameters are optional, and default to None. (This function is never called in the Django codebase with missing parameters, except in the test suite)

If the name parameter is left out, it is explicitly passed as None to the Template constructor, and so the new template receives a name of None, rather than the default "<Unknown Template>".

django.test.testcases.TransactionTestCase.assertTemplateUsed contains an assertion which joins the 'name' parameter of all of the templates in the request. If any templates used were constructed without a name, the None in the list will cause a TypeError before the assertion can even be tested.

This is the simplest project I can create which exemplifies this problem:


from django.conf.urls import patterns, include, url

urlpatterns = patterns('',
    url(r'^test/$', 'templatetest.views.test_view', name='test'),


from django.template import loader, Context
from django.http import HttpResponse

def test_view(request):
    template = loader.get_template_from_string("This is a string-based template")
    return HttpResponse(template.render(Context({})))


from django.test import TestCase

class TemplateFromStringTest(TestCase):
    def test_none_template_used(self):
        response = self.client.get('/test/')
        self.assertTemplateUsed(response, "base.html")

./ test templatetest:

Creating test database for alias 'default'...
ERROR: test_template_used (templatetest.tests.TemplateFromStringTest)
Traceback (most recent call last):
  File "/Users/ian/Code/Tests/django-template-test/templatetest/templatetest/", line 6, in test_template_used
    self.assertTemplateUsed(response, "base.html")
  File "/Users/ian/.virtualenvs/django-trunk/lib/python2.7/site-packages/django/test/", line 629, in assertTemplateUsed
    (template_name, u', '.join(template_names)))
TypeError: sequence item 0: expected string or Unicode, NoneType found

Ran 1 test in 0.133s

FAILED (errors=1)
Destroying test database for alias 'default'...

I believe that either assertTemplateUsed needs to guard against None values appearing in the list of template names, or get_template_from_string needs to be modified to callTemplate.__init__ in a way which uses *that* class's default parameters, or possibly both. I'll work up a quick patch once I get a feel for the right place to fix this.

Change History (7)

comment:1 Changed 8 years ago by Ian Clelland

Component: Testing frameworkTemplate system
Version: 1.3SVN

comment:2 Changed 8 years ago by Claude Paroz

Cc: claude@… added
Triage Stage: UnreviewedAccepted

I would be tempted to fix it this way in assertTemplateUsed:

  -      template_names = [ for t in response.templates]
  +      template_names = [ for t in response.templates if]
         if not template_names:
  - + "No templates used to render the response")
  + + "No named templates used to render the response")

comment:3 Changed 8 years ago by Ian Clelland

Claude, that's in fact how I've handled it locally, in a TransactionTestCase subclass -- my only reservation is that this still leaves a difference between the objects returned from

t = loader.get_template_from_string("template source")


t = Template("template source")

So I'm torn between considering this a bug in the testing framework and a bug in the template system.

comment:4 Changed 8 years ago by Claude Paroz

I see your point. It's about the semantic of the name property of a template created from a direct string parameter, None or '<Unknown Template>'. I would vote for replacing '<Unknown Template>' by None in the Template __init__ which seems a slightly more pythonic way of stating that a property is unset. I've run the entire test suite with this change without failure.

FWIW, I traced the adding of this code: changeset:3707.

comment:5 Changed 6 years ago by Unai Zalakain

Has patch: set
Owner: changed from nobody to Unai Zalakain
Status: newassigned

PR sent:

Do I have to note this change in the release notes? It's kind of insignificant.

comment:6 Changed 6 years ago by Claude Paroz <claude@…>

Resolution: fixed
Status: assignedclosed

In 72f63bd24d44b5a4f24ad8fa27ebba96d9a507d8:

Fixed #17529 -- get_template_from_string default arguments break

get_template_from_string default arguments were breaking
assertTemplateUsed. The solution has been to return only the names of the
templates with a name attribute distinct of None. The default name
kwarg of Template has been changed to None, more pythonic than '<Unknown

comment:7 Changed 6 years ago by Unai Zalakain

Great, thanks!

Note: See TracTickets for help on using tickets.
Back to Top