1
0
mirror of https://github.com/django/django.git synced 2025-07-04 09:49:12 +00:00

boulder-oracle-sprint: Merged to [5173]

git-svn-id: http://code.djangoproject.com/svn/django/branches/boulder-oracle-sprint@5174 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Boulder Sprinters 2007-05-08 17:46:05 +00:00
parent a275d3da8e
commit 7f13278f86
27 changed files with 271 additions and 81 deletions

View File

@ -43,12 +43,14 @@ answer newbie questions, and generally made Django that much better:
adurdin@gmail.com
alang@bright-green.com
Marty Alchin <gulopine@gamemusic.org>
Daniel Alves Barbosa de Oliveira Vaz <danielvaz@gmail.com>
Andreas
andy@jadedplanet.net
Fabrice Aneche <akh@nobugware.com>
ant9000@netwise.it
David Ascher <http://ascher.ca/>
david@kazserve.org
Arthur <avandorp@gmail.com>
axiak@mit.edu
Jiri Barton
@ -68,6 +70,7 @@ answer newbie questions, and generally made Django that much better:
Amit Chakradeo <http://amit.chakradeo.net/>
ChaosKCW
ivan.chelubeev@gmail.com
Bryan Chow <bryan at verdjn dot com>
Ian Clelland <clelland@gmail.com>
crankycoder@gmail.com
Matt Croydon <http://www.postneo.com/>
@ -145,7 +148,7 @@ answer newbie questions, and generally made Django that much better:
lerouxb@gmail.com
Waylan Limberg <waylan@gmail.com>
limodou
mattmcc
Matt McClanahan <http://mmcc.cx/>
Martin Maney <http://www.chipy.org/Martin_Maney>
masonsimon+django@gmail.com
Manuzhai

View File

@ -367,11 +367,11 @@ msgstr "Abmelden"
#: contrib/admin/templates/admin/base_site.html:4
msgid "Django site admin"
msgstr "Django Systemverwaltung"
msgstr "Django-Systemverwaltung"
#: contrib/admin/templates/admin/base_site.html:7
msgid "Django administration"
msgstr "Django Verwaltung"
msgstr "Django-Verwaltung"
#: contrib/admin/templates/admin/change_form.html:15
#: contrib/admin/templates/admin/index.html:28
@ -385,7 +385,7 @@ msgstr "Geschichte"
#: contrib/admin/templates/admin/change_form.html:22
msgid "View on site"
msgstr "Im Web Anzeigen"
msgstr "Im Web anzeigen"
#: contrib/admin/templates/admin/change_form.html:32
#: contrib/admin/templates/admin/auth/user/change_password.html:24
@ -614,7 +614,7 @@ msgid ""
"your computer is \"internal\").</p>\n"
msgstr ""
"\n"
"<p class=\"help\">Um Bookmarklets zu installieren müssen diese Links in die\n"
"<p class=\"help\">Um Bookmarklets zu installieren, müssen diese Links in die\n"
"Browser-Werkzeugleiste gezogen werden, oder mittels rechter Maustaste in "
"die\n"
"Bookmarks gespeichert werden. Danach können die Bookmarklets von jeder "
@ -998,7 +998,7 @@ msgstr "%s ist scheinbar kein urlpattern Objekt"
#: contrib/admin/views/main.py:223
msgid "Site administration"
msgstr "Website Verwaltung"
msgstr "Website-Verwaltung"
#: contrib/admin/views/main.py:271 contrib/admin/views/main.py:356
#, python-format
@ -1023,7 +1023,7 @@ msgstr "und"
#: contrib/admin/views/main.py:337
#, python-format
msgid "Changed %s."
msgstr "%s geändert"
msgstr "%s geändert."
#: contrib/admin/views/main.py:339
#, python-format
@ -1490,8 +1490,8 @@ msgstr "Ihr Name:"
msgid ""
"This rating is required because you've entered at least one other rating."
msgstr ""
"Diese Abstimmung ist zwingend erforderlich, da Du an mindestens einer "
"weiteren Abstimmung teilnimmst."
"Diese Abstimmung ist zwingend erforderlich, da Sie an mindestens einer "
"weiteren Abstimmung teilnehmen."
#: contrib/comments/views/comments.py:111
#, python-format

View File

