Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #12991 -- Added unittest2 support. Thanks to PaulM for the draf…

…t patch, and to Luke, Karen, Justin, Alex, Łukasz Rekucki, and Chuck Harmston for their help testing and reviewing the final patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14139 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 121d2e36785dc0ce8e7d1c48883fc7b719b21afc 1 parent 1070c57
Russell Keith-Magee authored October 11, 2010

Showing 106 changed files with 3,875 additions and 1,054 deletions. Show diff stats Hide diff stats

  1. 5  django/contrib/admindocs/tests/__init__.py
  2. 6  django/contrib/formtools/tests.py
  3. 4  django/contrib/gis/db/backends/spatialite/creation.py
  4. 2  django/contrib/gis/gdal/tests/__init__.py
  5. 83  django/contrib/gis/gdal/tests/test_envelope.py
  6. 3  django/contrib/gis/gdal/tests/test_geom.py
  7. 7  django/contrib/gis/gdal/tests/test_srs.py
  8. 2  django/contrib/gis/geos/tests/__init__.py
  9. 2  django/contrib/gis/geos/tests/test_geos_mutation.py
  10. 3  django/contrib/gis/geos/tests/test_mutable_list.py
  11. 3  django/contrib/gis/tests/__init__.py
  12. 4  django/contrib/gis/tests/geoapp/test_feeds.py
  13. 14  django/contrib/gis/tests/geoapp/test_sitemaps.py
  14. 34  django/contrib/gis/tests/layermap/tests.py
  15. 4  django/contrib/gis/tests/test_geoforms.py
  16. 53  django/contrib/gis/tests/test_measure.py
  17. 8  django/contrib/gis/tests/test_spatialrefsys.py
  18. 109  django/contrib/markup/tests.py
  19. 2  django/contrib/messages/tests/middleware.py
  20. 7  django/contrib/sessions/tests.py
  21. 90  django/db/backends/__init__.py
  22. 17  django/db/backends/creation.py
  23. 2  django/db/backends/dummy/base.py
  24. 12  django/db/backends/mysql/base.py
  25. 8  django/db/backends/oracle/base.py
  26. 5  django/db/backends/postgresql/base.py
  27. 5  django/db/backends/postgresql_psycopg2/base.py
  28. 25  django/db/backends/sqlite3/base.py
  29. 2  django/test/__init__.py
  30. 59  django/test/simple.py
  31. 32  django/test/testcases.py
  32. 80  django/utils/unittest/__init__.py
  33. 10  django/utils/unittest/__main__.py
  34. 1,083  django/utils/unittest/case.py
  35. 9  django/utils/unittest/collector.py
  36. 64  django/utils/unittest/compatibility.py
  37. 322  django/utils/unittest/loader.py
  38. 241  django/utils/unittest/main.py
  39. 183  django/utils/unittest/result.py
  40. 206  django/utils/unittest/runner.py
  41. 57  django/utils/unittest/signals.py
  42. 287  django/utils/unittest/suite.py
  43. 99  django/utils/unittest/util.py
  44. 28  docs/releases/1.3.txt
  45. 70  docs/topics/testing.txt
  46. 9  tests/modeltests/basic/models.py
  47. 21  tests/modeltests/custom_pk/tests.py
  48. 89  tests/modeltests/fixtures/tests.py
  49. 17  tests/modeltests/lookup/models.py
  50. 2  tests/modeltests/test_client/tests.py
  51. 300  tests/modeltests/transactions/tests.py
  52. 2  tests/modeltests/validation/__init__.py
  53. 4  tests/modeltests/validation/test_unique.py
  54. 3  tests/modeltests/validation/validators.py
  55. 4  tests/modeltests/validators/tests.py
  56. 2  tests/regressiontests/admin_scripts/tests.py
  57. 11  tests/regressiontests/admin_util/tests.py
  58. 66  tests/regressiontests/admin_views/tests.py
  59. 5  tests/regressiontests/admin_widgets/tests.py
  60. 185  tests/regressiontests/aggregation_regress/tests.py
  61. 2  tests/regressiontests/app_loading/tests.py
  62. 2  tests/regressiontests/backends/models.py
  63. 166  tests/regressiontests/backends/tests.py
  64. 2  tests/regressiontests/bash_completion/tests.py
  65. 3  tests/regressiontests/bug639/tests.py
  66. 3  tests/regressiontests/bug8245/tests.py
  67. 3  tests/regressiontests/builtin_server/tests.py
  68. 3  tests/regressiontests/cache/tests.py
  69. 17  tests/regressiontests/datatypes/tests.py
  70. 19  tests/regressiontests/decorators/tests.py
  71. 107  tests/regressiontests/delete_regress/tests.py
  72. 17  tests/regressiontests/dispatch/tests/test_dispatcher.py
  73. 2  tests/regressiontests/dispatch/tests/test_saferef.py
  74. 28  tests/regressiontests/expressions_regress/tests.py
  75. 135  tests/regressiontests/file_storage/tests.py
  76. 8  tests/regressiontests/file_uploads/tests.py
  77. 4  tests/regressiontests/fixtures_regress/models.py
  78. 3  tests/regressiontests/forms/fields.py
  79. 2  tests/regressiontests/forms/input_formats.py
  80. 3  tests/regressiontests/forms/validators.py
  81. 5  tests/regressiontests/forms/widgets.py
  82. 49  tests/regressiontests/httpwrappers/tests.py
  83. 3  tests/regressiontests/humanize/tests.py
  84. 16  tests/regressiontests/introspection/tests.py
  85. 2  tests/regressiontests/localflavor/tests.py
  86. 10  tests/regressiontests/max_lengths/tests.py
  87. 22  tests/regressiontests/model_fields/tests.py
  88. 6  tests/regressiontests/model_regress/models.py
  89. 3  tests/regressiontests/pagination_regress/tests.py
  90. 8  tests/regressiontests/queries/models.py
  91. 3  tests/regressiontests/queries/tests.py
  92. 6  tests/regressiontests/serializers_regress/tests.py
  93. 2  tests/regressiontests/settings_tests/tests.py
  94. 6  tests/regressiontests/templates/loaders.py
  95. 2  tests/regressiontests/templates/nodelist.py
  96. 2  tests/regressiontests/templates/smartif.py
  97. 60  tests/regressiontests/templates/tests.py
  98. 96  tests/regressiontests/test_client_regress/models.py
  99. 4  tests/regressiontests/test_runner/tests.py
  100. 3  tests/regressiontests/urlpatterns_reverse/tests.py
  101. 4  tests/regressiontests/utils/dateformat.py
  102. 3  tests/regressiontests/utils/feedgenerator.py
  103. 3  tests/regressiontests/utils/functional.py
  104. 3  tests/regressiontests/utils/module_loading.py
  105. 3  tests/regressiontests/utils/termcolors.py
  106. 5  tests/runtests.py
