Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed #12226 -- Deprecated test client Response.template attribute in…

… favor of templates attribute, which is always a list. Thanks Russell for patch review.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14106 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 501546df6f4cbb56ea94da073e8206804fef3040 1 parent d084439
@carljm carljm authored
View
32 django/test/client.py
@@ -4,6 +4,7 @@
import os
import re
import mimetypes
+import warnings
try:
from cStringIO import StringIO
except ImportError:
@@ -93,7 +94,7 @@ def store_rendered_templates(store, signal, sender, template, context, **kwargs)
"""
Stores templates and contexts that are rendered.
"""
- store.setdefault('template', []).append(template)
+ store.setdefault('templates', []).append(template)
store.setdefault('context', ContextList()).append(context)
def encode_multipart(boundary, data):
@@ -260,16 +261,25 @@ def request(self, **request):
response.request = request
# Add any rendered template detail to the response.
- # If there was only one template rendered (the most likely case),
- # flatten the list to a single element.
- for detail in ('template', 'context'):
- if data.get(detail):
- if len(data[detail]) == 1:
- setattr(response, detail, data[detail][0]);
- else:
- setattr(response, detail, data[detail])
- else:
- setattr(response, detail, None)
+ response.templates = data.get("templates", [])
+ response.context = data.get("context")
+
+ # Flatten a single context. Not really necessary anymore thanks to
+ # the __getattr__ flattening in ContextList, but has some edge-case
+ # backwards-compatibility implications.
+ if response.context and len(response.context) == 1:
+ response.context = response.context[0]
+
+ # Provide a backwards-compatible (but pending deprecation) response.template
+ def _get_template(self):
+ warnings.warn("response.template is deprecated; use response.templates instead (which is always a list)",
+ PendingDeprecationWarning)
+ if not self.templates:
+ return None
+ elif len(self.templates) == 1:
+ return self.templates[0]
+ return self.templates
+ response.__class__.template = property(_get_template)
# Update persistent cookie data.
if response.cookies:
View
4 django/test/testcases.py
@@ -443,7 +443,7 @@ def assertTemplateUsed(self, response, template_name, msg_prefix=''):
if msg_prefix:
msg_prefix += ": "
- template_names = [t.name for t in to_list(response.template)]
+ template_names = [t.name for t in response.templates]
if not template_names:
self.fail(msg_prefix + "No templates used to render the response")
self.failUnless(template_name in template_names,
@@ -459,7 +459,7 @@ def assertTemplateNotUsed(self, response, template_name, msg_prefix=''):
if msg_prefix:
msg_prefix += ": "
- template_names = [t.name for t in to_list(response.template)]
+ template_names = [t.name for t in response.templates]
self.failIf(template_name in template_names,
msg_prefix + "Template '%s' was used unexpectedly in rendering"
" the response" % template_name)
View
6 docs/internals/deprecation.txt
@@ -102,6 +102,12 @@ their deprecation, as per the :ref:`Django deprecation policy
* The ``mod_python`` request handler has been deprecated since the 1.3
release. The ``mod_wsgi`` handler should be used instead.
+ * The ``template`` attribute on :class:`~django.test.client.Response`
+ objects returned by the :ref:`test client <test-client>` has been
+ deprecated since the 1.3 release. The
+ :attr:`~django.test.client.Response.templates` attribute should be
+ used instead.
+
* 2.0
* ``django.views.defaults.shortcut()``. This function has been moved
to ``django.contrib.contenttypes.views.shortcut()`` as part of the
View
17 docs/releases/1.3.txt
@@ -106,6 +106,23 @@ If you are currently using the ``mod_python`` request handler, it is strongly
encouraged you redeploy your Django instances using :doc:`mod_wsgi
</howto/deployment/modwsgi>`.
+Test client response ``template`` attribute
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Django's :ref:`test client <test-client>` returns
+:class:`~django.test.client.Response` objects annotated with extra testing
+information. In Django versions prior to 1.3, this included a
+:attr:`~django.test.client.Response.template` attribute containing information
+about templates rendered in generating the response: either None, a single
+:class:`~django.template.Template` object, or a list of
+:class:`~django.template.Template` objects. This inconsistency in return values
+(sometimes a list, sometimes not) made the attribute difficult to work with.
+
+In Django 1.3 the :attr:`~django.test.client.Response.template` attribute is
+deprecated in favor of a new :attr:`~django.test.client.Response.templates`
+attribute, which is always a list, even if it has only a single element or no
+elements.
+
What's new in Django 1.3
========================
View
16 docs/topics/testing.txt
@@ -494,6 +494,8 @@ Testing tools
Django provides a small set of tools that come in handy when writing tests.
+.. _test-client:
+
The test client
---------------
@@ -894,15 +896,15 @@ Specifically, a ``Response`` object has the following attributes:
The HTTP status of the response, as an integer. See RFC2616_ for a full
list of HTTP status codes.
- .. attribute:: template
+ .. versionadded:: 1.3
+
+ .. attribute:: templates
- The ``Template`` instance that was used to render the final content. Use
+ A list of ``Template`` instances used to render the final content, in
+ the order they were rendered. For each template in the list, use
``template.name`` to get the template's file name, if the template was
- loaded from a file. (The name is a string such as ``'admin/index.html'``.)
-
- If the rendered page used multiple templates -- e.g., using :ref:`template
- inheritance<template-inheritance>` -- then ``template`` will be a list of
- ``Template`` instances, in the order in which they were rendered.
+ loaded from a file. (The name is a string such as
+ ``'admin/index.html'``.)
You can also use dictionary syntax on the response object to query the value
of any settings in the HTTP headers. For example, you could determine the
View
10 tests/modeltests/test_client/models.py
@@ -37,7 +37,7 @@ def test_get_view(self):
# Check some response details
self.assertContains(response, 'This is a test')
self.assertEqual(response.context['var'], u'\xf2')
- self.assertEqual(response.template.name, 'GET Template')
+ self.assertEqual(response.templates[0].name, 'GET Template')
def test_get_post_view(self):
"GET a view that normally expects POSTs"
@@ -45,7 +45,7 @@ def test_get_post_view(self):
# Check some response details
self.assertEqual(response.status_code, 200)
- self.assertEqual(response.template.name, 'Empty GET Template')
+ self.assertEqual(response.templates[0].name, 'Empty GET Template')
self.assertTemplateUsed(response, 'Empty GET Template')
self.assertTemplateNotUsed(response, 'Empty POST Template')
@@ -55,7 +55,7 @@ def test_empty_post(self):
# Check some response details
self.assertEqual(response.status_code, 200)
- self.assertEqual(response.template.name, 'Empty POST Template')
+ self.assertEqual(response.templates[0].name, 'Empty POST Template')
self.assertTemplateNotUsed(response, 'Empty GET Template')
self.assertTemplateUsed(response, 'Empty POST Template')
@@ -69,7 +69,7 @@ def test_post(self):
# Check some response details
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context['data'], '37')
- self.assertEqual(response.template.name, 'POST Template')
+ self.assertEqual(response.templates[0].name, 'POST Template')
self.failUnless('Data received' in response.content)
def test_response_headers(self):
@@ -84,7 +84,7 @@ def test_raw_post(self):
response = self.client.post("/test_client/raw_post_view/", test_doc,
content_type="text/xml")
self.assertEqual(response.status_code, 200)
- self.assertEqual(response.template.name, "Book template")
+ self.assertEqual(response.templates[0].name, "Book template")
self.assertEqual(response.content, "Blink - Malcolm Gladwell")
def test_redirect(self):
View
17 tests/regressiontests/test_client_regress/models.py
@@ -9,7 +9,7 @@
from django.test.utils import ContextList
from django.core.urlresolvers import reverse
from django.core.exceptions import SuspiciousOperation
-from django.template import TemplateDoesNotExist, TemplateSyntaxError, Context
+from django.template import TemplateDoesNotExist, TemplateSyntaxError, Context, Template
from django.template import loader
from django.test.client import encode_file
@@ -861,3 +861,18 @@ def test_client_headers_redirect(self):
self.assertEquals(response.content, "HTTP_X_ARG_CHECK: Testing 123")
self.assertRedirects(response, '/test_client_regress/check_headers/',
status_code=301, target_status_code=200)
+
+class ResponseTemplateDeprecationTests(TestCase):
+ """
+ Response.template still works backwards-compatibly, but with pending deprecation warning. Refs #12226.
+
+ """
+ def test_response_template_data(self):
+ response = self.client.get("/test_client_regress/request_data/", data={'foo':'whiz'})
+ self.assertEqual(response.template.__class__, Template)
+ self.assertEqual(response.template.name, 'base.html')
+
+ def test_response_no_template(self):
+ response = self.client.get("/test_client_regress/request_methods/")
+ self.assertEqual(response.template, None)
+
Please sign in to comment.
Something went wrong with that request. Please try again.