@ -11,7 +11,10 @@ class AdminLogNode(template.Node):
return "<GetAdminLog Node>"
def render(self, context):
if self.user is not None and not self.user.isdigit():
if self.user is None:
context[self.varname] = LogEntry.objects.all().select_related()[:self.limit]
else:
if not self.user.isdigit():
self.user = context[self.user].id
context[self.varname] = LogEntry.objects.filter(user__id__exact=self.user).select_related()[:self.limit]
return ''

View File

@ -54,3 +54,6 @@ class BaseCache(object):
Returns True if the key is in the cache and has not expired.
"""
return self.get(key) is not None
__contains__ = has_key

View File

@ -260,14 +260,14 @@ def _get_sql_for_pending_references(model, pending_references):
def _get_many_to_many_sql_for_model(model):
from django.db import backend, get_creation_module
from django.db.models import GenericRel
from django.contrib.contenttypes import generic
data_types = get_creation_module().DATA_TYPES
opts = model._meta
final_output = []
for f in opts.many_to_many:
if not isinstance(f.rel, GenericRel):
if not isinstance(f.rel, generic.GenericRel):
tablespace = f.db_tablespace or opts.db_tablespace
if tablespace and backend.supports_tablespaces and backend.autoindexes_primary_keys:
tablespace_sql = ' ' + backend.get_tablespace_sql(tablespace, inline=True)

View File

@ -8,7 +8,6 @@ from django.db.models.manager import Manager
from django.db.models.base import Model, AdminOptions
from django.db.models.fields import *
from django.db.models.fields.related import ForeignKey, OneToOneField, ManyToManyField, ManyToOneRel, ManyToManyRel, OneToOneRel, TABULAR, STACKED
from django.db.models.fields.generic import GenericRelation, GenericRel, GenericForeignKey
from django.db.models import signals
from django.utils.functional import curry
from django.utils.text import capfirst

View File

@ -42,11 +42,11 @@ class ModelBase(type):
new_class._meta.parents.append(base)
new_class._meta.parents.extend(base._meta.parents)
model_module = sys.modules[new_class.__module__]
if getattr(new_class._meta, 'app_label', None) is None:
# Figure out the app_label by looking one level up.
# For 'django.contrib.sites.models', this would be 'sites'.
model_module = sys.modules[new_class.__module__]
new_class._meta.app_label = model_module.__name__.split('.')[-2]
# Bail out early if we have already created this class.

View File

@ -1,10 +1,9 @@
from django.db import backend, connection, transaction
from django.db.models.fields import DateField, FieldDoesNotExist
from django.db.models.fields.generic import GenericRelation
from django.db.models import signals
from django.db.models import signals, loading
from django.dispatch import dispatcher
from django.utils.datastructures import SortedDict
from django.conf import settings
from django.contrib.contenttypes import generic
import datetime
import operator
import re
@ -1091,7 +1090,7 @@ def delete_objects(seen_objs):
pk_list = [pk for pk,instance in seen_objs[cls]]
for related in cls._meta.get_all_related_many_to_many_objects():
if not isinstance(related.field, GenericRelation):
if not isinstance(related.field, generic.GenericRelation):
for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
cursor.execute("DELETE FROM %s WHERE %s IN (%s)" % \
(qn(related.field.m2m_db_table()),
@ -1099,7 +1098,7 @@ def delete_objects(seen_objs):
','.join(['%s' for pk in pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE]])),
pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE])
for f in cls._meta.many_to_many:
if isinstance(f, GenericRelation):
if isinstance(f, generic.GenericRelation):
from django.contrib.contenttypes.models import ContentType
query_extra = 'AND %s=%%s' % f.rel.to._meta.get_field(f.content_type_field_name).column
args_extra = [ContentType.objects.get_for_model(cls).id]

View File

@ -99,6 +99,10 @@ libraries = {}
# global list of libraries to load by default for a new parser
builtins = []
# True if TEMPLATE_STRING_IF_INVALID contains a format string (%s). None means
# uninitialised.
invalid_var_format_string = None
class TemplateSyntaxError(Exception):
def __str__(self):
try:
@ -575,6 +579,11 @@ class FilterExpression(object):
obj = None
else:
if settings.TEMPLATE_STRING_IF_INVALID:
global invalid_var_format_string
if invalid_var_format_string is None:
invalid_var_format_string = '%s' in settings.TEMPLATE_STRING_IF_INVALID
if invalid_var_format_string:
return settings.TEMPLATE_STRING_IF_INVALID % self.var
return settings.TEMPLATE_STRING_IF_INVALID
else:
obj = settings.TEMPLATE_STRING_IF_INVALID

View File

@ -1,7 +1,7 @@
import re, doctest, unittest
from urlparse import urlparse
from django.db import transaction
from django.core import management
from django.core import management, mail
from django.db.models import get_apps
from django.test.client import Client
@ -33,23 +33,27 @@ class DocTestRunner(doctest.DocTestRunner):
transaction.rollback_unless_managed()
class TestCase(unittest.TestCase):
def install_fixtures(self):
"""If the Test Case class has a 'fixtures' member, clear the database and
install the named fixtures at the start of each test.
def _pre_setup(self):
"""Perform any pre-test setup. This includes:
* If the Test Case class has a 'fixtures' member, clearing the
database and installing the named fixtures at the start of each test.
* Clearing the mail test outbox.
"""
management.flush(verbosity=0, interactive=False)
if hasattr(self, 'fixtures'):
management.load_data(self.fixtures, verbosity=0)
mail.outbox = []
def run(self, result=None):
"""Wrapper around default run method so that user-defined Test Cases
automatically call install_fixtures without having to include a call to
super().
"""Wrapper around default run method to perform common Django test set up.
This means that user-defined Test Cases aren't required to include a call
to super().setUp().
"""
self.client = Client()
self.install_fixtures()
self._pre_setup()
super(TestCase, self).run(result)
def assertRedirects(self, response, expected_path):

View File

@ -1,7 +1,7 @@
import sys, time
from django.conf import settings
from django.db import connection, backend, get_creation_module
from django.core import management
from django.core import management, mail
from django.dispatch import dispatcher
from django.test import signals
from django.template import Template
@ -18,24 +18,54 @@ def instrumented_test_render(self, context):
dispatcher.send(signal=signals.template_rendered, sender=self, template=self, context=context)
return self.nodelist.render(context)
class TestSMTPConnection(object):
"""A substitute SMTP connection for use during test sessions.
The test connection stores email messages in a dummy outbox,
rather than sending them out on the wire.
"""
def __init__(*args, **kwargs):
pass
def open(self):
"Mock the SMTPConnection open() interface"
pass
def close(self):
"Mock the SMTPConnection close() interface"
pass
def send_messages(self, messages):
"Redirect messages to the dummy outbox"
mail.outbox.extend(messages)
def setup_test_environment():
"""Perform any global pre-test setup. This involves:
- Installing the instrumented test renderer
- Diverting the email sending functions to a test buffer
"""
Template.original_render = Template.render
Template.render = instrumented_test_render
mail.original_SMTPConnection = mail.SMTPConnection
mail.SMTPConnection = TestSMTPConnection
mail.outbox = []
def teardown_test_environment():
"""Perform any global post-test teardown. This involves:
- Restoring the original test renderer
- Restoring the email sending functions
"""
Template.render = Template.original_render
del Template.original_render
mail.SMTPConnection = mail.original_SMTPConnection
del mail.original_SMTPConnection
del mail.outbox
def _set_autocommit(connection):
"Make sure a connection is in autocommit mode."
if hasattr(connection.connection, "autocommit"):

View File

@ -396,10 +396,11 @@ To run the tests, ``cd`` to the ``tests/`` directory and type::
./runtests.py --settings=path.to.django.settings
Yes, the unit tests need a settings module, but only for database connection
info -- the ``DATABASE_ENGINE``, ``DATABASE_USER`` and ``DATABASE_PASSWORD``.
You will also need a ``ROOT_URLCONF`` setting (its value is ignored; it just
needs to be present) and a ``SITE_ID`` setting (any integer value will do) in
order for all the tests to pass.
info -- the ``DATABASE_NAME`` (required, but will be ignored),
``DATABASE_ENGINE``, ``DATABASE_USER`` and ``DATABASE_PASSWORD`` settings. You
will also need a ``ROOT_URLCONF`` setting (its value is ignored; it just needs
to be present) and a ``SITE_ID`` setting (any integer value will do) in order
for all the tests to pass.
The unit tests will not touch your existing databases; they create a new
database, called ``django_test_db``, which is deleted when the tests are

View File

@ -310,7 +310,7 @@ To create or update a message file, run this command::
...where ``de`` is the language code for the message file you want to create.
The language code, in this case, is in locale format. For example, it's
``pt_BR`` for Brazilian and ``de_AT`` for Austrian German.
``pt_BR`` for Brazilian Portugese and ``de_AT`` for Austrian German.
The script should be run from one of three places:
@ -463,8 +463,8 @@ following this algorithm:
Notes:
* In each of these places, the language preference is expected to be in the
standard language format, as a string. For example, Brazilian is
``pt-br``.
standard language format, as a string. For example, Brazilian Portugese
is ``pt-br``.
* If a base language is available but the sublanguage specified is not,
Django uses the base language. For example, if a user specifies ``de-at``
(Austrian German) but Django only has ``de`` available, Django uses

View File

@ -459,7 +459,7 @@ string, not ``NULL``.
``blank``
~~~~~~~~~
If ``True``, the field is allowed to be blank.
If ``True``, the field is allowed to be blank. Default is ``False``.
Note that this is different than ``null``. ``null`` is purely
database-related, whereas ``blank`` is validation-related. If a field has

View File

@ -109,7 +109,7 @@ serializer, you must pass ``ensure_ascii=False`` as a parameter to the
For example::
json_serializer = serializers.get_serializer("json")
json_serializer = serializers.get_serializer("json")()
json_serializer.serialize(queryset, ensure_ascii=False, stream=response)
Writing custom serializers

View File

@ -2,8 +2,6 @@
The sitemap framework
=====================
**New in Django development version**.
Django comes with a high-level sitemap-generating framework that makes
creating sitemap_ XML files easy.

View File

@ -212,6 +212,9 @@ template tags. If an invalid variable is provided to one of these template
tags, the variable will be interpreted as ``None``. Filters are always
applied to invalid variables within these template tags.
If ``TEMPLATE_STRING_IF_INVALID`` contains a ``'%s'``, the format marker will
be replaced with the name of the invalid variable.
.. admonition:: For debug purposes only!
While ``TEMPLATE_STRING_IF_INVALID`` can be a useful debugging tool,
@ -866,7 +869,7 @@ current context, available in the ``render`` method::
try:
actual_date = resolve_variable(self.date_to_be_formatted, context)
return actual_date.strftime(self.format_string)
except VariableDoesNotExist:
except template.VariableDoesNotExist:
return ''
``resolve_variable`` will try to resolve ``blog_entry.date_updated`` and then

View File

@ -177,6 +177,7 @@ tools that can be used to establish tests and test conditions.
* `Test Client`_
* `TestCase`_
* `Email services`_
Test Client
-----------
@ -289,9 +290,9 @@ can be invoked on the ``Client`` instance.
Testing Responses
~~~~~~~~~~~~~~~~~
The ``get()``, ``post()`` and ``login()`` methods all return a Response
object. This Response object has the following properties that can be used
for testing purposes:
The ``get()`` and ``post()`` methods both return a Response object. This
Response object has the following properties that can be used for testing
purposes:
=============== ==========================================================
Property Description
@ -453,6 +454,15 @@ This flush/load procedure is repeated for each test in the test case, so you
can be certain that the outcome of a test will not be affected by
another test, or the order of test execution.
Emptying the test outbox
~~~~~~~~~~~~~~~~~~~~~~~~
**New in Django development version**
At the start of each test case, in addition to installing fixtures,
Django clears the contents of the test email outbox.
For more detail on email services during tests, see `Email services`_.
Assertions
~~~~~~~~~~
**New in Django development version**
@ -491,6 +501,49 @@ that can be useful in testing the behavior of web sites.
Assert that the template with the given name was used in rendering the
response.
Email services
--------------
**New in Django development version**
If your view makes use of the `Django email services`_, you don't really
want email to be sent every time you run a test using that view.
When the Django test framework is initialized, it transparently replaces the
normal `SMTPConnection`_ class with a dummy implementation that redirects all
email to a dummy outbox. This outbox, stored as ``django.core.mail.outbox``,
is a simple list of all `EmailMessage`_ instances that have been sent.
For example, during test conditions, it would be possible to run the following
code::
from django.core import mail
# Send message
mail.send_mail('Subject here', 'Here is the message.', 'from@example.com',
['to@example.com'], fail_silently=False)
# One message has been sent
self.assertEqual(len(mail.outbox), 1)
# Subject of first message is correct
self.assertEqual(mail.outbox[0].subject, 'Subject here')
The ``mail.outbox`` object does not exist under normal execution conditions.
The outbox is created during test setup, along with the dummy `SMTPConnection`_.
When the test framework is torn down, the standard `SMTPConnection`_ class
is restored, and the test outbox is destroyed.
As noted `previously`_, the test outbox is emptied at the start of every
test in a Django TestCase. To empty the outbox manually, assign the empty list
to mail.outbox::
from django.core import mail
# Empty the test outbox
mail.outbox = []
.. _`Django email services`: ../email/
.. _`SMTPConnection`: ../email/#the-emailmessage-and-smtpconnection-classes
.. _`EmailMessage`: ../email/#the-emailmessage-and-smtpconnection-classes
.. _`previously`: #emptying-the-test-outbox
Running tests
=============
@ -516,6 +569,10 @@ database settings will the same as they would be for the project normally.
If you wish to use a name other than the default for the test database,
you can use the ``TEST_DATABASE_NAME`` setting to provide a name.
The test database is created by the user in the ``DATABASE_USER`` setting.
This user needs to have sufficient privileges to create a new database on the
system.
Once the test database has been established, Django will run your tests.
If everything goes well, at the end you'll see::
@ -606,11 +663,12 @@ a number of utility methods in the ``django.test.utils`` module.
``setup_test_environment()``
Performs any global pre-test setup, such as the installing the
instrumentation of the template rendering system.
instrumentation of the template rendering system and setting up
the dummy SMTPConnection.
``teardown_test_environment()``
Performs any global post-test teardown, such as removing the instrumentation
of the template rendering system.
of the template rendering system and restoring normal email services.
``create_test_db(verbosity=1, autoclobber=False)``
Creates a new test database, and run ``syncdb`` against it.

View File

@ -11,6 +11,7 @@ from complete).
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
class TaggedItem(models.Model):
"""A tag on an item."""
@ -18,7 +19,7 @@ class TaggedItem(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = models.GenericForeignKey()
content_object = generic.GenericForeignKey()
class Meta:
ordering = ["tag"]
@ -30,7 +31,7 @@ class Animal(models.Model):
common_name = models.CharField(maxlength=150)
latin_name = models.CharField(maxlength=150)
tags = models.GenericRelation(TaggedItem)
tags = generic.GenericRelation(TaggedItem)
def __str__(self):
return self.common_name
@ -39,7 +40,7 @@ class Vegetable(models.Model):
name = models.CharField(maxlength=150)
is_yucky = models.BooleanField(default=True)
tags = models.GenericRelation(TaggedItem)
tags = generic.GenericRelation(TaggedItem)
def __str__(self):
return self.name

View File

@ -20,6 +20,7 @@ rather than the HTML rendered to the end-user.
"""
from django.test import Client, TestCase
from django.core import mail
class ClientTest(TestCase):
fixtures = ['testdata.json']
@ -232,3 +233,36 @@ class ClientTest(TestCase):
self.fail('Should raise an error')
except KeyError:
pass
def test_mail_sending(self):
"Test that mail is redirected to a dummy outbox during test setup"
response = self.client.get('/test_client/mail_sending_view/')
self.assertEqual(response.status_code, 200)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, 'Test message')
self.assertEqual(mail.outbox[0].body, 'This is a test email')
self.assertEqual(mail.outbox[0].from_email, 'from@example.com')
self.assertEqual(mail.outbox[0].to[0], 'first@example.com')
self.assertEqual(mail.outbox[0].to[1], 'second@example.com')
def test_mass_mail_sending(self):
"Test that mass mail is redirected to a dummy outbox during test setup"
response = self.client.get('/test_client/mass_mail_sending_view/')
self.assertEqual(response.status_code, 200)
self.assertEqual(len(mail.outbox), 2)
self.assertEqual(mail.outbox[0].subject, 'First Test message')
self.assertEqual(mail.outbox[0].body, 'This is the first test email')
self.assertEqual(mail.outbox[0].from_email, 'from@example.com')
self.assertEqual(mail.outbox[0].to[0], 'first@example.com')
self.assertEqual(mail.outbox[0].to[1], 'second@example.com')
self.assertEqual(mail.outbox[1].subject, 'Second Test message')
self.assertEqual(mail.outbox[1].body, 'This is the second test email')
self.assertEqual(mail.outbox[1].from_email, 'from@example.com')
self.assertEqual(mail.outbox[1].to[0], 'second@example.com')
self.assertEqual(mail.outbox[1].to[1], 'third@example.com')