5  django/contrib/admindocs/tests/__init__.py
... ...
@@ -1,7 +1,8 @@
1  
-import unittest
2  
-import fields
3 1
 from django.contrib.admindocs import views
4 2
 from django.db.models import fields as builtin_fields
  3
+from django.utils import unittest
  4
+
  5
+import fields
5 6
 
6 7
 
7 8
 class TestFieldType(unittest.TestCase):
6  django/contrib/formtools/tests.py
... ...
@@ -1,8 +1,8 @@
1  
-import unittest
2 1
 from django import forms
3  
-from django.contrib.formtools import preview, wizard, utils
4 2
 from django import http
  3
+from django.contrib.formtools import preview, wizard, utils
5 4
 from django.test import TestCase
  5
+from django.utils import unittest
6 6
 
7 7
 success_string = "Done was called!"
8 8
 
@@ -115,7 +115,7 @@ def test_textfield_hash(self):
115 115
         hash1 = utils.security_hash(None, f1)
116 116
         hash2 = utils.security_hash(None, f2)
117 117
         self.assertEqual(hash1, hash2)
118  
-        
  118
+
119 119
     def test_empty_permitted(self):
120 120
         """
121 121
         Regression test for #10643: the security hash should allow forms with
4  django/contrib/gis/db/backends/spatialite/creation.py
@@ -22,8 +22,8 @@ def create_test_db(self, verbosity=1, autoclobber=False):
22 22
         self.connection.close()
23 23
 
24 24
         self.connection.settings_dict["NAME"] = test_database_name
25  
-        can_rollback = self._rollback_works()
26  
-        self.connection.settings_dict["SUPPORTS_TRANSACTIONS"] = can_rollback
  25
+        # Confirm the feature set of the test database
  26
+        self.connection.features.confirm()
27 27
         # Need to load the SpatiaLite initialization SQL before running `syncdb`.
28 28
         self.load_spatialite_sql()
29 29
         call_command('syncdb', verbosity=verbosity, interactive=False, database=self.connection.alias)
2  django/contrib/gis/gdal/tests/__init__.py
@@ -2,7 +2,7 @@
2 2
 Module for executing all of the GDAL tests.  None
3 3
 of these tests require the use of the database.
4 4
 """
5  
-from unittest import TestSuite, TextTestRunner
  5
+from django.utils.unittest import TestSuite, TextTestRunner
6 6
 
7 7
 # Importing the GDAL test modules.
8 8
 import test_driver, test_ds, test_envelope, test_geom, test_srs
83  django/contrib/gis/gdal/tests/test_envelope.py
... ...
@@ -1,5 +1,6 @@
1  
-import unittest
2 1
 from django.contrib.gis.gdal import Envelope, OGRException
  2
+from django.utils import unittest
  3
+
3 4
 
4 5
 class TestPoint(object):
5 6
     def __init__(self, x, y):
@@ -8,8 +9,8 @@ def __init__(self, x, y):
8 9
 
9 10
 class EnvelopeTest(unittest.TestCase):
10 11
 
11  
-    def setUp(self): 
12  
-        self.e = Envelope(0, 0, 5, 5) 
  12
+    def setUp(self):
  13
+        self.e = Envelope(0, 0, 5, 5)
13 14
 
14 15
     def test01_init(self):
15 16
         "Testing Envelope initilization."
@@ -23,10 +24,10 @@ def test01_init(self):
23 24
         self.assertRaises(OGRException, Envelope, ())
24 25
         self.assertRaises(ValueError, Envelope, 0, 'a', 5, 5)
25 26
         self.assertRaises(TypeError, Envelope, u'foo')
26  
-        self.assertRaises(OGRException, Envelope, (1, 1, 0, 0)) 
27  
-        try: 
28  
-            Envelope(0, 0, 0, 0) 
29  
-        except OGRException: 
  27
+        self.assertRaises(OGRException, Envelope, (1, 1, 0, 0))
  28
+        try:
  29
+            Envelope(0, 0, 0, 0)
  30
+        except OGRException:
30 31
             self.fail("shouldn't raise an exception for min_x == max_x or min_y == max_y")
31 32
 
32 33
     def test02_properties(self):
@@ -49,41 +50,41 @@ def test03_equivalence(self):
49 50
         self.assertEqual(e1, e2)
50 51
         self.assertEqual((0.523, 0.217, 253.23, 523.69), e1)
51 52
 
52  
-    def test04_expand_to_include_pt_2_params(self): 
53  
-        "Testing Envelope expand_to_include -- point as two parameters." 
54  
-        self.e.expand_to_include(2, 6) 
55  
-        self.assertEqual((0, 0, 5, 6), self.e) 
56  
-        self.e.expand_to_include(-1, -1) 
57  
-        self.assertEqual((-1, -1, 5, 6), self.e) 
58  
-  
59  
-    def test05_expand_to_include_pt_2_tuple(self): 
60  
-        "Testing Envelope expand_to_include -- point as a single 2-tuple parameter." 
61  
-        self.e.expand_to_include((10, 10)) 
62  
-        self.assertEqual((0, 0, 10, 10), self.e) 
63  
-        self.e.expand_to_include((-10, -10)) 
64  
-        self.assertEqual((-10, -10, 10, 10), self.e) 
  53
+    def test04_expand_to_include_pt_2_params(self):
  54
+        "Testing Envelope expand_to_include -- point as two parameters."
  55
+        self.e.expand_to_include(2, 6)
  56
+        self.assertEqual((0, 0, 5, 6), self.e)
  57
+        self.e.expand_to_include(-1, -1)
  58
+        self.assertEqual((-1, -1, 5, 6), self.e)
  59
+
  60
+    def test05_expand_to_include_pt_2_tuple(self):
  61
+        "Testing Envelope expand_to_include -- point as a single 2-tuple parameter."
  62
+        self.e.expand_to_include((10, 10))
  63
+        self.assertEqual((0, 0, 10, 10), self.e)
  64
+        self.e.expand_to_include((-10, -10))
  65
+        self.assertEqual((-10, -10, 10, 10), self.e)
  66
+
  67
+    def test06_expand_to_include_extent_4_params(self):
  68
+        "Testing Envelope expand_to_include -- extent as 4 parameters."
  69
+        self.e.expand_to_include(-1, 1, 3, 7)
  70
+        self.assertEqual((-1, 0, 5, 7), self.e)
  71
+
  72
+    def test06_expand_to_include_extent_4_tuple(self):
  73
+        "Testing Envelope expand_to_include -- extent as a single 4-tuple parameter."
  74
+        self.e.expand_to_include((-1, 1, 3, 7))
  75
+        self.assertEqual((-1, 0, 5, 7), self.e)
  76
+
  77
+    def test07_expand_to_include_envelope(self):
  78
+        "Testing Envelope expand_to_include with Envelope as parameter."
  79
+        self.e.expand_to_include(Envelope(-1, 1, 3, 7))
  80
