Commits

Martin von Löwis committed f75c667 Merge

merged

Comments (0)

Files changed (56)

     Sengtha Chay <sengtha@e-khmer.com>
     ivan.chelubeev@gmail.com
     Bryan Chow <bryan at verdjn dot com>
+    Tom Christie <tom@tomchristie.com>
     Antonis Christofides <anthony@itia.ntua.gr>
     Michal Chruszcz <troll@pld-linux.org>
     Can Burak Çilingir <canburak@cs.bilgi.edu.tr>
 
     * Follow the instructions in the "Unit tests" section of
       docs/internals/contributing/writing-code/unit-tests.txt, published online at
-      http://docs.djangoproject.com/en/dev/internals/contributing/#running-the-unit-tests
+      https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/unit-tests/#running-the-unit-tests
 
 

django/conf/global_settings.py

 SEND_BROKEN_LINK_EMAILS = False
 
 # Database connection info.
-# Legacy format
-DATABASE_ENGINE = ''           # 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
-DATABASE_NAME = ''             # Or path to database file if using sqlite3.
-DATABASE_USER = ''             # Not used with sqlite3.
-DATABASE_PASSWORD = ''         # Not used with sqlite3.
-DATABASE_HOST = ''             # Set to empty string for localhost. Not used with sqlite3.
-DATABASE_PORT = ''             # Set to empty string for default. Not used with sqlite3.
-DATABASE_OPTIONS = {}          # Set to empty dictionary for default.
-
-# New format
 DATABASES = {
 }
 
 # The name of the class to use to run the test suite
 TEST_RUNNER = 'django.test.simple.DjangoTestSuiteRunner'
 
-# The name of the database to use for testing purposes.
-# If None, a name of 'test_' + DATABASE_NAME will be assumed
-TEST_DATABASE_NAME = None
-
-# Strings used to set the character set and collation order for the test
-# database. These values are passed literally to the server, so they are
-# backend-dependent. If None, no special settings are sent (system defaults are
-# used).
-TEST_DATABASE_CHARSET = None
-TEST_DATABASE_COLLATION = None
-
 ############
 # FIXTURES #
 ############

django/contrib/admindocs/utils.py

 "Misc. utility functions/classes for admin documentation generator."
 
-import re, sys
-if sys.version_info < (2,5):
-    from email.Parser import HeaderParser
-    from email.Errors import HeaderParseError
-else:
-    from email.parser import HeaderParser
-    from email.errors import HeaderParseError
+import re
+from email.parser import HeaderParser
+from email.errors import HeaderParseError
+
 from django.utils.safestring import mark_safe
 from django.core.urlresolvers import reverse
 from django.utils.encoding import smart_str

django/contrib/auth/management/__init__.py

         "content_type", "codename"
     ))
 
-    for ctype, (codename, name) in searched_perms:
-        # If the permissions exists, move on.
-        if (ctype.pk, codename) in all_perms:
-            continue
-        p = auth_app.Permission.objects.create(
-            codename=codename,
-            name=name,
-            content_type=ctype
-        )
-        if verbosity >= 2:
-            print "Adding permission '%s'" % p
+    objs = [
+        auth_app.Permission(codename=codename, name=name, content_type=ctype)
+        for ctype, (codename, name) in searched_perms
+        if (ctype.pk, codename) not in all_perms
+    ]
+    auth_app.Permission.objects.bulk_create(objs)
+    if verbosity >= 2:
+        for obj in objs:
+            print "Adding permission '%s'" % obj
 
 
 def create_superuser(app, created_models, verbosity, **kwargs):

django/contrib/comments/forms.py

File contents unchanged.

django/contrib/comments/templatetags/comments.py

     def lookup_content_type(token, tagname):
         try:
             app, model = token.split('.')
-            return ContentType.objects.get(app_label=app, model=model)
+            return ContentType.objects.get_by_natural_key(app, model)
         except ValueError:
             raise template.TemplateSyntaxError("Third argument in %r must be in the format 'app.model'" % tagname)
         except ContentType.DoesNotExist:

django/contrib/contenttypes/management.py

     entries that no longer have a matching model class.
     """
     ContentType.objects.clear_cache()
-    content_types = list(ContentType.objects.filter(app_label=app.__name__.split('.')[-2]))
     app_models = get_models(app)
     if not app_models:
         return
-    for klass in app_models:
-        opts = klass._meta
-        try:
-            ct = ContentType.objects.get(app_label=opts.app_label,
-                                         model=opts.object_name.lower())
-            content_types.remove(ct)
-        except ContentType.DoesNotExist:
-            ct = ContentType(name=smart_unicode(opts.verbose_name_raw),
-                app_label=opts.app_label, model=opts.object_name.lower())
-            ct.save()
-            if verbosity >= 2:
-                print "Adding content type '%s | %s'" % (ct.app_label, ct.model)
-    # The presence of any remaining content types means the supplied app has an
-    # undefined model. Confirm that the content type is stale before deletion.
-    if content_types:
+    # They all have the same app_label, get the first one.
+    app_label = app_models[0]._meta.app_label
+    app_models = dict(
+        (model._meta.object_name.lower(), model)
+        for model in app_models
+    )
+    # Get all the content types
+    content_types = dict(
+        (ct.model, ct)
+        for ct in ContentType.objects.filter(app_label=app_label)
+    )
+    to_remove = [
+        ct
+        for (model_name, ct) in content_types.iteritems()
+        if model_name not in app_models
+    ]
+
+    cts = ContentType.objects.bulk_create([
+        ContentType(
+            name=smart_unicode(model._meta.verbose_name_raw),
+            app_label=app_label,
+            model=model_name,
+        )
+        for (model_name, model) in app_models.iteritems()
+        if model_name not in content_types
+    ])
+    if verbosity >= 2:
+        for ct in cts:
+            print "Adding content type '%s | %s'" % (ct.app_label, ct.model)
+
+    # Confirm that the content type is stale before deletion.
+    if to_remove:
         if kwargs.get('interactive', False):
             content_type_display = '\n'.join(['    %s | %s' % (ct.app_label, ct.model) for ct in content_types])
             ok_to_delete = raw_input("""The following content types are stale and need to be deleted:
             ok_to_delete = False
 
         if ok_to_delete == 'yes':
-            for ct in content_types:
+            for ct in to_remove:
                 if verbosity >= 2:
                     print "Deleting stale content type '%s | %s'" % (ct.app_label, ct.model)
                 ct.delete()