View File

@ -11,5 +11,7 @@ urlpatterns = patterns('',
(r'^form_view_with_template/$', views.form_view_with_template),
(r'^login_protected_view/$', views.login_protected_view),
(r'^session_view/$', views.session_view),
(r'^broken_view/$', views.broken_view)
(r'^broken_view/$', views.broken_view),
(r'^mail_sending_view/$', views.mail_sending_view),
(r'^mass_mail_sending_view/$', views.mass_mail_sending_view)
)

View File

@ -1,4 +1,5 @@
from xml.dom.minidom import parseString
from django.core.mail import EmailMessage, SMTPConnection
from django.template import Context, Template
from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth.decorators import login_required
@ -124,3 +125,28 @@ def session_view(request):
def broken_view(request):
"""A view which just raises an exception, simulating a broken view."""
raise KeyError("Oops! Looks like you wrote some bad code.")
def mail_sending_view(request):
EmailMessage(
"Test message",
"This is a test email",
"from@example.com",
['first@example.com', 'second@example.com']).send()
return HttpResponse("Mail sent")
def mass_mail_sending_view(request):
m1 = EmailMessage(
'First Test message',
'This is the first test email',
'from@example.com',
['first@example.com', 'second@example.com'])
m2 = EmailMessage(
'Second Test message',
'This is the second test email',
'from@example.com',
['second@example.com', 'third@example.com'])
c = SMTPConnection()
c.send_messages([m1,m2])
return HttpResponse("Mail sent")