+        self.assertEqual((-1, 0, 5, 7), self.e)
65 81
 
66  
-    def test06_expand_to_include_extent_4_params(self): 
67  
-        "Testing Envelope expand_to_include -- extent as 4 parameters." 
68  
-        self.e.expand_to_include(-1, 1, 3, 7) 
69  
-        self.assertEqual((-1, 0, 5, 7), self.e) 
70  
-  
71  
-    def test06_expand_to_include_extent_4_tuple(self): 
72  
-        "Testing Envelope expand_to_include -- extent as a single 4-tuple parameter." 
73  
-        self.e.expand_to_include((-1, 1, 3, 7)) 
74  
-        self.assertEqual((-1, 0, 5, 7), self.e) 
75  
-  
76  
-    def test07_expand_to_include_envelope(self): 
77  
-        "Testing Envelope expand_to_include with Envelope as parameter." 
78  
-        self.e.expand_to_include(Envelope(-1, 1, 3, 7)) 
79  
-        self.assertEqual((-1, 0, 5, 7), self.e) 
80  
-  
81  
-    def test08_expand_to_include_point(self): 
82  
-        "Testing Envelope expand_to_include with Point as parameter." 
83  
-        self.e.expand_to_include(TestPoint(-1, 1)) 
84  
-        self.assertEqual((-1, 0, 5, 5), self.e) 
85  
-        self.e.expand_to_include(TestPoint(10, 10)) 
86  
-        self.assertEqual((-1, 0, 10, 10), self.e) 
  82
+    def test08_expand_to_include_point(self):
  83
+        "Testing Envelope expand_to_include with Point as parameter."
  84
+        self.e.expand_to_include(TestPoint(-1, 1))
  85
+        self.assertEqual((-1, 0, 5, 5), self.e)
  86
+        self.e.expand_to_include(TestPoint(10, 10))
  87
+        self.assertEqual((-1, 0, 10, 10), self.e)
87 88
 
88 89
 def suite():
89 90
     s = unittest.TestSuite()
3  django/contrib/gis/gdal/tests/test_geom.py
... ...
@@ -1,8 +1,9 @@
1  
-import unittest
2 1
 from django.contrib.gis.gdal import OGRGeometry, OGRGeomType, \
3 2
     OGRException, OGRIndexError, SpatialReference, CoordTransform, \
4 3
     gdal_version
5 4
 from django.contrib.gis.tests.geometries import *
  5
+from django.utils import unittest
  6
+
6 7
 
7 8
 class OGRGeomTest(unittest.TestCase):
8 9
     "This tests the OGR Geometry."
7  django/contrib/gis/gdal/tests/test_srs.py
... ...
@@ -1,5 +1,6 @@
1  
-import unittest
2 1
 from django.contrib.gis.gdal import SpatialReference, CoordTransform, OGRException, SRSException
  2
+from django.utils import unittest
  3
+
3 4
 
4 5
 class TestSRS:
5 6
     def __init__(self, wkt, **kwargs):
@@ -79,7 +80,7 @@ def test04_proj(self):
79 80
                 srs1 = SpatialReference(s.wkt)
80 81
                 srs2 = SpatialReference(s.proj)
81 82
                 self.assertEqual(srs1.proj, srs2.proj)
82  
-        
  83
+
83 84
     def test05_epsg(self):
84 85
         "Test EPSG import."
85 86
         for s in srlist:
@@ -159,7 +160,7 @@ def test13_attr_value(self):
159 160
         self.assertEqual(4326, int(s1['AUTHORITY', 1]))
160 161
         #for i in range(7): self.assertEqual(0, int(s1['TOWGS84', i]))
161 162
         self.assertEqual(None, s1['FOOBAR'])
162  
-    
  163
+
163 164
 def suite():
164 165
     s = unittest.TestSuite()
165 166
     s.addTest(unittest.makeSuite(SpatialRefTest))
2  django/contrib/gis/geos/tests/__init__.py
... ...
@@ -1,7 +1,7 @@
1 1
 """
2 2
 GEOS Testing module.
3 3
 """
4  
-from unittest import TestSuite, TextTestRunner
  4
+from django.utils.unittest import TestSuite, TextTestRunner
5 5
 import test_geos, test_io, test_geos_mutation, test_mutable_list
6 6
 