django/contrib/databrowse/plugins/calendars.py

         if url is None:
             return self.homepage_view(request)
         url_bits = url.split('/')
-        if self.fields.has_key(url_bits[0]):
+        if url_bits[0] in self.fields:
             return self.calendar_view(request, self.fields[url_bits[0]], *url_bits[1:])
 
         raise http.Http404('The requested page does not exist.')

django/contrib/databrowse/plugins/fieldchoices.py

         if url is None:
             return self.homepage_view(request)
         url_bits = url.split('/', 1)
-        if self.fields.has_key(url_bits[0]):
+        if url_bits[0] in self.fields:
             return self.field_view(request, self.fields[url_bits[0]], *url_bits[1:])
 
         raise http.Http404('The requested page does not exist.')

django/contrib/gis/tests/layermap/tests.py

 
             # Comparing the geometries.
             pnt1, pnt2 = feat.geom, city.point
-            self.assertAlmostEqual(pnt1.x, pnt2.x, 6)
-            self.assertAlmostEqual(pnt1.y, pnt2.y, 6)
+            self.assertAlmostEqual(pnt1.x, pnt2.x, 5)
+            self.assertAlmostEqual(pnt1.y, pnt2.y, 5)
 
     def test03_layermap_strict(self):
         "Testing the `strict` keyword, and import of a LineString shapefile."

django/contrib/humanize/templatetags/humanize.py

             return ungettext(
                 u'a second ago', u'%(count)s seconds ago', delta.seconds
             ) % {'count': delta.seconds}
-        elif delta.seconds / 60 < 60:
-            count = delta.seconds / 60
+        elif delta.seconds // 60 < 60:
+            count = delta.seconds // 60
             return ungettext(
                 u'a minute ago', u'%(count)s minutes ago', count
             ) % {'count': count}
         else:
-            count = delta.seconds / 60 / 60
+            count = delta.seconds // 60 // 60
             return ungettext(
                 u'an hour ago', u'%(count)s hours ago', count
             ) % {'count': count}
             return ungettext(
                 u'a second from now', u'%(count)s seconds from now', delta.seconds
             ) % {'count': delta.seconds}
-        elif delta.seconds / 60 < 60:
-            count = delta.seconds / 60
+        elif delta.seconds // 60 < 60:
+            count = delta.seconds // 60
             return ungettext(
                 u'a minute from now', u'%(count)s minutes from now', count
             ) % {'count': count}
         else:
-            count = delta.seconds / 60 / 60
+            count = delta.seconds // 60 // 60
             return ungettext(
                 u'an hour from now', u'%(count)s hours from now', count
             ) % {'count': count}

django/contrib/localflavor/se/utils.py

     if (s % 10) == 0:
         return 0
 