View File

@ -46,6 +46,11 @@ class Cache(unittest.TestCase):
self.assertEqual(cache.has_key("hello"), True)
self.assertEqual(cache.has_key("goodbye"), False)
def test_in(self):
cache.set("hello", "goodbye")
self.assertEqual("hello" in cache, True)
self.assertEqual("goodbye" in cache, False)
def test_data_types(self):
# test data types
stuff = {

View File

@ -6,6 +6,7 @@ This class sets up a model for each model field type
"""
from django.db import models
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
# The following classes are for testing basic data
@ -80,7 +81,7 @@ class Tag(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = models.GenericForeignKey()
content_object = generic.GenericForeignKey()
class Meta:
ordering = ["data"]
@ -88,7 +89,7 @@ class Tag(models.Model):
class GenericData(models.Model):
data = models.CharField(maxlength=30)
tags = models.GenericRelation(Tag)
tags = generic.GenericRelation(Tag)
# The following test classes are all for validation
# of related objects; in particular, forward, backward,

View File

@ -586,6 +586,8 @@ class Templates(unittest.TestCase):
'invalidstr03': ('{% for v in var %}({{ v }}){% endfor %}', {}, ''),
'invalidstr04': ('{% if var %}Yes{% else %}No{% endif %}', {}, 'No'),
'invalidstr04': ('{% if var|default:"Foo" %}Yes{% else %}No{% endif %}', {}, 'Yes'),
'invalidstr05': ('{{ var }}', {}, ('', 'INVALID %s', 'var')),
'invalidstr06': ('{{ var.prop }}', {'var': {}}, ('', 'INVALID %s', 'var.prop')),
### MULTILINE #############################################################
@ -737,6 +739,7 @@ class Templates(unittest.TestCase):
# Set TEMPLATE_STRING_IF_INVALID to a known string
old_invalid = settings.TEMPLATE_STRING_IF_INVALID
expected_invalid_str = 'INVALID'
for name, vals in tests:
install()
@ -744,6 +747,10 @@ class Templates(unittest.TestCase):
if isinstance(vals[2], tuple):
normal_string_result = vals[2][0]
invalid_string_result = vals[2][1]
if '%s' in invalid_string_result:
expected_invalid_str = 'INVALID %s'
invalid_string_result = invalid_string_result % vals[2][2]
template.invalid_var_format_string = True
else:
normal_string_result = vals[2]
invalid_string_result = vals[2]
@ -754,7 +761,7 @@ class Templates(unittest.TestCase):
activate('en-us')
for invalid_str, result in [('', normal_string_result),
('INVALID', invalid_string_result)]:
(expected_invalid_str, invalid_string_result)]:
settings.TEMPLATE_STRING_IF_INVALID = invalid_str
try:
output = loader.get_template(name).render(template.Context(vals[1]))
@ -768,6 +775,10 @@ class Templates(unittest.TestCase):
if 'LANGUAGE_CODE' in vals[1]:
deactivate()
if template.invalid_var_format_string:
expected_invalid_str = 'INVALID'
template.invalid_var_format_string = False
loader.template_source_loaders = old_template_loaders
deactivate()
settings.TEMPLATE_DEBUG = old_td