7 7
 test_suites = [
2  django/contrib/gis/geos/tests/test_geos_mutation.py
... ...
@@ -1,12 +1,12 @@
1 1
 # Copyright (c) 2008-2009 Aryeh Leib Taurog, all rights reserved.
2 2
 # Modified from original contribution by Aryeh Leib Taurog, which was
3 3
 # released under the New BSD license.
4  
-import unittest
5 4
 
6 5
 import django.utils.copycompat as copy
7 6
 
8 7
 from django.contrib.gis.geos import *
9 8
 from django.contrib.gis.geos.error import GEOSIndexError
  9
+from django.utils import unittest
10 10
 
11 11
 def getItem(o,i): return o[i]
12 12
 def delItem(o,i): del o[i]
3  django/contrib/gis/geos/tests/test_mutable_list.py
@@ -3,8 +3,9 @@
3 3
 #
4 4
 # Modified from original contribution by Aryeh Leib Taurog, which was
5 5
 # released under the New BSD license.
6  
-import unittest
7 6
 from django.contrib.gis.geos.mutable_list import ListMixin
  7
+from django.utils import unittest
  8
+
8 9
 
9 10
 class UserListA(ListMixin):
10 11
     _mytype = tuple
3  django/contrib/gis/tests/__init__.py
... ...
@@ -1,9 +1,10 @@
1 1
 import sys
2  
-import unittest
3 2
 
4 3
 from django.conf import settings
5 4
 from django.db.models import get_app
6 5
 from django.test.simple import build_suite, DjangoTestSuiteRunner
  6
+from django.utils import unittest
  7
+
7 8
 
8 9
 def run_tests(*args, **kwargs):
9 10
     from django.test.simple import run_tests as base_run_tests
4  django/contrib/gis/tests/geoapp/test_feeds.py
... ...
@@ -1,9 +1,11 @@
1  
-import unittest
2 1
 from xml.dom import minidom
3 2
 
4 3
 from django.test import Client
  4
+from django.utils import unittest
  5
+
5 6
 from models import City
6 7
 
  8
+
7 9
 class GeoFeedTest(unittest.TestCase):
8 10
     client = Client()
9 11
 
14  django/contrib/gis/tests/geoapp/test_sitemaps.py
... ...
@@ -1,9 +1,13 @@
1  
-import unittest, zipfile, cStringIO
  1
+import cStringIO
2 2
 from xml.dom import minidom
  3
+import zipfile
3 4
 
4 5
 from django.test import Client
  6
+from django.utils import unittest
  7
+
5 8
 from models import City, Country
6 9
 
  10
+
7 11
 class GeoSitemapTest(unittest.TestCase):
8 12
     client = Client()
9 13
 
@@ -30,7 +34,7 @@ def test_geositemap_kml(self):
30 34
             urlset = doc.firstChild
31 35
             self.assertEqual(urlset.getAttribute(u'xmlns'), u'http://www.sitemaps.org/schemas/sitemap/0.9')
32 36
             self.assertEqual(urlset.getAttribute(u'xmlns:geo'), u'http://www.google.com/geo/schemas/sitemap/1.0')
33  
-        
  37
+
34 38
             urls = urlset.getElementsByTagName('url')
35 39
             self.assertEqual(2, len(urls)) # Should only be 2 sitemaps.
36 40
             for url in urls:
@@ -42,7 +46,7 @@ def test_geositemap_kml(self):
42 46
 
43 47
                 # Getting the relative URL since we don't have a real site.
44 48
                 kml_url = url.getElementsByTagName('loc')[0].childNodes[0].data.split('http://example.com')[1]
45  
-                
  49
+
46 50
                 if kml_type == 'kml':
47 51
                     kml_doc = minidom.parseString(self.client.get(kml_url).content)
48 52
                 elif kml_type == 'kmz':
@@ -52,7 +56,7 @@ def test_geositemap_kml(self):
52 56
                     self.assertEqual(1, len(zf.filelist))
53 57
                     self.assertEqual('doc.kml', zf.filelist[0].filename)
54 58
                     kml_doc = minidom.parseString(zf.read('doc.kml'))
55  
-                
  59
+
56 60
                 # Ensuring the correct number of placemarks are in the KML doc.
57 61
                 if 'city' in kml_url:
58 62
                     model = City
@@ -65,7 +69,7 @@ def test_geositemap_georss(self):
65 69
         from feeds import feed_dict
66 70
 
67 71
         doc = minidom.parseString(self.client.get('/geoapp/sitemaps/georss.xml').content)
68  
-   
  72
+
69 73
         # Ensuring the right sitemaps namespaces are present.
70 74
         urlset = doc.firstChild
71 75
         self.assertEqual(urlset.getAttribute(u'xmlns'), u'http://www.sitemaps.org/schemas/sitemap/0.9')
34  django/contrib/gis/tests/layermap/tests.py
... ...
@@ -1,7 +1,7 @@
1 1
 import os
2  
-import unittest
3 2
 from decimal import Decimal
4 3
 
  4
+from django.utils import unittest
5 5
 from django.utils.copycompat import copy
6 6
 
7 7
 from django.contrib.gis.gdal import DataSource
@@ -15,9 +15,9 @@
15 15
 co_shp = os.path.join(shp_path, 'counties', 'counties.shp')
16 16
 inter_shp = os.path.join(shp_path, 'interstates', 'interstates.shp')
17 17
 
18  
-# Dictionaries to hold what's expected in the county shapefile.  
  18
+# Dictionaries to hold what's expected in the county shapefile.
19 19
 NAMES  = ['Bexar', 'Galveston', 'Harris', 'Honolulu', 'Pueblo']
20  
-NUMS   = [1, 2, 1, 19, 1] # Number of polygons for each.                                                                                                                                                  
  20
+NUMS   = [1, 2, 1, 19, 1] # Number of polygons for each.
21 21
 STATES = ['Texas', 'Texas', 'Texas', 'Hawaii', 'Colorado']
22 22
 
23 23
 class LayerMapTest(unittest.TestCase):
@@ -98,7 +98,7 @@ def test03_layermap_strict(self):
98 98
 
99 99
         # Two interstate should have imported correctly.
100 100
         self.assertEqual(2, Interstate.objects.count())
101  
-        
  101
+
102 102
         # Verifying the values in the layer w/the model.
103 103
         ds = DataSource(inter_shp)
104 104
 
@@ -106,7 +106,7 @@ def test03_layermap_strict(self):
106 106
         valid_feats = ds[0][:2]
107 107
         for feat in valid_feats:
108 108
             istate = Interstate.objects.get(name=feat['Name'].value)
109  
-            
  109
+
110 110
             if feat.fid == 0:
111 111
                 self.assertEqual(Decimal(str(feat['Length'])), istate.length)
112 112
             elif feat.fid == 1:
@@ -125,7 +125,7 @@ def county_helper(self, county_feat=True):
125 125
             c = County.objects.get(name=name)
126 126
             self.assertEqual(n, len(c.mpoly))
127 127
             self.assertEqual(st, c.state.name) # Checking ForeignKey mapping.
128  
-            
  128
+
129 129
             # Multiple records because `unique` was not set.
130 130
             if county_feat:
131 131
                 qs = CountyFeat.objects.filter(name=name)
@@ -137,7 +137,7 @@ def test04_layermap_unique_multigeometry_fk(self):
137 137
         try:
138 138
             # Telling LayerMapping that we want no transformations performed on the data.
139 139
             lm = LayerMapping(County, co_shp, co_mapping, transform=False)
140  
-        
  140
+
141 141
             # Specifying the source spatial reference system via the `source_srs` keyword.
142 142
             lm = LayerMapping(County, co_shp, co_mapping, source_srs=4269)
143 143
             lm = LayerMapping(County, co_shp, co_mapping, source_srs='NAD83')
@@ -147,7 +147,7 @@ def test04_layermap_unique_multigeometry_fk(self):
147 147
                 lm = LayerMapping(County, co_shp, co_mapping, transform=False, unique=arg)
148 148
         except:
149 149
             self.fail('No exception should be raised for proper use of keywords.')
150  
-            
  150
+
151 151
         # Testing invalid params for the `unique` keyword.
152 152
         for e, arg in ((TypeError, 5.0), (ValueError, 'foobar'), (ValueError, ('name', 'mpolygon'))):
153 153
             self.assertRaises(e, LayerMapping, County, co_shp, co_mapping, transform=False, unique=arg)
@@ -177,11 +177,11 @@ def test04_layermap_unique_multigeometry_fk(self):
177 177
         # are not collections will be converted into them.  For example,
178 178
         # a Point column would be converted to MultiPoint. Other things being done
179 179
         # w/the keyword args:
180  
-        #  `transform=False`: Specifies that no transform is to be done; this 
  180
+        #  `transform=False`: Specifies that no transform is to be done; this
181 181
         #    has the effect of ignoring the spatial reference check (because the
182 182
         #    county shapefile does not have implicit spatial reference info).
183  
-        # 
184  
-        #  `unique='name'`: Creates models on the condition that they have 
  183
+        #
  184
+        #  `unique='name'`: Creates models on the condition that they have
185 185
         #    unique county names; geometries from each feature however will be
186 186
         #    appended to the geometry collection of the unique model.  Thus,
187 187
         #    all of the various islands in Honolulu county will be in in one
@@ -201,7 +201,7 @@ def test05_test_fid_range_step(self):
201 201
         "Tests the `fid_range` keyword and the `step` keyword of .save()."
202 202
         # Function for clearing out all the counties before testing.
203 203
         def clear_counties(): County.objects.all().delete()
204  
-        
  204
+
205 205
         # Initializing the LayerMapping object to use in these tests.
206 206
         lm = LayerMapping(County, co_shp, co_mapping, transform=False, unique='name')
207 207
 
@@ -213,9 +213,9 @@ def clear_counties(): County.objects.all().delete()
213 213
 
214 214
         # Step keyword should not be allowed w/`fid_range`.
215 215
         fr = (3, 5) # layer[3:5]
216  
-        self.assertRaises(LayerMapError, lm.save, fid_range=fr, step=10) 
  216
+        self.assertRaises(LayerMapError, lm.save, fid_range=fr, step=10)
217 217
         lm.save(fid_range=fr)
218  
-        
  218
+
219 219
         # Features IDs 3 & 4 are for Galveston County, Texas -- only
220 220
         # one model is returned because the `unique` keyword was set.
221 221
         qs = County.objects.all()
@@ -229,9 +229,9 @@ def clear_counties(): County.objects.all().delete()
229 229
         lm.save(fid_range=slice(None, 1), silent=True, strict=True) # layer[:1]
230 230
 
231 231
         # Only Pueblo & Honolulu counties should be present because of
232  
-        # the `unique` keyword.  Have to set `order_by` on this QuerySet 
  232
+        # the `unique` keyword.  Have to set `order_by` on this QuerySet
233 233
         # or else MySQL will return a different ordering than the other dbs.
234  
-        qs = County.objects.order_by('name') 
  234
+        qs = County.objects.order_by('name')
235 235
         self.assertEqual(2, qs.count())
236 236
         hi, co = tuple(qs)
237 237
         hi_idx, co_idx = tuple(map(NAMES.index, ('Honolulu', 'Pueblo')))
@@ -265,7 +265,7 @@ def test06_model_inheritance(self):
265 265
 
266 266
         self.assertEqual(6, ICity1.objects.count())
267 267
         self.assertEqual(3, ICity2.objects.count())
268  
-        
  268
+
269 269
 def suite():
270 270
     s = unittest.TestSuite()
271 271
     s.addTest(unittest.makeSuite(LayerMapTest))
4  django/contrib/gis/tests/test_geoforms.py
... ...
@@ -1,8 +1,8 @@
1  
-import unittest
2  
-
3 1
 from django.forms import ValidationError
4 2
 from django.contrib.gis import forms
5 3
 from django.contrib.gis.geos import GEOSGeometry
  4
+from django.utils import unittest
  5
+
6 6
 
7 7
 class GeometryFieldTest(unittest.TestCase):
8 8
 
53  django/contrib/gis/tests/test_measure.py
... ...
@@ -1,10 +1,11 @@
1 1
 """
2  
-Distance and Area objects to allow for sensible and convienient calculation 
  2
+Distance and Area objects to allow for sensible and convienient calculation
3 3
 and conversions. Here are some tests.
4 4
 """
5 5
 
6  
-import unittest
7 6
 from django.contrib.gis.measure import Distance, Area, D, A
  7
+from django.utils import unittest
  8
+
8 9
 
9 10
 class DistanceTest(unittest.TestCase):
10 11
     "Testing the Distance object"
@@ -30,7 +31,7 @@ def testInit(self):
30 31
             self.assertEqual(d.m, 1.0)
31 32
             self.assertEqual(d.mm, 1000.0)
32 33
 
33  
-    
  34
+
34 35
     def testInitInvalid(self):
35 36
         "Testing initialisation from invalid units"
36 37
         self.assertRaises(AttributeError, D, banana=100)
@@ -40,7 +41,7 @@ def testAccess(self):
40 41
         d = D(m=100)
41 42
         self.assertEqual(d.km, 0.1)
42 43
         self.assertAlmostEqual(d.ft, 328.084, 3)
43  
-    
  44
+
44 45
     def testAccessInvalid(self):
45 46
         "Testing access in invalid units"
46 47
         d = D(m=100)
@@ -55,12 +56,12 @@ def testAddition(self):
55 56
         self.assertEqual(d3.m, 300)
56 57
         d3 += d1
57 58
         self.assertEqual(d3.m, 400)
58  
-        
  59
+
59 60
         d4 = d1 - d2
60 61
         self.assertEqual(d4.m, -100)
61 62
         d4 -= d1
62 63
         self.assertEqual(d4.m, -200)
63  
-        
  64
+
64 65
         try:
65 66
             d5 = d1 + 1
66 67
         except TypeError, e:
@@ -88,7 +89,7 @@ def testAddition(self):
88 89
             pass
89 90
         else:
90 91
             self.fail('Distance -= number should raise TypeError')
91  
-            
  92
+
92 93
     def testMultiplication(self):
93 94
         "Test multiplication & division"
94 95
         d1 = D(m=100)
@@ -99,12 +100,12 @@ def testMultiplication(self):
99 100
         self.assertEqual(d3.m, 200)
100 101
         d3 *= 5
101 102
         self.assertEqual(d3.m, 1000)
102  
-        
  103
+
103 104
         d4 = d1 / 2
104 105
         self.assertEqual(d4.m, 50)
105 106
         d4 /= 5
106 107
         self.assertEqual(d4.m, 10)
107  
-        
  108
+
108 109
         a5 = d1 * D(m=10)
109 110
         self.assert_(isinstance(a5, Area))
110 111
         self.assertEqual(a5.sq_m, 100*10)
@@ -115,7 +116,7 @@ def testMultiplication(self):
115 116
             pass
116 117
         else:
117 118
             self.fail('Distance *= Distance should raise TypeError')
118  
-            
  119
+
119 120
         try:
120 121
             d5 = d1 / D(m=1)
121 122
         except TypeError, e:
@@ -143,23 +144,23 @@ def testUnitConversions(self):
143 144
         self.assertEqual(d5._default_unit, 'm')
144 145
         d6 = d1 / 2
145 146
         self.assertEqual(d6._default_unit, 'm')
146  
-    
  147
+
147 148
     def testComparisons(self):
148 149
         "Testing comparisons"
149 150
         d1 = D(m=100)
150 151
         d2 = D(km=1)
151 152
         d3 = D(km=0)
152  
-        
  153
+
153 154
         self.assert_(d2 > d1)
154 155
         self.assert_(d1 == d1)
155 156
         self.assert_(d1 < d2)
156 157
         self.failIf(d3)
157  
-        
  158
+
158 159
     def testUnitsStr(self):
159 160
         "Testing conversion to strings"
160 161
         d1 = D(m=100)
161 162
         d2 = D(km=3.5)
162  
-        
  163
+
163 164
         self.assertEqual(str(d1), '100.0 m')
164 165
         self.assertEqual(str(d2), '3.5 km')
165 166
         self.assertEqual(repr(d1), 'Distance(m=100.0)')
@@ -185,7 +186,7 @@ def testInit(self):
185 186
 
186 187
         a = A(sq_mi=100)
187 188
         self.assertEqual(a.sq_m, 258998811.0336)
188  
-    
  189
+
189 190
     def testInitInvaliA(self):
190 191
         "Testing initialisation from invalid units"
191 192
         self.assertRaises(AttributeError, A, banana=100)
@@ -195,7 +196,7 @@ def testAccess(self):
195 196
         a = A(sq_m=100)
196 197
         self.assertEqual(a.sq_km, 0.0001)
197 198
         self.assertAlmostEqual(a.sq_ft, 1076.391, 3)
198  
-    
  199
+
199 200
     def testAccessInvaliA(self):
200 201
         "Testing access in invalid units"
201 202
         a = A(sq_m=100)
@@ -210,12 +211,12 @@ def testAddition(self):
210 211
         self.assertEqual(a3.sq_m, 300)
211 212
         a3 += a1
212 213
         self.assertEqual(a3.sq_m, 400)
213  
-        
  214
+
214 215
         a4 = a1 - a2
215 216
         self.assertEqual(a4.sq_m, -100)
216 217
         a4 -= a1
217 218
         self.assertEqual(a4.sq_m, -200)
218  
-        
  219
+
219 220
         try:
220 221
             a5 = a1 + 1
221 222
         except TypeError, e:
@@ -243,7 +244,7 @@ def testAddition(self):
243 244
             pass
244 245
         else:
245 246
             self.fail('Area -= number should raise TypeError')
246  
-            
  247
+
247 248
     def testMultiplication(self):
248 249
         "Test multiplication & division"
249 250
         a1 = A(sq_m=100)
@@ -254,12 +255,12 @@ def testMultiplication(self):
254 255
         self.assertEqual(a3.sq_m, 200)
255 256
         a3 *= 5
256 257
         self.assertEqual(a3.sq_m, 1000)
257  
-        
  258
+
258 259
         a4 = a1 / 2
259 260
         self.assertEqual(a4.sq_m, 50)
260 261
         a4 /= 5
261 262
         self.assertEqual(a4.sq_m, 10)
262  
-        
  263
+
263 264
         try:
264 265
             a5 = a1 * A(sq_m=1)
265 266
         except TypeError, e:
@@ -273,7 +274,7 @@ def testMultiplication(self):
273 274
             pass
274 275
         else:
275 276
             self.fail('Area *= Area should raise TypeError')
276  
-            
  277
+
277 278
         try:
278 279
             a5 = a1 / A(sq_m=1)
279 280
         except TypeError, e:
@@ -301,23 +302,23 @@ def testUnitConversions(self):
301 302
         self.assertEqual(a5._default_unit, 'sq_m')
302 303
         a6 = a1 / 2
303 304
         self.assertEqual(a6._default_unit, 'sq_m')
304  
-    
  305
+
305 306
     def testComparisons(self):
306 307
         "Testing comparisons"
307 308
         a1 = A(sq_m=100)
308 309
         a2 = A(sq_km=1)
309 310
         a3 = A(sq_km=0)
310  
-        
  311
+
311 312
         self.assert_(a2 > a1)
312 313
         self.assert_(a1 == a1)
313 314
         self.assert_(a1 < a2)
314 315
         self.failIf(a3)
315  
-        
  316
+
316 317
     def testUnitsStr(self):
317 318
         "Testing conversion to strings"
318 319
         a1 = A(sq_m=100)
319 320
         a2 = A(sq_km=3.5)
320  
-        
  321
+
321 322
         self.assertEqual(str(a1), '100.0 sq_m')
322 323
         self.assertEqual(str(a2), '3.5 sq_km')
323 324
         self.assertEqual(repr(a1), 'Area(sq_m=100.0)')
8  django/contrib/gis/tests/test_spatialrefsys.py
... ...
@@ -1,7 +1,7 @@
1  
-import unittest
2  
-
3 1
 from django.db import connection
4 2
 from django.contrib.gis.tests.utils import mysql, no_mysql, oracle, postgis, spatialite
  3
+from django.utils import unittest
  4
+
5 5
 
6 6
 test_srs = ({'srid' : 4326,
7 7
              'auth_name' : ('EPSG', True),
@@ -9,7 +9,7 @@
9 9
              'srtext' : 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]',
10 10
              'srtext14' : 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]',
11 11
              'proj4' : '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs ',
12  
-             'spheroid' : 'WGS 84', 'name' : 'WGS 84', 
  12
+             'spheroid' : 'WGS 84', 'name' : 'WGS 84',
13 13
              'geographic' : True, 'projected' : False, 'spatialite' : True,
14 14
              'ellipsoid' : (6378137.0, 6356752.3, 298.257223563), # From proj's "cs2cs -le" and Wikipedia (semi-minor only)
15 15
              'eprec' : (1, 1, 9),
@@ -49,7 +49,7 @@ def test01_retrieve(self):
49 49
             auth_name, oracle_flag = sd['auth_name']
50 50
             if postgis or (oracle and oracle_flag):
51 51
                 self.assertEqual(True, srs.auth_name.startswith(auth_name))
52  
-                
  52
+
53 53
             self.assertEqual(sd['auth_srid'], srs.auth_srid)
54 54
 
55 55
             # No proj.4 and different srtext on oracle backends :(
109  django/contrib/markup/tests.py
... ...
@@ -1,77 +1,90 @@
1 1
 # Quick tests for the markup templatetags (django.contrib.markup)
2  
-
3 2
 import re
4  
-import unittest
5 3
 
6 4
 from django.template import Template, Context, add_to_builtins
  5
+from django.utils import unittest
7 6
 from django.utils.html import escape
8 7
 
9 8
 add_to_builtins('django.contrib.markup.templatetags.markup')
10 9
 
  10
+try:
  11
+    import textile
  12
+except ImportError:
  13
+    textile = None
  14
+
  15
+try:
  16
+    import markdown
  17
+except ImportError:
  18
+    markdown = None
  19
+
  20
+try:
  21
+    import docutils
  22
+except ImportError:
  23
+    docutils = None
  24
+
11 25
 class Templates(unittest.TestCase):
12  
-    def test_textile(self):
13  
-        try:
14  
-            import textile
15  
-        except ImportError:
16  
-            textile = None
17 26
 
18  
-        textile_content = """Paragraph 1
  27
+    textile_content = """Paragraph 1
19 28
 
20 29
 Paragraph 2 with "quotes" and @code@"""
21 30
 
22  
-        t = Template("{{ textile_content|textile }}")
23  
-        rendered = t.render(Context(locals())).strip()
24  
-        if textile:
25  
-            self.assertEqual(rendered.replace('\t', ''), """<p>Paragraph 1</p>
  31
+    markdown_content = """Paragraph 1
26 32
 
27  
-<p>Paragraph 2 with &#8220;quotes&#8221; and <code>code</code></p>""")
28  
-        else:
29  
-            self.assertEqual(rendered, escape(textile_content))
  33