-    return (((s / 10) + 1) * 10) - s
+    return (((s // 10) + 1) * 10) - s
 
 def validate_id_birthday(gd, fix_coordination_number_day=True):
     """

django/contrib/sessions/backends/base.py

         self.modified = True
 
     def has_key(self, key):
-        return self._session.has_key(key)
+        return key in self._session
 
     def values(self):
         return self._session.values()

django/contrib/sessions/backends/cache.py

             raise CreateError
 
     def exists(self, session_key):
-        if self._cache.has_key(session_key):
-            return True
-        return False
+        return session_key in self._cache
 
     def delete(self, session_key=None):
         if session_key is None:

django/contrib/sessions/backends/file.py

             pass
 
     def exists(self, session_key):
-        if os.path.exists(self._key_to_file(session_key)):
-            return True
-        return False
+        return os.path.exists(self._key_to_file(session_key))
 
     def delete(self, session_key=None):
         if session_key is None:

django/contrib/sessions/tests.py

         self.session['some key'] = 1
         self.session.modified = False
         self.session.accessed = False
-        self.assertTrue(self.session.has_key('some key'))
+        self.assertTrue('some key' in self.session)
         self.assertTrue(self.session.accessed)
         self.assertFalse(self.session.modified)
 

django/core/handlers/wsgi.py

 logger = getLogger('django.request')
 
 
-# See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
+# See http://www.iana.org/assignments/http-status-codes
 STATUS_CODE_TEXT = {
     100: 'CONTINUE',
     101: 'SWITCHING PROTOCOLS',
+    102: 'PROCESSING',
     200: 'OK',
     201: 'CREATED',
     202: 'ACCEPTED',
     204: 'NO CONTENT',
     205: 'RESET CONTENT',
     206: 'PARTIAL CONTENT',
+    207: 'MULTI-STATUS',
+    208: 'ALREADY REPORTED',
+    226: 'IM USED',
     300: 'MULTIPLE CHOICES',
     301: 'MOVED PERMANENTLY',
     302: 'FOUND',
     415: 'UNSUPPORTED MEDIA TYPE',
     416: 'REQUESTED RANGE NOT SATISFIABLE',
     417: 'EXPECTATION FAILED',
+    422: 'UNPROCESSABLE ENTITY',
+    423: 'LOCKED',
+    424: 'FAILED DEPENDENCY',
+    426: 'UPGRADE REQUIRED',
     500: 'INTERNAL SERVER ERROR',
     501: 'NOT IMPLEMENTED',
     502: 'BAD GATEWAY',
     503: 'SERVICE UNAVAILABLE',
     504: 'GATEWAY TIMEOUT',
     505: 'HTTP VERSION NOT SUPPORTED',
+    506: 'VARIANT ALSO NEGOTIATES',
+    507: 'INSUFFICIENT STORAGE',
+    508: 'LOOP DETECTED',
+    510: 'NOT EXTENDED',
 }
 
 class LimitedStream(object):

django/core/mail/message.py

 import os
 import random
 import time
-import sys
-if sys.version_info < (2,5): # email package renamed to lowercase in 2.5
-    from email import Charset, Encoders
-    from email.Generator import Generator
-    from email.MIMEText import MIMEText
-    from email.MIMEMultipart import MIMEMultipart
-    from email.MIMEBase import MIMEBase
-    from email.Header import Header
-    from email.Utils import formatdate, getaddresses, formataddr, parseaddr
-else:
-    from email import charset as Charset, encoders as Encoders
-    from email.generator import Generator
-    from email.mime.text import MIMEText
-    from email.mime.multipart import MIMEMultipart
-    from email.mime.base import MIMEBase
-    from email.header import Header
-    from email.utils import formatdate, getaddresses, formataddr, parseaddr
+from email import charset as Charset, encoders as Encoders
+from email.generator import Generator
+from email.mime.text import MIMEText
+from email.mime.multipart import MIMEMultipart
+from email.mime.base import MIMEBase
+from email.header import Header
+from email.utils import formatdate, getaddresses, formataddr, parseaddr
 
 from django.conf import settings
 from django.core.mail.utils import DNS_NAME

django/core/management/__init__.py

         and formatted as potential completion suggestions.
         """
         # Don't complete if user hasn't sourced bash_completion file.
-        if not os.environ.has_key('DJANGO_AUTO_COMPLETE'):
+        if 'DJANGO_AUTO_COMPLETE' not in os.environ:
             return
 
         cwords = os.environ['COMP_WORDS'].split()[1:]

django/core/management/commands/loaddata.py

File contents unchanged.

django/db/backends/__init__.py

 
     can_use_chunked_reads = True
     can_return_id_from_insert = False
+    has_bulk_insert = False
     uses_autocommit = False
     uses_savepoints = False
+    can_combine_inserts_with_and_without_auto_increment_pk = False
 
     # If True, don't use integer foreign keys referring to, e.g., positive
     # integer primary keys.

django/db/backends/mysql/base.py

     allows_group_by_pk = True
     related_fields_match_type = True
     allow_sliced_subqueries = False
+    has_bulk_insert = True
     has_select_for_update = True
     has_select_for_update_nowait = False
     supports_forward_references = False
     def max_name_length(self):
         return 64
 
+    def bulk_insert_sql(self, fields, num_values):
+        items_sql = "(%s)" % ", ".join(["%s"] * len(fields))
+        return "VALUES " + ", ".join([items_sql] * num_values)
+
 class DatabaseWrapper(BaseDatabaseWrapper):
     vendor = 'mysql'
     operators = {

django/db/backends/postgresql_psycopg2/base.py

     can_defer_constraint_checks = True
     has_select_for_update = True
     has_select_for_update_nowait = True
+    has_bulk_insert = True
 
 
 class DatabaseWrapper(BaseDatabaseWrapper):

django/db/backends/postgresql_psycopg2/operations.py

 
     def return_insert_id(self):
         return "RETURNING %s", ()
+
+    def bulk_insert_sql(self, fields, num_values):
+        items_sql = "(%s)" % ", ".join(["%s"] * len(fields))
+        return "VALUES " + ", ".join([items_sql] * num_values)

django/db/backends/sqlite3/base.py

     supports_unspecified_pk = True
     supports_1000_query_parameters = False
     supports_mixed_date_datetime_comparisons = False
+    has_bulk_insert = True
+    can_combine_inserts_with_and_without_auto_increment_pk = True
 
     def _supports_stddev(self):
         """Confirm support for STDDEV and related stats functions
         return ""
 
     def pk_default_value(self):
-        return 'NULL'
+        return "NULL"
 
     def quote_name(self, name):
         if name.startswith('"') and name.endswith('"'):
         # No field, or the field isn't known to be a decimal or integer
         return value
 
+    def bulk_insert_sql(self, fields, num_values):
+        res = []
+        res.append("SELECT %s" % ", ".join(
+            "%%s AS %s" % self.quote_name(f.column) for f in fields
+        ))
+        res.extend(["UNION SELECT %s" % ", ".join(["%s"] * len(fields))] * (num_values - 1))
+        return " ".join(res)
+
 class DatabaseWrapper(BaseDatabaseWrapper):
     vendor = 'sqlite'
     # SQLite requires LIKE statements to include an ESCAPE clause if the value

django/db/models/base.py

                     order_value = manager.using(using).filter(**{field.name: getattr(self, field.attname)}).count()
                     self._order = order_value
 
+                fields = meta.local_fields
                 if not pk_set:
                     if force_update:
                         raise ValueError("Cannot force an update in save() with no primary key.")
-                    values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True), connection=connection))
-                        for f in meta.local_fields if not isinstance(f, AutoField)]
-                else:
-                    values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True), connection=connection))
-                        for f in meta.local_fields]
+                    fields = [f for f in fields if not isinstance(f, AutoField)]
 
                 record_exists = False
 
                 update_pk = bool(meta.has_auto_field and not pk_set)
-                if values:
-                    # Create a new record.
-                    result = manager._insert(values, return_id=update_pk, using=using)
-                else:
-                    # Create a new record with defaults for everything.
-                    result = manager._insert([(meta.pk, connection.ops.pk_default_value())], return_id=update_pk, raw_values=True, using=using)
+                result = manager._insert([self], fields=fields, return_id=update_pk, using=using, raw=raw)
 
                 if update_pk:
                     setattr(self, meta.pk.attname, result)

django/db/models/fields/related.py

             add.alters_data = True
 
             def create(self, **kwargs):
-                kwargs.update({rel_field.name: instance})
+                kwargs[rel_field.name] = instance
                 db = router.db_for_write(rel_model, instance=instance)
                 return super(RelatedManager, self.db_manager(db)).create(**kwargs)
             create.alters_data = True
             def get_or_create(self, **kwargs):
                 # Update kwargs with the related object that this
                 # ForeignRelatedObjectsDescriptor knows about.
-                kwargs.update({rel_field.name: instance})
+                kwargs[rel_field.name] = instance
                 db = router.db_for_write(rel_model, instance=instance)
                 return super(RelatedManager, self.db_manager(db)).get_or_create(**kwargs)
             get_or_create.alters_data = True
                         instance=self.instance, reverse=self.reverse,
                         model=self.model, pk_set=new_ids, using=db)
                 # Add the ones that aren't there already
-                for obj_id in new_ids:
-                    self.through._default_manager.using(db).create(**{
+                self.through._default_manager.using(db).bulk_create([
+                    self.through(**{
                         '%s_id' % source_field_name: self._pk_val,
                         '%s_id' % target_field_name: obj_id,
                     })
+                    for obj_id in new_ids
+                ])
                 if self.reverse or source_field_name == self.source_field_name:
                     # Don't send the signal when we are inserting the
                     # duplicate data row for symmetrical reverse entries.
     def __init__(self, m2m_field):
         self.field = m2m_field
 
-    def _through(self):
+    @property
+    def through(self):
         # through is provided so that you have easy access to the through
         # model (Book.authors.through) for inlines, etc. This is done as
         # a property to ensure that the fully resolved value is returned.
         return self.field.rel.through
-    through = property(_through)
 
     def __get__(self, instance, instance_type=None):
         if instance is None:

django/db/models/manager.py

     def create(self, **kwargs):
         return self.get_query_set().create(**kwargs)
 
+    def bulk_create(self, *args, **kwargs):
+        return self.get_query_set().bulk_create(*args, **kwargs)
+
     def filter(self, *args, **kwargs):
         return self.get_query_set().filter(*args, **kwargs)
 
     def exists(self, *args, **kwargs):
         return self.get_query_set().exists(*args, **kwargs)
 
-    def _insert(self, values, **kwargs):
-        return insert_query(self.model, values, **kwargs)
+    def _insert(self, objs, fields, **kwargs):
+        return insert_query(self.model, objs, fields, **kwargs)
 
     def _update(self, values, **kwargs):
         return self.get_query_set()._update(values, **kwargs)

django/db/models/query.py

 import copy
 
 from django.db import connections, router, transaction, IntegrityError
+from django.db.models.fields import AutoField
 from django.db.models.query_utils import (Q, select_related_descend,
     deferred_class_factory, InvalidQuery)
 from django.db.models.deletion import Collector
 from django.db.models import signals, sql
+from django.utils.functional import partition
 
 # Used to control how many objects are worked with at once in some cases (e.g.
 # when deleting objects).
         obj.save(force_insert=True, using=self.db)
         return obj
 
+    def bulk_create(self, objs):
+        """
+        Inserts each of the instances into the database. This does *not* call
+        save() on each of the instances, does not send any pre/post save
+        signals, and does not set the primary key attribute if it is an
+        autoincrement field.
+        """
+        # So this case is fun. When you bulk insert you don't get the primary
+        # keys back (if it's an autoincrement), so you can't insert into the
+        # child tables which references this. There are two workarounds, 1)
+        # this could be implemented if you didn't have an autoincrement pk,
+        # and 2) you could do it by doing O(n) normal inserts into the parent
+        # tables to get the primary keys back, and then doing a single bulk
+        # insert into the childmost table. We're punting on these for now
+        # because they are relatively rare cases.
+        if self.model._meta.parents:
+            raise ValueError("Can't bulk create an inherited model")
+        if not objs:
+            return
+        self._for_write = True
+        connection = connections[self.db]
+        fields = self.model._meta.local_fields
+        if (connection.features.can_combine_inserts_with_and_without_auto_increment_pk
+            and self.model._meta.has_auto_field):
+            self.model._base_manager._insert(objs, fields=fields, using=self.db)
+        else:
+            objs_with_pk, objs_without_pk = partition(
+                lambda o: o.pk is None,
+                objs
+            )
+            if objs_with_pk:
+                self.model._base_manager._insert(objs_with_pk, fields=fields, using=self.db)
+            if objs_without_pk:
+                self.model._base_manager._insert(objs_without_pk, fields=[f for f in fields if not isinstance(f, AutoField)], using=self.db)
+
     def get_or_create(self, **kwargs):
         """
         Looks up an object with the given kwargs, creating one if necessary.
                 self._model_fields[converter(column)] = field
         return self._model_fields
 
-def insert_query(model, values, return_id=False, raw_values=False, using=None):
+def insert_query(model, objs, fields, return_id=False, raw=False, using=None):
     """
     Inserts a new record for the given model. This provides an interface to
     the InsertQuery class and is how Model.save() is implemented. It is not
     part of the public API.
     """
     query = sql.InsertQuery(model)
-    query.insert_values(values, raw_values)
+    query.insert_values(fields, objs, raw=raw)
     return query.get_compiler(using=using).execute_sql(return_id)

django/db/models/sql/compiler.py

+from itertools import izip
+
 from django.core.exceptions import FieldError
 from django.db import connections
 from django.db import transaction
      select_related_descend, Query)
 from django.db.utils import DatabaseError
 
+
 class SQLCompiler(object):
     def __init__(self, query, connection, using):
         self.query = query
         qn = self.connection.ops.quote_name
         opts = self.query.model._meta
         result = ['INSERT INTO %s' % qn(opts.db_table)]
-        result.append('(%s)' % ', '.join([qn(c) for c in self.query.columns]))
-        values = [self.placeholder(*v) for v in self.query.values]
-        result.append('VALUES (%s)' % ', '.join(values))
-        params = self.query.params
+
+        has_fields = bool(self.query.fields)
+        fields = self.query.fields if has_fields else [opts.pk]
+        result.append('(%s)' % ', '.join([qn(f.column) for f in fields]))
+
+        if has_fields:
+            params = values = [
+                [
+                    f.get_db_prep_save(getattr(obj, f.attname) if self.query.raw else f.pre_save(obj, True), connection=self.connection)
+                    for f in fields
+                ]
+                for obj in self.query.objs
+            ]
+        else:
+            values = [[self.connection.ops.pk_default_value()] for obj in self.query.objs]
+            params = [[]]
+            fields = [None]
+        can_bulk = not any(hasattr(field, "get_placeholder") for field in fields) and not self.return_id
+
+        if can_bulk:
+            placeholders = [["%s"] * len(fields)]
+        else:
+            placeholders = [
+                [self.placeholder(field, v) for field, v in izip(fields, val)]
+                for val in values
+            ]
         if self.return_id and self.connection.features.can_return_id_from_insert:
+            params = values[0]
             col = "%s.%s" % (qn(opts.db_table), qn(opts.pk.column))
+            result.append("VALUES (%s)" % ", ".join(placeholders[0]))
             r_fmt, r_params = self.connection.ops.return_insert_id()
             result.append(r_fmt % col)
-            params = params + r_params
-        return ' '.join(result), params
+            params += r_params
+            return [(" ".join(result), tuple(params))]
+        if can_bulk and self.connection.features.has_bulk_insert:
+            result.append(self.connection.ops.bulk_insert_sql(fields, len(values)))
+            return [(" ".join(result), tuple([v for val in values for v in val]))]
+        else:
+            return [
+                (" ".join(result + ["VALUES (%s)" % ", ".join(p)]), vals)
+                for p, vals in izip(placeholders, params)
+            ]
 
     def execute_sql(self, return_id=False):
+        assert not (return_id and len(self.query.objs) != 1)
         self.return_id = return_id
-        cursor = super(SQLInsertCompiler, self).execute_sql(None)
+        cursor = self.connection.cursor()
+        for sql, params in self.as_sql():
+            cursor.execute(sql, params)
         if not (return_id and cursor):
             return
         if self.connection.features.can_return_id_from_insert:

django/db/models/sql/query.py

 """
 
 import copy
-from django.utils.tree import Node
+
 from django.utils.datastructures import SortedDict
 from django.utils.encoding import force_unicode
+from django.utils.tree import Node
 from django.db import connections, DEFAULT_DB_ALIAS
 from django.db.models import signals
 from django.db.models.fields import FieldDoesNotExist

django/db/models/sql/subqueries.py

 
     def __init__(self, *args, **kwargs):
         super(InsertQuery, self).__init__(*args, **kwargs)
-        self.columns = []
-        self.values = []
-        self.params = ()
+        self.fields = []
+        self.objs = []
 
     def clone(self, klass=None, **kwargs):
         extras = {
-            'columns': self.columns[:],
-            'values': self.values[:],
-            'params': self.params
+            'fields': self.fields[:],
+            'objs': self.objs[:],
+            'raw': self.raw,
         }
         extras.update(kwargs)
         return super(InsertQuery, self).clone(klass, **extras)
 
-    def insert_values(self, insert_values, raw_values=False):
+    def insert_values(self, fields, objs, raw=False):
         """
         Set up the insert query from the 'insert_values' dictionary. The
         dictionary gives the model field names and their target values.
         parameters. This provides a way to insert NULL and DEFAULT keywords
         into the query, for example.
         """
-        placeholders, values = [], []
-        for field, val in insert_values:
-            placeholders.append((field, val))
-            self.columns.append(field.column)
-            values.append(val)
-        if raw_values:
-            self.values.extend([(None, v) for v in values])
-        else:
-            self.params += tuple(values)
-            self.values.extend(placeholders)
+        self.fields = fields
+        self.objs = objs
+        self.raw = raw
 
 class DateQuery(Query):
     """

django/http/__init__.py

 import Cookie
 # httponly support exists in Python 2.6's Cookie library,
 # but not in Python 2.5.
-_morsel_supports_httponly = Cookie.Morsel._reserved.has_key('httponly')
+_morsel_supports_httponly = 'httponly' in Cookie.Morsel._reserved
 # Some versions of Python 2.7 and later won't need this encoding bug fix:
 _cookie_encodes_correctly = Cookie.SimpleCookie().value_encode(';') == (';', '"\\073"')
 # See ticket #13007, http://bugs.python.org/issue2193 and http://trac.edgewall.org/ticket/2256
 
     def has_header(self, header):
         """Case-insensitive check for a header."""
-        return self._headers.has_key(header.lower())
+        return header.lower() in self._headers
 
     __contains__ = has_header
 

django/utils/baseconv.py

             while x > 0:
                 digit = x % len(to_digits)
                 res = to_digits[digit] + res
-                x = int(x / len(to_digits))
+                x = int(x // len(to_digits))
         return neg, res
 
 base2 = BaseConverter(BASE2_ALPHABET)

django/utils/feedgenerator.py

     time_str = date.strftime('%s, %%d %s %%Y %%H:%%M:%%S ' % (dow, month))
     if date.tzinfo:
         offset = date.tzinfo.utcoffset(date)
-        timezone = (offset.days * 24 * 60) + (offset.seconds / 60)
+        timezone = (offset.days * 24 * 60) + (offset.seconds // 60)
         hour, minute = divmod(timezone, 60)
         return time_str + "%+03d%02d" % (hour, minute)
     else:
     if date.tzinfo:
         time_str = date.strftime('%Y-%m-%dT%H:%M:%S')
         offset = date.tzinfo.utcoffset(date)
-        timezone = (offset.days * 24 * 60) + (offset.seconds / 60)
+        timezone = (offset.days * 24 * 60) + (offset.seconds // 60)
         hour, minute = divmod(timezone, 60)
         return time_str + "%+03d:%02d" % (hour, minute)
     else:
 
 class Atom1Feed(SyndicationFeed):
     # Spec: http://atompub.org/2005/07/11/draft-ietf-atompub-format-10.html
-    mime_type = 'application/atom+xml; charset=utf8'
+    mime_type = 'application/atom+xml; charset=utf-8'
     ns = u"http://www.w3.org/2005/Atom"
 
     def write(self, outfile, encoding):

django/utils/functional.py

             def fdel(instance, name=fdel.__name__):
                 return getattr(instance, name)()
         return property(fget, fset, fdel, doc)
+
+def partition(predicate, values):
+    """
+    Splits the values into two sets, based on the return value of the function
+    (True/False). e.g.:
+
+        >>> partition(lambda: x > 3, range(5))
+        [1, 2, 3], [4]
+    """
+    results = ([], [])
+    for item in values:
+        results[predicate(item)].append(item)
+    return results

django/utils/http.py

 import sys
 import urllib
 import urlparse
-try:
-    from email.Utils import formatdate
-except ImportError:
-    from email.utils import formatdate
+from email.utils import formatdate
 
 from django.utils.datastructures import MultiValueDict
 from django.utils.encoding import smart_str, force_unicode
     # Construct base36 representation
     while factor >= 0:
         j = 36 ** factor
-        base36.append(digits[i / j])
+        base36.append(digits[i // j])
         i = i % j
         factor -= 1
     return ''.join(base36)

django/views/debug.py

                 else:
                     # Cleanse only the specified parameters.
                     for param in sensitive_post_parameters:
-                        if cleansed.has_key(param):
+                        if param in cleansed:
                             cleansed[param] = CLEANSED_SUBSTITUTE
                     return cleansed
             else:

docs/ref/contrib/gis/db-api.txt

 * :mod:`django.contrib.gis.db.backends.oracle`
 * :mod:`django.contrib.gis.db.backends.spatialite`
 
-Database Settings Backwards-Compatibility
------------------------------------------
-
-In :doc:`Django 1.2 </releases/1.2>`, the way
-to :ref:`specify databases <specifying-databases>` in your settings was changed.
-The old database settings format (e.g., the ``DATABASE_*`` settings)
-is backwards compatible with GeoDjango, and  will automatically use the
-appropriate spatial backend as long as :mod:`django.contrib.gis` is in
-your :setting:`INSTALLED_APPS`.  For example, if you have the following in
-your settings::
-
-    DATABASE_ENGINE='postgresql_psycopg2'
-
-    ...
-
-    INSTALLED_APPS = (
-      ...
-      'django.contrib.gis',
-      ...
-    )
-
-Then, :mod:`django.contrib.gis.db.backends.postgis` is automatically used as your
-spatial backend.
-
 .. _mysql-spatial-limitations:
 
 MySQL Spatial Limitations

docs/ref/contrib/gis/install.txt

 .. note::
 
     The parameter ``geodjango.db`` is the *filename* of the SQLite database
-    you want to use.  Use the same in the :setting:`DATABASE_NAME`
+    you want to use.  Use the same in the :setting:`DATABASES` ``"name"`` key
     inside your ``settings.py``.
 
 

docs/ref/models/querysets.txt

 
 .. _Safe methods: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
 
+bulk_create
+~~~~~~~~~~~
+
+.. method:: bulk_create(objs)
+
+This method inserts the provided list of objects into the database in an
+efficient manner (generally only 1 query, no matter how many objects there
+are)::
+
+    >>> Entry.objects.bulk_create([
+    ...     Entry(headline="Django 1.0 Released"),
+    ...     Entry(headline="Django 1.1 Announced"),
+    ...     Entry(headline="Breaking: Django is awesome")
+    ... ])
+
+This has a number of caveats though:
+
+  * The model's ``save()`` method will not be called, and the ``pre_save`` and
+    ``post_save`` signals will not be sent.
+  * It does not work with child models in a multi-table inheritance scenario.
+  * If the model's primary key is an :class:`~django.db.models.AutoField` it
+    does not retrieve and set the primary key attribute, as ``save()`` does.
+
 count
 ~~~~~
 

docs/ref/settings.txt

    This setting has been replaced by :setting:`BACKEND <CACHES-BACKEND>` in
    :setting:`CACHES`.
 
-.. setting:: DATABASE_ENGINE
-
-DATABASE_ENGINE
----------------
-
-.. deprecated:: 1.2
-   This setting has been replaced by :setting:`ENGINE` in
-   :setting:`DATABASES`.
-
-.. setting:: DATABASE_HOST
-
-DATABASE_HOST
--------------
-
-.. deprecated:: 1.2
-   This setting has been replaced by :setting:`HOST` in
-   :setting:`DATABASES`.
-
-.. setting:: DATABASE_NAME
-
-DATABASE_NAME
--------------
-
-.. deprecated:: 1.2
-   This setting has been replaced by :setting:`NAME` in
-   :setting:`DATABASES`.
-
-.. setting:: DATABASE_OPTIONS
-
-DATABASE_OPTIONS
-----------------
-
-.. deprecated:: 1.2
-   This setting has been replaced by :setting:`OPTIONS` in
-   :setting:`DATABASES`.
-
-.. setting:: DATABASE_PASSWORD
-
-DATABASE_PASSWORD
------------------
-
-.. deprecated:: 1.2
-   This setting has been replaced by :setting:`PASSWORD` in
-   :setting:`DATABASES`.
-
-.. setting:: DATABASE_PORT
-
-DATABASE_PORT
--------------
-
-.. deprecated:: 1.2
-   This setting has been replaced by :setting:`PORT` in
-   :setting:`DATABASES`.
-
-.. setting:: DATABASE_USER
-
-DATABASE_USER
--------------
-
-.. deprecated:: 1.2
-   This setting has been replaced by :setting:`USER` in
-   :setting:`DATABASES`.
-
 .. setting:: IGNORABLE_404_ENDS
 
 IGNORABLE_404_ENDS
 --------------------
 
 .. deprecated:: 1.4
-   This setting has been superseded by :setting:`IGNORABLE_404_URLS`.
-
-.. setting:: TEST_DATABASE_CHARSET
-
-TEST_DATABASE_CHARSET
----------------------
-
-.. deprecated:: 1.2
-   This setting has been replaced by :setting:`TEST_CHARSET` in
-   :setting:`DATABASES`.
-
-.. setting:: TEST_DATABASE_COLLATION
-
-TEST_DATABASE_COLLATION
------------------------
-
-.. deprecated:: 1.2
-   This setting has been replaced by :setting:`TEST_COLLATION` in
-   :setting:`DATABASES`.
-
-.. setting:: TEST_DATABASE_NAME
-
-TEST_DATABASE_NAME
-------------------
-
-.. deprecated:: 1.2
-   This setting has been replaced by :setting:`TEST_NAME` in
-   :setting:`DATABASES`.
+   This setting has been superseded by :setting:`IGNORABLE_404_URLS`.

docs/releases/1.4.txt

 See the :class:`~django.contrib.staticfiles.storage.CachedStaticFilesStorage`
 docs for more information.
 
+``Model.objects.bulk_create`` in the ORM
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This method allows for more efficient creation of multiple objects in the ORM.
+It can provide significant performance increases if you have many objects,
+Django makes use of this internally, meaning some operations (such as database
+setup for test suites) has seen a performance benefit as a result.
+
+See the :meth:`~django.db.models.query.QuerySet.bulk_create` docs for more
+information.
+
 Minor features
 ~~~~~~~~~~~~~~
 

docs/topics/db/optimization.txt

 
    entry.blog.id
 
+Insert in bulk
+==============
+
+When creating objects, where possible, use the
+:meth:`~django.db.models.query.QuerySet.bulk_create()` method to reduce the
+number of SQL queries. For example::
+
+    Entry.objects.bulk_create([
+        Entry(headline="Python 3.0 Released"),
+        Entry(headline="Python 3.1 Planned")
+    ])
+
+Is preferable to::
+
+    Entry.objects.create(headline="Python 3.0 Released")
+    Entry.objects.create(headline="Python 3.1 Planned")
+
+Note that there are a number of :meth:`caveats to this method
+<django.db.models.query.QuerySet.bulk_create>`, make sure it is appropriate for
+your use case. This also applies to :class:`ManyToManyFields
+<django.db.models.ManyToManyField>`, doing::
+
+    my_band.members.add(me, my_friend)
+
+Is preferable to::
+
+    my_band.members.add(me)
+    my_band.members.add(my_friend)
+
+Where ``Bands`` and ``Artists`` have a many-to-many relationship.

docs/topics/http/file-uploads.txt

 data on the fly, render progress bars, and even send data to another storage
 location directly without storing it locally.
 
+.. _modifying_upload_handlers_on_the_fly:
+
 Modifying upload handlers on the fly
 ------------------------------------
 

docs/topics/http/middleware.txt

 view; it'll return that :class:`~django.http.HttpResponse`. Response
 middleware is always called on every response.
 
+.. note::
+    Accessing :attr:`request.POST <django.http.HttpRequest.POST>` or 
+    :attr:`request.REQUEST <django.http.HttpRequest.REQUEST>` inside 
+    middleware from ``process_request`` or ``process_view`` will prevent any
+    view running after the middleware from being able to
+    :ref:`modify the upload handlers for the 
+    request <modifying_upload_handlers_on_the_fly>`, and should normally be
+    avoided.
+
+    The :class:`~django.middleware.csrf.CsrfViewMiddleware` class can be
+    considered an exception, as it provides the
+    :func:`~django.views.decorators.csrf.csrf_exempt` and
+    :func:`~django.views.decorators.csrf.csrf_protect` decorators which allow
+    views to explicitly control at what point the CSRF validation should occur.
+
 .. _template-response-middleware:
 
 ``process_template_response``

tests/regressiontests/bulk_create/__init__.py

Empty file added.

tests/regressiontests/bulk_create/models.py

+from django.db import models
+
+
+class Country(models.Model):
+    name = models.CharField(max_length=255)
+    iso_two_letter = models.CharField(max_length=2)
+
+class Place(models.Model):
+    name = models.CharField(max_length=100)
+
+    class Meta:
+        abstract = True
+
+class Restaurant(Place):
+    pass
+
+class Pizzeria(Restaurant):
+    pass
+
+class State(models.Model):
+    two_letter_code = models.CharField(max_length=2, primary_key=True)

tests/regressiontests/bulk_create/tests.py

+from __future__ import with_statement
+
+from operator import attrgetter
+
+from django.test import TestCase, skipUnlessDBFeature
+
+from models import Country, Restaurant, Pizzeria, State
+
+
+class BulkCreateTests(TestCase):
+    def setUp(self):
+        self.data = [
+            Country(name="United States of America", iso_two_letter="US"),
+            Country(name="The Netherlands", iso_two_letter="NL"),
+            Country(name="Germany", iso_two_letter="DE"),
+            Country(name="Czech Republic", iso_two_letter="CZ")
+        ]
+
+    def test_simple(self):
+        Country.objects.bulk_create(self.data)
+        self.assertQuerysetEqual(Country.objects.order_by("-name"), [
+            "United States of America", "The Netherlands", "Germany", "Czech Republic"
+        ], attrgetter("name"))
+
+    @skipUnlessDBFeature("has_bulk_insert")
+    def test_efficiency(self):
+        with self.assertNumQueries(1):
+            Country.objects.bulk_create(self.data)
+
+    def test_inheritance(self):
+        Restaurant.objects.bulk_create([
+            Restaurant(name="Nicholas's")
+        ])
+        self.assertQuerysetEqual(Restaurant.objects.all(), [
+            "Nicholas's",
+        ], attrgetter("name"))
+        with self.assertRaises(ValueError):
+            Pizzeria.objects.bulk_create([
+                Pizzeria(name="The Art of Pizza")
+            ])
+        self.assertQuerysetEqual(Pizzeria.objects.all(), [])
+        self.assertQuerysetEqual(Restaurant.objects.all(), [
+            "Nicholas's",
+        ], attrgetter("name"))
+
+    def test_non_auto_increment_pk(self):
+        with self.assertNumQueries(1):
+            State.objects.bulk_create([
+                State(two_letter_code=s)
+                for s in ["IL", "NY", "CA", "ME"]
+            ])
+        self.assertQuerysetEqual(State.objects.order_by("two_letter_code"), [
+            "CA", "IL", "ME", "NY",
+        ], attrgetter("two_letter_code"))

tests/regressiontests/comment_tests/tests/templatetag_tests.py

+from __future__ import with_statement
+
 from django.contrib.comments.forms import CommentForm
+from django.contrib.comments.models import Comment
 from django.contrib.contenttypes.models import ContentType
 from django.template import Template, Context
 from regressiontests.comment_tests.models import Article, Author
             self.testRenderCommentFormFromObject()
         self.assertNumQueries(1, test)
 
-    def testGetCommentCount(self, tag=None):
-        self.createSomeComments()
+    def verifyGetCommentCount(self, tag=None):
         t = "{% load comments %}" + (tag or "{% get_comment_count for comment_tests.article a.id as cc %}") + "{{ cc }}"
         ctx, out = self.render(t, a=Article.objects.get(pk=1))
         self.assertEqual(out, "2")
 
+    def testGetCommentCount(self):
+        self.createSomeComments()
+        self.verifyGetCommentCount("{% get_comment_count for comment_tests.article a.id as cc %}")
+
     def testGetCommentCountFromLiteral(self):
-        self.testGetCommentCount("{% get_comment_count for comment_tests.article 1 as cc %}")
+        self.createSomeComments()
+        self.verifyGetCommentCount("{% get_comment_count for comment_tests.article 1 as cc %}")
 
     def testGetCommentCountFromObject(self):
-        self.testGetCommentCount("{% get_comment_count for a as cc %}")
+        self.createSomeComments()
+        self.verifyGetCommentCount("{% get_comment_count for a as cc %}")
 
-    def testGetCommentList(self, tag=None):
-        c1, c2, c3, c4 = self.createSomeComments()
-        t = "{% load comments %}" + (tag or "{% get_comment_list for comment_tests.author a.id as cl %}")
+    def verifyGetCommentList(self, tag=None):
+        c1, c2, c3, c4 = Comment.objects.all()[:4]
+        t = "{% load comments %}" +  (tag or "{% get_comment_list for comment_tests.author a.id as cl %}")
         ctx, out = self.render(t, a=Author.objects.get(pk=1))
         self.assertEqual(out, "")
         self.assertEqual(list(ctx["cl"]), [c2])
 
+    def testGetCommentList(self):
+        self.createSomeComments()
+        self.verifyGetCommentList("{% get_comment_list for comment_tests.author a.id as cl %}")
+
     def testGetCommentListFromLiteral(self):
-        self.testGetCommentList("{% get_comment_list for comment_tests.author 1 as cl %}")
+        self.createSomeComments()
+        self.verifyGetCommentList("{% get_comment_list for comment_tests.author 1 as cl %}")
 
     def testGetCommentListFromObject(self):
-        self.testGetCommentList("{% get_comment_list for a as cl %}")
+        self.createSomeComments()
+        self.verifyGetCommentList("{% get_comment_list for a as cl %}")
 
     def testGetCommentPermalink(self):
         c1, c2, c3, c4 = self.createSomeComments()
     def testRenderCommentListFromObject(self):
         self.testRenderCommentList("{% render_comment_list for a %}")
 
+    def testNumberQueries(self):
+        """
+        Ensure that the template tags use cached content types to reduce the
+        number of DB queries.
+        Refs #16042.
+        """
+
+        self.createSomeComments()
+
+        # {% render_comment_list %} -----------------
+
+        # Clear CT cache
+        ContentType.objects.clear_cache()
+        with self.assertNumQueries(4):
+            self.testRenderCommentListFromObject()
+
+        # Force the CT to be cached
+        ct = ContentType.objects.get_for_model(Article)
+        with self.assertNumQueries(3):
+            self.testRenderCommentListFromObject()
+
+        # {% get_comment_list %} --------------------
+
+        ContentType.objects.clear_cache()
+        with self.assertNumQueries(4):
+            self.verifyGetCommentList()
+
+        ct = ContentType.objects.get_for_model(Author)
+        with self.assertNumQueries(3):
+            self.verifyGetCommentList()
+
+        # {% render_comment_form %} -----------------
+
+        ContentType.objects.clear_cache()
+        with self.assertNumQueries(3):
+            self.testRenderCommentForm()
+
+        ct = ContentType.objects.get_for_model(Article)
+        with self.assertNumQueries(2):
+            self.testRenderCommentForm()
+
+        # {% get_comment_form %} --------------------
+
+        ContentType.objects.clear_cache()
+        with self.assertNumQueries(3):
+            self.testGetCommentForm()
+
+        ct = ContentType.objects.get_for_model(Article)
+        with self.assertNumQueries(2):
+            self.testGetCommentForm()
+
+        # {% get_comment_count %} -------------------
+
+        ContentType.objects.clear_cache()
+        with self.assertNumQueries(3):
+            self.verifyGetCommentCount()
+
+        ct = ContentType.objects.get_for_model(Article)
+        with self.assertNumQueries(2):
+            self.verifyGetCommentCount()

tests/regressiontests/db_typecasts/tests.py

 
 class DBTypeCasts(unittest.TestCase):
     def test_typeCasts(self):
-        for k, v in TEST_CASES.items():
+        for k, v in TEST_CASES.iteritems():
             for inpt, expected in v:
                 got = getattr(typecasts, k)(inpt)
-                assert got == expected, "In %s: %r doesn't match %r. Got %r instead." % (k, inpt, expected, got)
+                self.assertEqual(got, expected, "In %s: %r doesn't match %r. Got %r instead." % (k, inpt, expected, got))
 
 if __name__ == '__main__':
     unittest.main()

tests/regressiontests/humanize/tests.py

 
         self.humanize_tester(test_list, result_list, 'intcomma')
 
+    def test_l10n_intcomma(self):
+        test_list = (100, 1000, 10123, 10311, 1000000, 1234567.25,
+                     '100', '1000', '10123', '10311', '1000000', '1234567.1234567',
+                     None)
+        result_list = ('100', '1,000', '10,123', '10,311', '1,000,000', '1,234,567.25',
+                       '100', '1,000', '10,123', '10,311', '1,000,000', '1,234,567.1234567',
+                     None)
+
+        with self.settings(USE_L10N=True, USE_THOUSAND_SEPARATOR=False):
+            self.humanize_tester(test_list, result_list, 'intcomma')
+
     def test_intword(self):
         test_list = ('100', '1000000', '1200000', '1290000',
                      '1000000000', '2000000000', '6000000000000',

tests/regressiontests/signing/tests.py

         for s in (
             'hello',
             '3098247:529:087:',
-            u'\u2019'.encode('utf8'),
+            u'\u2019'.encode('utf-8'),
         ):
             self.assertEqual(
                 signer.signature(s),

tests/regressiontests/templates/tests.py

 class ContextStackException(Exception):
     pass
 
+class ShouldNotExecuteException(Exception):
+    pass
+
 class SomeClass:
     def __init__(self):
         self.otherclass = OtherClass()
         return False
 
     def is_bad(self):
-        time.sleep(0.3)
-        return True
+        raise ShouldNotExecuteException()
 
 class SilentGetItemClass(object):
     def __getitem__(self, key):
                 settings.TEMPLATE_DEBUG = template_debug
                 for is_cached in (False, True):
                     try:
-                        start = datetime.now()
-                        test_template = loader.get_template(name)
-                        end = datetime.now()
-                        if end-start > timedelta(seconds=0.2):
-                            failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Took too long to parse test" % (is_cached, invalid_str, template_debug, name))
+                        try:
+                            test_template = loader.get_template(name)
+                        except ShouldNotExecuteException:
+                            failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Template loading invoked method that shouldn't have been invoked." % (is_cached, invalid_str, template_debug, name))
 
-                        start = datetime.now()
-                        output = self.render(test_template, vals)
-                        end = datetime.now()
-                        if end-start > timedelta(seconds=0.2):
-                            failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Took too long to render test" % (is_cached, invalid_str, template_debug, name))
+                        try:
+                            output = self.render(test_template, vals)
+                        except ShouldNotExecuteException:
+                            failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Template rendering invoked method that shouldn't have been invoked." % (is_cached, invalid_str, template_debug, name))
                     except ContextStackException:
                         failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Context stack was left imbalanced" % (is_cached, invalid_str, template_debug, name))
                         continue
                     except Exception:
                         exc_type, exc_value, exc_tb = sys.exc_info()
                         if exc_type != result:
-                            print "CHECK", name, exc_type, result
                             tb = '\n'.join(traceback.format_exception(exc_type, exc_value, exc_tb))
                             failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Got %s, exception: %s\n%s" % (is_cached, invalid_str, template_debug, name, exc_type, exc_value, tb))
                         continue
             'if-tag-error12': ("{% if a not b %}yes{% endif %}", {}, template.TemplateSyntaxError),
 
             # If evaluations are shortcircuited where possible
-            # These tests will fail by taking too long to run. When the if clause
-            # is shortcircuiting correctly, the is_bad() function shouldn't be
-            # evaluated, and the deliberate sleep won't happen.
+            # If is_bad is invoked, it will raise a ShouldNotExecuteException
             'if-tag-shortcircuit01': ('{% if x.is_true or x.is_bad %}yes{% else %}no{% endif %}', {'x': TestObj()}, "yes"),
             'if-tag-shortcircuit02': ('{% if x.is_false and x.is_bad %}yes{% else %}no{% endif %}', {'x': TestObj()}, "no"),
 

tests/regressiontests/utils/feedgenerator.py

         """
         atom_feed = feedgenerator.Atom1Feed("title", "link", "description")
         self.assertEqual(
-            atom_feed.mime_type, "application/atom+xml; charset=utf8"
+            atom_feed.mime_type, "application/atom+xml; charset=utf-8"
         )