+## An h2"""
30 34
 
31  
-    def test_markdown(self):
32  
-        try:
33  
-            import markdown
34  
-        except ImportError:
35  
-            markdown = None
  35
+    rest_content = """Paragraph 1
36 36
 
37  
-        markdown_content = """Paragraph 1
  37
+Paragraph 2 with a link_
38 38
 
39  
-## An h2"""
  39
+.. _link: http://www.example.com/"""
40 40
 
41  
-        t = Template("{{ markdown_content|markdown }}")
42  
-        rendered = t.render(Context(locals())).strip()
43  
-        if markdown:
44  
-            pattern = re.compile("""<p>Paragraph 1\s*</p>\s*<h2>\s*An h2</h2>""")
45  
-            self.assert_(pattern.match(rendered))
46  
-        else:
47  
-            self.assertEqual(rendered, markdown_content)
48 41
 
49  
-    def test_docutils(self):
50  
-        try:
51  
-            import docutils
52  
-        except ImportError:
53  
-            docutils = None
  42
+    @unittest.skipUnless(textile, 'texttile not installed')
  43
+    def test_textile(self):
  44
+        t = Template("{{ textile_content|textile }}")
  45
+        rendered = t.render(Context({'textile_content':self.textile_content})).strip()
  46
+        self.assertEqual(rendered.replace('\t', ''), """<p>Paragraph 1</p>
54 47
 
55  
-        rest_content = """Paragraph 1
  48
+<p>Paragraph 2 with &#8220;quotes&#8221; and <code>code</code></p>""")
56 49
 
57  
-Paragraph 2 with a link_
  50
+    @unittest.skipIf(textile, 'texttile is installed')
  51
+    def test_no_textile(self):
  52
+        t = Template("{{ textile_content|textile }}")
  53
+        rendered = t.render(Context({'textile_content':self.textile_content})).strip()
  54
+        self.assertEqual(rendered, escape(self.textile_content))
58 55
 
59  
-.. _link: http://www.example.com/"""
  56
+    @unittest.skipUnless(markdown, 'markdown not installed')
  57
+    def test_markdown(self):
  58
+        t = Template("{{ markdown_content|markdown }}")
  59
+        rendered = t.render(Context({'markdown_content':self.markdown_content})).strip()
  60
+        pattern = re.compile("""<p>Paragraph 1\s*</p>\s*<h2>\s*An h2</h2>""")
  61
+        self.assertTrue(pattern.match(rendered))
  62
+
  63
+    @unittest.skipIf(markdown, 'markdown is installed')
  64
+    def test_no_markdown(self):
  65
+        t = Template("{{ markdown_content|markdown }}")
  66
+        rendered = t.render(Context({'markdown_content':self.markdown_content})).strip()
  67
+        self.assertEqual(rendered, self.markdown_content)
60 68
 
  69
+    @unittest.skipUnless(docutils, 'docutils not installed')
  70
+    def test_docutils(self):
61 71
         t = Template("{{ rest_content|restructuredtext }}")
62  
-        rendered = t.render(Context(locals())).strip()
63  
-        if docutils:
64  
-            # Different versions of docutils return slightly different HTML
65  
-            try:
66  
-                # Docutils v0.4 and earlier
67  
-                self.assertEqual(rendered, """<p>Paragraph 1</p>
  72
+        rendered = t.render(Context({'rest_content':self.rest_content})).strip()
  73
+        # Different versions of docutils return slightly different HTML
  74
+        try:
  75
+            # Docutils v0.4 and earlier
  76
+            self.assertEqual(rendered, """<p>Paragraph 1</p>
68 77
 <p>Paragraph 2 with a <a class="reference" href="http://www.example.com/">link</a></p>""")
69  
-            except AssertionError, e:
70  
-                # Docutils from SVN (which will become 0.5)
71  
-                self.assertEqual(rendered, """<p>Paragraph 1</p>
  78
+        except AssertionError, e:
  79
+            # Docutils from SVN (which will become 0.5)
  80
+            self.assertEqual(rendered, """<p>Paragraph 1</p>
72 81
 <p>Paragraph 2 with a <a class="reference external" href="http://www.example.com/">link</a></p>""")
73  
-        else:
74  
-            self.assertEqual(rendered, rest_content)
  82
+
  83
+    @unittest.skipIf(docutils, 'docutils is installed')
  84
+    def test_no_docutils(self):
  85
+        t = Template("{{ rest_content|restructuredtext }}")
  86
+        rendered = t.render(Context({'rest_content':self.rest_content})).strip()
  87
+        self.assertEqual(rendered, self.rest_content)
75 88
 
76 89
 
77 90
 if __name__ == '__main__':
2  django/contrib/messages/tests/middleware.py
... ...
@@ -1,6 +1,6 @@
1  
-import unittest
2 1
 from django import http
3 2
 from django.contrib.messages.middleware import MessageMiddleware
  3
+from django.utils import unittest
4 4
 
5 5
 
6 6
 class MiddlewareTest(unittest.TestCase):
7  django/contrib/sessions/tests.py
... ...
@@ -1,4 +1,7 @@
1 1
 from datetime import datetime, timedelta
  2
+import shutil
  3
+import tempfile
  4
+
2 5
 from django.conf import settings
3 6
 from django.contrib.sessions.backends.db import SessionStore as DatabaseSession
4 7
 from django.contrib.sessions.backends.cache import SessionStore as CacheSession
@@ -8,9 +11,7 @@
8 11
 from django.contrib.sessions.models import Session
9 12
 from django.core.exceptions import ImproperlyConfigured
10 13
 from django.test import TestCase
11  
-import shutil
12  
-import tempfile
13  
-import unittest
  14
+from django.utils import unittest
14 15
 
15 16
 
16 17
 class SessionTestsMixin(object):
90  django/db/backends/__init__.py
@@ -20,6 +20,7 @@ def __init__(self, settings_dict, alias=DEFAULT_DB_ALIAS):
20 20
         self.queries = []
21 21
         self.settings_dict = settings_dict
22 22
         self.alias = alias
  23
+        self.vendor = 'unknown'
23 24
 
24 25
     def __eq__(self, other):
25 26
         return self.settings_dict == other.settings_dict
@@ -87,16 +88,105 @@ class BaseDatabaseFeatures(object):
87 88
     needs_datetime_string_cast = True
88 89
     empty_fetchmany_value = []
89 90
     update_can_self_select = True
  91
+
  92
+    # Does the backend distinguish between '' and None?
90 93
     interprets_empty_strings_as_nulls = False
  94
+
91 95
     can_use_chunked_reads = True
92 96
     can_return_id_from_insert = False
93 97
     uses_autocommit = False
94 98
     uses_savepoints = False
  99
+
95 100
     # If True, don't use integer foreign keys referring to, e.g., positive
96 101
     # integer primary keys.
97 102
     related_fields_match_type = False
98 103
     allow_sliced_subqueries = True
99 104
 
  105
+    # Does the default test database allow multiple connections?
  106
+    # Usually an indication that the test database is in-memory
  107
+    test_db_allows_multiple_connections = True
  108
+
  109
+    # Can an object be saved without an explicit primary key?
  110
+    supports_unspecified_pk = False
  111
+
  112
+    # Can a fixture contain forward references? i.e., are
  113
+    # FK constraints checked at the end of transaction, or
  114
+    # at the end of each save operation?
  115
+    supports_forward_references = True
  116
+
  117
+    # Does a dirty transaction need to be rolled back
  118
+    # before the cursor can be used again?
  119
+    requires_rollback_on_dirty_transaction = False
  120
+
  121
+    # Does the backend allow very long model names without error?
  122
+    supports_long_model_names = True
  123
+
  124
+    # Is there a REAL datatype in addition to floats/doubles?
  125
+    has_real_datatype = False
  126
+    supports_subqueries_in_group_by = True
  127
+    supports_bitwise_or = True
  128
+
  129
+    # Do time/datetime fields have microsecond precision?
  130
+    supports_microsecond_precision = True
  131
+
  132
+    # Does the __regex lookup support backreferencing and grouping?
  133
+    supports_regex_backreferencing = True
  134
+
  135
+    # Can date/datetime lookups be performed using a string?
  136
+    supports_date_lookup_using_string = True
  137
+
  138
+    # Can datetimes with timezones be used?
  139
+    supports_timezones = True
  140
+
  141
+    # When performing a GROUP BY, is an ORDER BY NULL required
  142
+    # to remove any ordering?
  143
+    requires_explicit_null_ordering_when_grouping = False
  144
+
  145
+    # Is there a 1000 item limit on query parameters?
  146
+    supports_1000_query_paramters = True
  147
+
  148
+    # Can an object have a primary key of 0? MySQL says No.
  149
+    allows_primary_key_0 = True
  150
+
  151
+    # Features that need to be confirmed at runtime
  152
+    # Cache whether the confirmation has been performed.
  153
+    _confirmed = False
  154
+    supports_transactions = None
  155
+    supports_stddev = None
  156
+
  157
+    def __init__(self, connection):
  158
+        self.connection = connection
  159
+
  160
+    def confirm(self):
  161
+        "Perform manual checks of any database features that might vary between installs"
  162
+        self._confirmed = True
  163
+        self.supports_transactions = self._supports_transactions()
  164
+        self.supports_stddev = self._supports_stddev()
  165
+
  166
+    def _supports_transactions(self):
  167
+        "Confirm support for transactions"
  168
+        cursor = self.connection.cursor()
  169
+        cursor.execute('CREATE TABLE ROLLBACK_TEST (X INT)')
  170
+        self.connection._commit()
  171
+        cursor.execute('INSERT INTO ROLLBACK_TEST (X) VALUES (8)')
  172
+        self.connection._rollback()
  173
+        cursor.execute('SELECT COUNT(X) FROM ROLLBACK_TEST')
  174
+        count, = cursor.fetchone()
  175
+        cursor.execute('DROP TABLE ROLLBACK_TEST')
  176
+        self.connection._commit()
  177
+        return count == 0
  178
+
  179
+    def _supports_stddev(self):
  180
+        "Confirm support for STDDEV and related stats functions"
  181
+        class StdDevPop(object):
  182
+            sql_function = 'STDDEV_POP'
  183
+
  184
+        try:
  185
+            self.connection.ops.check_aggregate_support(StdDevPop())
  186
+        except DatabaseError:
  187
+            self.supports_stddev = False
  188
+
  189
+
100 190
 class BaseDatabaseOperations(object):
101 191
     """
102 192
     This class encapsulates all backend-specific differences, such as the way
17  django/db/backends/creation.py
@@ -347,8 +347,9 @@ def create_test_db(self, verbosity=1, autoclobber=False):
347 347
 
348 348
         self.connection.close()
349 349
         self.connection.settings_dict["NAME"] = test_database_name
350  
-        can_rollback = self._rollback_works()
351  
-        self.connection.settings_dict["SUPPORTS_TRANSACTIONS"] = can_rollback
  350
+
  351
+        # Confirm the feature set of the test database
  352
+        self.connection.features.confirm()
352 353
 
353 354
         # Report syncdb messages at one level lower than that requested.
354 355
         # This ensures we don't get flooded with messages during testing
@@ -405,18 +406,6 @@ def _create_test_db(self, verbosity, autoclobber):
405 406
 
406 407
         return test_database_name
407 408
 
408  
-    def _rollback_works(self):
409  
-        cursor = self.connection.cursor()
410  
-        cursor.execute('CREATE TABLE ROLLBACK_TEST (X INT)')
411  
-        self.connection._commit()
412  
-        cursor.execute('INSERT INTO ROLLBACK_TEST (X) VALUES (8)')
413  
-        self.connection._rollback()
414  
-        cursor.execute('SELECT COUNT(X) FROM ROLLBACK_TEST')
415  
-        count, = cursor.fetchone()
416  
-        cursor.execute('DROP TABLE ROLLBACK_TEST')
417  
-        self.connection._commit()
418  
-        return count == 0
419  
-
420 409
     def destroy_test_db(self, old_database_name, verbosity=1):
421 410
         """
422 411
         Destroy a test database, prompting the user for confirmation if the
2  django/db/backends/dummy/base.py
@@ -42,7 +42,7 @@ class DatabaseWrapper(object):
42 42
     _rollback = ignore
43 43
 
44 44
     def __init__(self, settings_dict, alias, *args, **kwargs):
45  
-        self.features = BaseDatabaseFeatures()
  45
+        self.features = BaseDatabaseFeatures(self)
46 46
         self.ops = DatabaseOperations()
47 47
         self.client = DatabaseClient(self)
48 48
         self.creation = BaseDatabaseCreation(self)
12  django/db/backends/mysql/base.py
@@ -124,6 +124,14 @@ class DatabaseFeatures(BaseDatabaseFeatures):
124 124
     allows_group_by_pk = True
125 125
     related_fields_match_type = True
126 126
     allow_sliced_subqueries = False
  127
+    supports_forward_references = False
  128
+    supports_long_model_names = False
  129
+    supports_microsecond_precision = False
  130
+    supports_regex_backreferencing = False
  131
+    supports_date_lookup_using_string = False
  132
+    supports_timezones = False
  133
+    requires_explicit_null_ordering_when_grouping = True
  134
+    allows_primary_key_0 = False
127 135
 
128 136
 class DatabaseOperations(BaseDatabaseOperations):
129 137
     compiler_module = "django.db.backends.mysql.compiler"
@@ -231,7 +239,7 @@ def max_name_length(self):
231 239
         return 64
232 240