diff options
| author | Andrew Godwin <andrew@aeracode.org> | 2012-07-26 18:58:10 +0100 |
|---|---|---|
| committer | Andrew Godwin <andrew@aeracode.org> | 2012-07-26 18:58:10 +0100 |
| commit | 4a2e80fff44d0eb1856b593ac5f31ab1492b3e45 (patch) | |
| tree | 9bc87a682dc488e6555792c1d4bb53f5f3cdc880 /tests | |
| parent | 959a3f9791d780062c4efe8765404a8ef95e87f0 (diff) | |
| parent | ab6cd1c839b136cbc94178da433b2e97ab7f6061 (diff) | |
Merge branch 'master' of github.com:django/django into schema-alteration
Conflicts:
django/db/backends/postgresql_psycopg2/base.py
Diffstat (limited to 'tests')
112 files changed, 1249 insertions, 674 deletions
diff --git a/tests/modeltests/aggregation/tests.py b/tests/modeltests/aggregation/tests.py index 433ea1641a..c23b32fc85 100644 --- a/tests/modeltests/aggregation/tests.py +++ b/tests/modeltests/aggregation/tests.py @@ -565,3 +565,23 @@ class BaseAggregateTestCase(TestCase): (Decimal('82.8'), 1), ] ) + + def test_dates_with_aggregation(self): + """ + Test that .dates() returns a distinct set of dates when applied to a + QuerySet with aggregation. + + Refs #18056. Previously, .dates() would return distinct (date_kind, + aggregation) sets, in this case (year, num_authors), so 2008 would be + returned twice because there are books from 2008 with a different + number of authors. + """ + dates = Book.objects.annotate(num_authors=Count("authors")).dates('pubdate', 'year') + self.assertQuerysetEqual( + dates, [ + "datetime.datetime(1991, 1, 1, 0, 0)", + "datetime.datetime(1995, 1, 1, 0, 0)", + "datetime.datetime(2007, 1, 1, 0, 0)", + "datetime.datetime(2008, 1, 1, 0, 0)" + ] + ) diff --git a/tests/modeltests/basic/tests.py b/tests/modeltests/basic/tests.py index 3f00fb25fe..d96c60bbe8 100644 --- a/tests/modeltests/basic/tests.py +++ b/tests/modeltests/basic/tests.py @@ -5,6 +5,7 @@ from datetime import datetime from django.core.exceptions import ObjectDoesNotExist from django.db.models.fields import Field, FieldDoesNotExist from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature +from django.utils.six import PY3 from django.utils.translation import ugettext_lazy from .models import Article @@ -321,17 +322,18 @@ class ModelTest(TestCase): ["<Article: Area man programs in Python>", "<Article: Third article>"]) - # Slicing works with longs. - self.assertEqual(Article.objects.all()[0L], a) - self.assertQuerysetEqual(Article.objects.all()[1L:3L], - ["<Article: Second article>", "<Article: Third article>"]) - self.assertQuerysetEqual((s1 | s2 | s3)[::2L], - ["<Article: Area man programs in Python>", - "<Article: Third article>"]) + # Slicing works with longs (Python 2 only -- Python 3 doesn't have longs). + if not PY3: + self.assertEqual(Article.objects.all()[long(0)], a) + self.assertQuerysetEqual(Article.objects.all()[long(1):long(3)], + ["<Article: Second article>", "<Article: Third article>"]) + self.assertQuerysetEqual((s1 | s2 | s3)[::long(2)], + ["<Article: Area man programs in Python>", + "<Article: Third article>"]) - # And can be mixed with ints. - self.assertQuerysetEqual(Article.objects.all()[1:3L], - ["<Article: Second article>", "<Article: Third article>"]) + # And can be mixed with ints. + self.assertQuerysetEqual(Article.objects.all()[1:long(3)], + ["<Article: Second article>", "<Article: Third article>"]) # Slices (without step) are lazy: self.assertQuerysetEqual(Article.objects.all()[0:5].filter(), diff --git a/tests/modeltests/custom_columns/tests.py b/tests/modeltests/custom_columns/tests.py index c1bb6f0a01..a2e5323a75 100644 --- a/tests/modeltests/custom_columns/tests.py +++ b/tests/modeltests/custom_columns/tests.py @@ -2,6 +2,7 @@ from __future__ import absolute_import from django.core.exceptions import FieldError from django.test import TestCase +from django.utils import six from .models import Author, Article @@ -22,13 +23,13 @@ class CustomColumnsTests(TestCase): Author.objects.all(), [ "Peter Jones", "John Smith", ], - unicode + six.text_type ) self.assertQuerysetEqual( Author.objects.filter(first_name__exact="John"), [ "John Smith", ], - unicode + six.text_type ) self.assertEqual( Author.objects.get(first_name__exact="John"), @@ -55,7 +56,7 @@ class CustomColumnsTests(TestCase): "Peter Jones", "John Smith", ], - unicode + six.text_type ) # Get the articles for an author self.assertQuerysetEqual( @@ -69,5 +70,5 @@ class CustomColumnsTests(TestCase): art.authors.filter(last_name='Jones'), [ "Peter Jones" ], - unicode + six.text_type ) diff --git a/tests/modeltests/custom_managers/tests.py b/tests/modeltests/custom_managers/tests.py index bdba3d0733..294920de2b 100644 --- a/tests/modeltests/custom_managers/tests.py +++ b/tests/modeltests/custom_managers/tests.py @@ -1,6 +1,7 @@ from __future__ import absolute_import from django.test import TestCase +from django.utils import six from .models import Person, Book, Car, PersonManager, PublishedBookManager @@ -14,7 +15,7 @@ class CustomManagerTests(TestCase): Person.objects.get_fun_people(), [ "Bugs Bunny" ], - unicode + six.text_type ) # The RelatedManager used on the 'books' descriptor extends the default # manager diff --git a/tests/modeltests/custom_pk/fields.py b/tests/modeltests/custom_pk/fields.py index 40551a363c..68fb9dcd16 100644 --- a/tests/modeltests/custom_pk/fields.py +++ b/tests/modeltests/custom_pk/fields.py @@ -2,6 +2,7 @@ import random import string from django.db import models +from django.utils import six class MyWrapper(object): @@ -44,12 +45,12 @@ class MyAutoField(models.CharField): if not value: return if isinstance(value, MyWrapper): - return unicode(value) + return six.text_type(value) return value def get_db_prep_value(self, value, connection, prepared=False): if not value: return if isinstance(value, MyWrapper): - return unicode(value) + return six.text_type(value) return value diff --git a/tests/modeltests/custom_pk/tests.py b/tests/modeltests/custom_pk/tests.py index b473dcab59..3f562f0bed 100644 --- a/tests/modeltests/custom_pk/tests.py +++ b/tests/modeltests/custom_pk/tests.py @@ -3,6 +3,7 @@ from __future__ import absolute_import, unicode_literals from django.db import transaction, IntegrityError from django.test import TestCase, skipIfDBFeature +from django.utils import six from .models import Employee, Business, Bar, Foo @@ -16,7 +17,7 @@ class CustomPKTests(TestCase): Employee.objects.all(), [ "Dan Jones", ], - unicode + six.text_type ) fran = Employee.objects.create( @@ -27,7 +28,7 @@ class CustomPKTests(TestCase): "Fran Bones", "Dan Jones", ], - unicode + six.text_type ) self.assertEqual(Employee.objects.get(pk=123), dan) @@ -45,7 +46,7 @@ class CustomPKTests(TestCase): "Fran Bones", "Dan Jones", ], - unicode + six.text_type ) # The primary key can be accessed via the pk property on the model. e = Employee.objects.get(pk=123) @@ -63,7 +64,7 @@ class CustomPKTests(TestCase): "Dan Jones", "Fran Jones", ], - unicode + six.text_type ) emps = Employee.objects.in_bulk([123, 456]) @@ -76,7 +77,7 @@ class CustomPKTests(TestCase): "Dan Jones", "Fran Jones", ], - unicode + six.text_type ) self.assertQuerysetEqual( fran.business_set.all(), [ @@ -108,14 +109,14 @@ class CustomPKTests(TestCase): "Dan Jones", "Fran Jones", ], - unicode, + six.text_type, ) self.assertQuerysetEqual( Employee.objects.filter(business__pk="Sears"), [ "Dan Jones", "Fran Jones", ], - unicode, + six.text_type, ) self.assertQuerysetEqual( diff --git a/tests/modeltests/defer/tests.py b/tests/modeltests/defer/tests.py index eb09162b01..50db5a76b4 100644 --- a/tests/modeltests/defer/tests.py +++ b/tests/modeltests/defer/tests.py @@ -1,6 +1,6 @@ from __future__ import absolute_import -from django.db.models.query_utils import DeferredAttribute +from django.db.models.query_utils import DeferredAttribute, InvalidQuery from django.test import TestCase from .models import Secondary, Primary, Child, BigChild, ChildProxy @@ -73,9 +73,19 @@ class DeferTests(TestCase): self.assert_delayed(qs.defer("name").get(pk=p1.pk), 1) self.assert_delayed(qs.only("name").get(pk=p1.pk), 2) - # DOES THIS WORK? - self.assert_delayed(qs.only("name").select_related("related")[0], 1) - self.assert_delayed(qs.defer("related").select_related("related")[0], 0) + # When we defer a field and also select_related it, the query is + # invalid and raises an exception. + with self.assertRaises(InvalidQuery): + qs.only("name").select_related("related")[0] + with self.assertRaises(InvalidQuery): + qs.defer("related").select_related("related")[0] + + # With a depth-based select_related, all deferred ForeignKeys are + # deferred instead of traversed. + with self.assertNumQueries(3): + obj = qs.defer("related").select_related()[0] + self.assert_delayed(obj, 1) + self.assertEqual(obj.related.id, s1.pk) # Saving models with deferred fields is possible (but inefficient, # since every field has to be retrieved first). @@ -155,7 +165,7 @@ class DeferTests(TestCase): children = ChildProxy.objects.all().select_related().only('id', 'name') self.assertEqual(len(children), 1) child = children[0] - self.assert_delayed(child, 1) + self.assert_delayed(child, 2) self.assertEqual(child.name, 'p1') self.assertEqual(child.value, 'xx') diff --git a/tests/modeltests/delete/tests.py b/tests/modeltests/delete/tests.py index d681a76fd2..26f2fd52c1 100644 --- a/tests/modeltests/delete/tests.py +++ b/tests/modeltests/delete/tests.py @@ -2,6 +2,7 @@ from __future__ import absolute_import from django.db import models, IntegrityError from django.test import TestCase, skipUnlessDBFeature, skipIfDBFeature +from django.utils.six.moves import xrange from .models import (R, RChild, S, T, U, A, M, MR, MRNull, create_a, get_default_r, User, Avatar, HiddenUser, HiddenUserProfile) diff --git a/tests/modeltests/expressions/tests.py b/tests/modeltests/expressions/tests.py index c4e2707109..99eb07e370 100644 --- a/tests/modeltests/expressions/tests.py +++ b/tests/modeltests/expressions/tests.py @@ -3,6 +3,7 @@ from __future__ import absolute_import, unicode_literals from django.core.exceptions import FieldError from django.db.models import F from django.test import TestCase +from django.utils import six from .models import Company, Employee @@ -156,7 +157,7 @@ class ExpressionsTests(TestCase): "Frank Meyer", "Max Mustermann", ], - lambda c: unicode(c.point_of_contact), + lambda c: six.text_type(c.point_of_contact), ) c = Company.objects.all()[0] diff --git a/tests/modeltests/field_defaults/tests.py b/tests/modeltests/field_defaults/tests.py index 206d380e1e..5d9b45610e 100644 --- a/tests/modeltests/field_defaults/tests.py +++ b/tests/modeltests/field_defaults/tests.py @@ -3,6 +3,7 @@ from __future__ import absolute_import from datetime import datetime from django.test import TestCase +from django.utils import six from .models import Article @@ -13,6 +14,6 @@ class DefaultTests(TestCase): now = datetime.now() a.save() - self.assertTrue(isinstance(a.id, (int, long))) + self.assertTrue(isinstance(a.id, six.integer_types)) self.assertEqual(a.headline, "Default headline") self.assertTrue((now - a.pub_date).seconds < 5) diff --git a/tests/modeltests/field_subclassing/fields.py b/tests/modeltests/field_subclassing/fields.py index b9987c0fab..a21085de9d 100644 --- a/tests/modeltests/field_subclassing/fields.py +++ b/tests/modeltests/field_subclassing/fields.py @@ -4,6 +4,7 @@ import json from django.db import models from django.utils.encoding import force_unicode +from django.utils import six class Small(object): @@ -18,7 +19,7 @@ class Small(object): return '%s%s' % (force_unicode(self.first), force_unicode(self.second)) def __str__(self): - return unicode(self).encode('utf-8') + return six.text_type(self).encode('utf-8') class SmallField(models.Field): """ @@ -41,7 +42,7 @@ class SmallField(models.Field): return Small(value[0], value[1]) def get_db_prep_save(self, value, connection): - return unicode(value) + return six.text_type(value) def get_prep_lookup(self, lookup_type, value): if lookup_type == 'exact': @@ -66,7 +67,7 @@ class JSONField(models.TextField): if not value: return None - if isinstance(value, basestring): + if isinstance(value, six.string_types): value = json.loads(value) return value diff --git a/tests/modeltests/files/models.py b/tests/modeltests/files/models.py index 4134472748..cefc7c7244 100644 --- a/tests/modeltests/files/models.py +++ b/tests/modeltests/files/models.py @@ -26,5 +26,5 @@ class Storage(models.Model): normal = models.FileField(storage=temp_storage, upload_to='tests') custom = models.FileField(storage=temp_storage, upload_to=custom_upload_to) - random = models.FileField(storage=temp_storage, upload_to=random_upload_to) + random = models.FileField(storage=temp_storage, upload_to=random_upload_to, max_length=16) default = models.FileField(storage=temp_storage, upload_to='tests', default='tests/default.txt') diff --git a/tests/modeltests/files/tests.py b/tests/modeltests/files/tests.py index 3e256f787f..565d4c8942 100644 --- a/tests/modeltests/files/tests.py +++ b/tests/modeltests/files/tests.py @@ -5,6 +5,7 @@ import shutil import tempfile from django.core.cache import cache +from django.core.exceptions import ValidationError from django.core.files import File from django.core.files.base import ContentFile from django.core.files.uploadedfile import SimpleUploadedFile @@ -102,11 +103,23 @@ class FileStorageTests(TestCase): obj4.random.save("random_file", ContentFile(b"random content")) self.assertTrue(obj4.random.name.endswith("/random_file")) - # Clean up the temporary files and dir. - obj1.normal.delete() - obj2.normal.delete() - obj3.default.delete() - obj4.random.delete() + def test_max_length(self): + """ + Test that FileField validates the length of the generated file name + that will be stored in the database. Regression for #9893. + """ + # upload_to = 'unused', so file names are saved as '456/xxxxx'. + # max_length = 16, so names longer than 12 characters are rejected. + s1 = Storage(random=SimpleUploadedFile(12 * 'x', b"content")) + s1.full_clean() + with self.assertRaises(ValidationError): + Storage(random=SimpleUploadedFile(13 * 'x', b"content")).full_clean() + + # Ticket #18515: validation for an already saved file should not check + # against a regenerated file name (and potentially raise a ValidationError + # if max_length is exceeded + s1.save() + s1.full_clean() class FileTests(unittest.TestCase): diff --git a/tests/modeltests/fixtures_model_package/tests.py b/tests/modeltests/fixtures_model_package/tests.py index 17538ed7e8..d147fe68a7 100644 --- a/tests/modeltests/fixtures_model_package/tests.py +++ b/tests/modeltests/fixtures_model_package/tests.py @@ -40,7 +40,7 @@ class TestNoInitialDataLoading(TransactionTestCase): # Test presence of fixture (flush called by TransactionTestCase) self.assertQuerysetEqual( Book.objects.all(), [ - u'Achieving self-awareness of Python programs' + 'Achieving self-awareness of Python programs' ], lambda a: a.name ) diff --git a/tests/modeltests/generic_relations/tests.py b/tests/modeltests/generic_relations/tests.py index d3de71d917..14871e4e09 100644 --- a/tests/modeltests/generic_relations/tests.py +++ b/tests/modeltests/generic_relations/tests.py @@ -231,7 +231,7 @@ class GenericRelationsTests(TestCase): tag = TaggedItem.objects.create(content_object=tailless, tag="lizard") self.assertEqual(tag.content_object, tailless) -class CustomWidget(forms.CharField): +class CustomWidget(forms.TextInput): pass class TaggedItemForm(forms.ModelForm): diff --git a/tests/modeltests/lookup/models.py b/tests/modeltests/lookup/models.py index 3e5d61538a..b685750347 100644 --- a/tests/modeltests/lookup/models.py +++ b/tests/modeltests/lookup/models.py @@ -7,6 +7,7 @@ This demonstrates features of the database API. from __future__ import unicode_literals from django.db import models +from django.utils import six class Author(models.Model): @@ -35,7 +36,7 @@ class Season(models.Model): gt = models.IntegerField(null=True, blank=True) def __unicode__(self): - return unicode(self.year) + return six.text_type(self.year) class Game(models.Model): season = models.ForeignKey(Season, related_name='games') diff --git a/tests/modeltests/m2m_and_m2o/models.py b/tests/modeltests/m2m_and_m2o/models.py index 6c1f277811..92ed3fbcd9 100644 --- a/tests/modeltests/m2m_and_m2o/models.py +++ b/tests/modeltests/m2m_and_m2o/models.py @@ -6,6 +6,7 @@ Make sure to set ``related_name`` if you use relationships to the same table. from __future__ import unicode_literals from django.db import models +from django.utils import six class User(models.Model): @@ -17,7 +18,7 @@ class Issue(models.Model): client = models.ForeignKey(User, related_name='test_issue_client') def __unicode__(self): - return unicode(self.num) + return six.text_type(self.num) class Meta: ordering = ('num',) diff --git a/tests/modeltests/m2m_intermediary/tests.py b/tests/modeltests/m2m_intermediary/tests.py index cdc762246a..f261f23546 100644 --- a/tests/modeltests/m2m_intermediary/tests.py +++ b/tests/modeltests/m2m_intermediary/tests.py @@ -3,6 +3,7 @@ from __future__ import absolute_import from datetime import datetime from django.test import TestCase +from django.utils import six from .models import Reporter, Article, Writer @@ -24,7 +25,7 @@ class M2MIntermediaryTests(TestCase): ("John Smith", "Main writer"), ("Jane Doe", "Contributor"), ], - lambda w: (unicode(w.reporter), w.position) + lambda w: (six.text_type(w.reporter), w.position) ) self.assertEqual(w1.reporter, r1) self.assertEqual(w2.reporter, r2) @@ -36,5 +37,5 @@ class M2MIntermediaryTests(TestCase): r1.writer_set.all(), [ ("John Smith", "Main writer") ], - lambda w: (unicode(w.reporter), w.position) + lambda w: (six.text_type(w.reporter), w.position) ) diff --git a/tests/modeltests/many_to_one/tests.py b/tests/modeltests/many_to_one/tests.py index 257025583b..20bd1be0df 100644 --- a/tests/modeltests/many_to_one/tests.py +++ b/tests/modeltests/many_to_one/tests.py @@ -3,8 +3,9 @@ from __future__ import absolute_import from copy import deepcopy from datetime import datetime -from django.core.exceptions import MultipleObjectsReturned +from django.core.exceptions import MultipleObjectsReturned, FieldError from django.test import TestCase +from django.utils import six from django.utils.translation import ugettext_lazy from .models import Article, Reporter @@ -421,6 +422,18 @@ class ManyToOneTests(TestCase): lazy = ugettext_lazy('test') reporter.article_set.create(headline=lazy, pub_date=datetime(2011, 6, 10)) - notlazy = unicode(lazy) + notlazy = six.text_type(lazy) article = reporter.article_set.get() self.assertEqual(article.headline, notlazy) + + def test_values_list_exception(self): + expected_message = "Cannot resolve keyword 'notafield' into field. Choices are: %s" + + self.assertRaisesMessage(FieldError, + expected_message % ', '.join(Reporter._meta.get_all_field_names()), + Article.objects.values_list, + 'reporter__notafield') + self.assertRaisesMessage(FieldError, + expected_message % ', '.join(['EXTRA',] + Article._meta.get_all_field_names()), + Article.objects.extra(select={'EXTRA': 'EXTRA_SELECT'}).values_list, + 'notafield') diff --git a/tests/modeltests/many_to_one_null/tests.py b/tests/modeltests/many_to_one_null/tests.py index 1a404bde02..4de44b5e64 100644 --- a/tests/modeltests/many_to_one_null/tests.py +++ b/tests/modeltests/many_to_one_null/tests.py @@ -88,8 +88,8 @@ class ManyToOneNullTests(TestCase): def test_clear_efficiency(self): r = Reporter.objects.create() - for _ in xrange(3): + for _ in range(3): r.article_set.create() with self.assertNumQueries(1): r.article_set.clear() - self.assertEqual(r.article_set.count(), 0)
\ No newline at end of file + self.assertEqual(r.article_set.count(), 0) diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py index a4ce86f184..8942b21f73 100644 --- a/tests/modeltests/model_forms/models.py +++ b/tests/modeltests/model_forms/models.py @@ -13,6 +13,7 @@ import tempfile from django.core.files.storage import FileSystemStorage from django.db import models +from django.utils import six temp_storage_dir = tempfile.mkdtemp(dir=os.environ['DJANGO_TEST_TEMP_DIR']) @@ -226,7 +227,7 @@ class BigInt(models.Model): biggie = models.BigIntegerField() def __unicode__(self): - return unicode(self.biggie) + return six.text_type(self.biggie) class MarkupField(models.CharField): def __init__(self, *args, **kwargs): diff --git a/tests/modeltests/model_forms/tests.py b/tests/modeltests/model_forms/tests.py index 281316a28e..fc37a25872 100644 --- a/tests/modeltests/model_forms/tests.py +++ b/tests/modeltests/model_forms/tests.py @@ -11,6 +11,7 @@ from django.db import connection from django.forms.models import model_to_dict from django.utils.unittest import skipUnless from django.test import TestCase +from django.utils import six from .models import (Article, ArticleStatus, BetterWriter, BigInt, Book, Category, CommaSeparatedInteger, CustomFieldForExclusionModel, DerivedBook, @@ -653,7 +654,7 @@ class OldFormForXTests(TestCase): # ManyToManyFields are represented by a MultipleChoiceField, ForeignKeys and any # fields with the 'choices' attribute are represented by a ChoiceField. f = ArticleForm(auto_id=False) - self.assertHTMLEqual(unicode(f), '''<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr> + self.assertHTMLEqual(six.text_type(f), '''<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr> <tr><th>Slug:</th><td><input type="text" name="slug" maxlength="50" /></td></tr> <tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr> <tr><th>Writer:</th><td><select name="writer"> @@ -681,14 +682,14 @@ class OldFormForXTests(TestCase): # a value of None. If a field isn't specified on a form, the object created # from the form can't provide a value for that field! f = PartialArticleForm(auto_id=False) - self.assertHTMLEqual(unicode(f), '''<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr> + self.assertHTMLEqual(six.text_type(f), '''<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr> <tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr>''') # When the ModelForm is passed an instance, that instance's current values are # inserted as 'initial' data in each Field. w = Writer.objects.get(name='Mike Royko') f = RoykoForm(auto_id=False, instance=w) - self.assertHTMLEqual(unicode(f), '''<tr><th>Name:</th><td><input type="text" name="name" value="Mike Royko" maxlength="50" /><br /><span class="helptext">Use both first and last names.</span></td></tr>''') + self.assertHTMLEqual(six.text_type(f), '''<tr><th>Name:</th><td><input type="text" name="name" value="Mike Royko" maxlength="50" /><br /><span class="helptext">Use both first and last names.</span></td></tr>''') art = Article( headline='Test article', @@ -725,7 +726,7 @@ class OldFormForXTests(TestCase): 'headline': 'Test headline', 'slug': 'test-headline', 'pub_date': '1984-02-06', - 'writer': unicode(w_royko.pk), + 'writer': six.text_type(w_royko.pk), 'article': 'Hello.' }, instance=art) self.assertEqual(f.errors, {}) @@ -808,9 +809,9 @@ class OldFormForXTests(TestCase): 'headline': 'New headline', 'slug': 'new-headline', 'pub_date': '1988-01-04', - 'writer': unicode(w_royko.pk), + 'writer': six.text_type(w_royko.pk), 'article': 'Hello.', - 'categories': [unicode(c1.id), unicode(c2.id)] + 'categories': [six.text_type(c1.id), six.text_type(c2.id)] }, instance=new_art) new_art = f.save() self.assertEqual(new_art.id == art_id_1, True) @@ -820,7 +821,7 @@ class OldFormForXTests(TestCase): # Now, submit form data with no categories. This deletes the existing categories. f = TestArticleForm({'headline': 'New headline', 'slug': 'new-headline', 'pub_date': '1988-01-04', - 'writer': unicode(w_royko.pk), 'article': 'Hello.'}, instance=new_art) + 'writer': six.text_type(w_royko.pk), 'article': 'Hello.'}, instance=new_art) new_art = f.save() self.assertEqual(new_art.id == art_id_1, True) new_art = Article.objects.get(id=art_id_1) @@ -828,7 +829,7 @@ class OldFormForXTests(TestCase): # Create a new article, with categories, via the form. f = ArticleForm({'headline': 'The walrus was Paul', 'slug': 'walrus-was-paul', 'pub_date': '1967-11-01', - 'writer': unicode(w_royko.pk), 'article': 'Test.', 'categories': [unicode(c1.id), unicode(c2.id)]}) + 'writer': six.text_type(w_royko.pk), 'article': 'Test.', 'categories': [six.text_type(c1.id), six.text_type(c2.id)]}) new_art = f.save() art_id_2 = new_art.id self.assertEqual(art_id_2 not in (None, art_id_1), True) @@ -837,7 +838,7 @@ class OldFormForXTests(TestCase): # Create a new article, with no categories, via the form. f = ArticleForm({'headline': 'The walrus was Paul', 'slug': 'walrus-was-paul', 'pub_date': '1967-11-01', - 'writer': unicode(w_royko.pk), 'article': 'Test.'}) + 'writer': six.text_type(w_royko.pk), 'article': 'Test.'}) new_art = f.save() art_id_3 = new_art.id self.assertEqual(art_id_3 not in (None, art_id_1, art_id_2), True) @@ -847,7 +848,7 @@ class OldFormForXTests(TestCase): # Create a new article, with categories, via the form, but use commit=False. # The m2m data won't be saved until save_m2m() is invoked on the form. f = ArticleForm({'headline': 'The walrus was Paul', 'slug': 'walrus-was-paul', 'pub_date': '1967-11-01', - 'writer': unicode(w_royko.pk), 'article': 'Test.', 'categories': [unicode(c1.id), unicode(c2.id)]}) + 'writer': six.text_type(w_royko.pk), 'article': 'Test.', 'categories': [six.text_type(c1.id), six.text_type(c2.id)]}) new_art = f.save(commit=False) # Manually save the instance @@ -1091,12 +1092,12 @@ class OldFormForXTests(TestCase): <p><label for="id_age">Age:</label> <input type="text" name="age" id="id_age" /></p>''' % (w_woodward.pk, w_bernstein.pk, bw.pk, w_royko.pk)) data = { - 'writer': unicode(w_woodward.pk), + 'writer': six.text_type(w_woodward.pk), 'age': '65', } form = WriterProfileForm(data) instance = form.save() - self.assertEqual(unicode(instance), 'Bob Woodward is 65') + self.assertEqual(six.text_type(instance), 'Bob Woodward is 65') form = WriterProfileForm(instance=instance) self.assertHTMLEqual(form.as_p(), '''<p><label for="id_writer">Writer:</label> <select name="writer" id="id_writer"> @@ -1376,7 +1377,7 @@ class OldFormForXTests(TestCase): # Similar to a regular Form class you can define custom media to be used on # the ModelForm. f = ModelFormWithMedia() - self.assertHTMLEqual(unicode(f.media), '''<link href="/some/form/css" type="text/css" media="all" rel="stylesheet" /> + self.assertHTMLEqual(six.text_type(f.media), '''<link href="/some/form/css" type="text/css" media="all" rel="stylesheet" /> <script type="text/javascript" src="/some/form/javascript"></script>''') f = CommaSeparatedIntegerForm({'field': '1,2,3'}) @@ -1445,7 +1446,7 @@ class OldFormForXTests(TestCase): (22, 'Pear'))) form = InventoryForm(instance=core) - self.assertHTMLEqual(unicode(form['parent']), '''<select name="parent" id="id_parent"> + self.assertHTMLEqual(six.text_type(form['parent']), '''<select name="parent" id="id_parent"> <option value="">---------</option> <option value="86" selected="selected">Apple</option> <option value="87">Core</option> @@ -1466,7 +1467,7 @@ class OldFormForXTests(TestCase): self.assertEqual(CategoryForm.base_fields.keys(), ['description', 'url']) - self.assertHTMLEqual(unicode(CategoryForm()), '''<tr><th><label for="id_description">Description:</label></th><td><input type="text" name="description" id="id_description" /></td></tr> + self.assertHTMLEqual(six.text_type(CategoryForm()), '''<tr><th><label for="id_description">Description:</label></th><td><input type="text" name="description" id="id_description" /></td></tr> <tr><th><label for="id_url">The URL:</label></th><td><input id="id_url" type="text" name="url" maxlength="40" /></td></tr>''') # to_field_name should also work on ModelMultipleChoiceField ################## @@ -1481,5 +1482,5 @@ class OldFormForXTests(TestCase): def test_model_field_that_returns_none_to_exclude_itself_with_explicit_fields(self): self.assertEqual(CustomFieldForExclusionForm.base_fields.keys(), ['name']) - self.assertHTMLEqual(unicode(CustomFieldForExclusionForm()), + self.assertHTMLEqual(six.text_type(CustomFieldForExclusionForm()), '''<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="10" /></td></tr>''') diff --git a/tests/modeltests/model_formsets/models.py b/tests/modeltests/model_formsets/models.py index 055aa8dff1..a01a2da0fa 100644 --- a/tests/modeltests/model_formsets/models.py +++ b/tests/modeltests/model_formsets/models.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals import datetime from django.db import models +from django.utils import six class Author(models.Model): @@ -149,7 +150,7 @@ class Revision(models.Model): unique_together = (("repository", "revision"),) def __unicode__(self): - return "%s (%s)" % (self.revision, unicode(self.repository)) + return "%s (%s)" % (self.revision, six.text_type(self.repository)) # models for testing callable defaults (see bug #7975). If you define a model # with a callable default value, you cannot rely on the initial value in a diff --git a/tests/modeltests/model_formsets/tests.py b/tests/modeltests/model_formsets/tests.py index 309dd3aaa2..e28560b237 100644 --- a/tests/modeltests/model_formsets/tests.py +++ b/tests/modeltests/model_formsets/tests.py @@ -10,6 +10,7 @@ from django.db import models from django.forms.models import (_get_foreign_key, inlineformset_factory, modelformset_factory) from django.test import TestCase, skipUnlessDBFeature +from django.utils import six from .models import (Author, BetterAuthor, Book, BookWithCustomPK, BookWithOptionalAltEditor, AlternateBook, AuthorMeeting, CustomPrimaryKey, @@ -72,7 +73,7 @@ class DeletionTests(TestCase): 'form-TOTAL_FORMS': '1', 'form-INITIAL_FORMS': '1', 'form-MAX_NUM_FORMS': '0', - 'form-0-id': unicode(poet.id), + 'form-0-id': six.text_type(poet.id), 'form-0-name': 'x' * 1000, } formset = PoetFormSet(data, queryset=Poet.objects.all()) @@ -772,7 +773,7 @@ class ModelFormsetTest(TestCase): 'owner_set-TOTAL_FORMS': '3', 'owner_set-INITIAL_FORMS': '1', 'owner_set-MAX_NUM_FORMS': '', - 'owner_set-0-auto_id': unicode(owner1.auto_id), + 'owner_set-0-auto_id': six.text_type(owner1.auto_id), 'owner_set-0-name': 'Joe Perry', 'owner_set-1-auto_id': '', 'owner_set-1-name': 'Jack Berry', @@ -835,7 +836,7 @@ class ModelFormsetTest(TestCase): 'ownerprofile-TOTAL_FORMS': '1', 'ownerprofile-INITIAL_FORMS': '1', 'ownerprofile-MAX_NUM_FORMS': '1', - 'ownerprofile-0-owner': unicode(owner1.auto_id), + 'ownerprofile-0-owner': six.text_type(owner1.auto_id), 'ownerprofile-0-age': '55', } formset = FormSet(data, instance=owner1) @@ -993,8 +994,8 @@ class ModelFormsetTest(TestCase): 'membership_set-TOTAL_FORMS': '1', 'membership_set-INITIAL_FORMS': '0', 'membership_set-MAX_NUM_FORMS': '', - 'membership_set-0-date_joined': unicode(now.strftime('%Y-%m-%d %H:%M:%S')), - 'initial-membership_set-0-date_joined': unicode(now.strftime('%Y-%m-%d %H:%M:%S')), + 'membership_set-0-date_joined': six.text_type(now.strftime('%Y-%m-%d %H:%M:%S')), + 'initial-membership_set-0-date_joined': six.text_type(now.strftime('%Y-%m-%d %H:%M:%S')), 'membership_set-0-karma': '', } formset = FormSet(data, instance=person) @@ -1007,8 +1008,8 @@ class ModelFormsetTest(TestCase): 'membership_set-TOTAL_FORMS': '1', 'membership_set-INITIAL_FORMS': '0', 'membership_set-MAX_NUM_FORMS': '', - 'membership_set-0-date_joined': unicode(one_day_later.strftime('%Y-%m-%d %H:%M:%S')), - 'initial-membership_set-0-date_joined': unicode(now.strftime('%Y-%m-%d %H:%M:%S')), + 'membership_set-0-date_joined': six.text_type(one_day_later.strftime('%Y-%m-%d %H:%M:%S')), + 'initial-membership_set-0-date_joined': six.text_type(now.strftime('%Y-%m-%d %H:%M:%S')), 'membership_set-0-karma': '', } formset = FormSet(filled_data, instance=person) @@ -1029,9 +1030,9 @@ class ModelFormsetTest(TestCase): 'membership_set-TOTAL_FORMS': '1', 'membership_set-INITIAL_FORMS': '0', 'membership_set-MAX_NUM_FORMS': '', - 'membership_set-0-date_joined_0': unicode(now.strftime('%Y-%m-%d')), - 'membership_set-0-date_joined_1': unicode(now.strftime('%H:%M:%S')), - 'initial-membership_set-0-date_joined': unicode(now.strftime('%Y-%m-%d %H:%M:%S')), + 'membership_set-0-date_joined_0': six.text_type(now.strftime('%Y-%m-%d')), + 'membership_set-0-date_joined_1': six.text_type(now.strftime('%H:%M:%S')), + 'initial-membership_set-0-date_joined': six.text_type(now.strftime('%Y-%m-%d %H:%M:%S')), 'membership_set-0-karma': '', } formset = FormSet(data, instance=person) diff --git a/tests/modeltests/model_inheritance/tests.py b/tests/modeltests/model_inheritance/tests.py index 695d3f836c..16d2242fbe 100644 --- a/tests/modeltests/model_inheritance/tests.py +++ b/tests/modeltests/model_inheritance/tests.py @@ -4,6 +4,7 @@ from operator import attrgetter from django.core.exceptions import FieldError from django.test import TestCase +from django.utils import six from .models import (Chef, CommonInfo, ItalianRestaurant, ParkingLot, Place, Post, Restaurant, Student, StudentWorker, Supplier, Worker, MixinModel) @@ -21,8 +22,8 @@ class ModelInheritanceTests(TestCase): s = Student.objects.create(name="Pebbles", age=5, school_class="1B") - self.assertEqual(unicode(w1), "Worker Fred") - self.assertEqual(unicode(s), "Student Pebbles") + self.assertEqual(six.text_type(w1), "Worker Fred") + self.assertEqual(six.text_type(s), "Student Pebbles") # The children inherit the Meta class of their parents (if they don't # specify their own). diff --git a/tests/modeltests/order_with_respect_to/models.py b/tests/modeltests/order_with_respect_to/models.py index 59f01d4cd1..a4e20c2fe0 100644 --- a/tests/modeltests/order_with_respect_to/models.py +++ b/tests/modeltests/order_with_respect_to/models.py @@ -3,6 +3,7 @@ Tests for the order_with_respect_to Meta attribute. """ from django.db import models +from django.utils import six class Question(models.Model): @@ -16,7 +17,7 @@ class Answer(models.Model): order_with_respect_to = 'question' def __unicode__(self): - return unicode(self.text) + return six.text_type(self.text) class Post(models.Model): title = models.CharField(max_length=200) diff --git a/tests/modeltests/pagination/tests.py b/tests/modeltests/pagination/tests.py index 4d5d8680e4..cba8825ec4 100644 --- a/tests/modeltests/pagination/tests.py +++ b/tests/modeltests/pagination/tests.py @@ -4,6 +4,7 @@ from datetime import datetime from django.core.paginator import Paginator, InvalidPage, EmptyPage from django.test import TestCase +from django.utils import six from .models import Article @@ -32,7 +33,7 @@ class PaginationTests(TestCase): def test_first_page(self): paginator = Paginator(Article.objects.all(), 5) p = paginator.page(1) - self.assertEqual("<Page 1 of 2>", unicode(p)) + self.assertEqual("<Page 1 of 2>", six.text_type(p)) self.assertQuerysetEqual(p.object_list, [ "<Article: Article 1>", "<Article: Article 2>", @@ -52,7 +53,7 @@ class PaginationTests(TestCase): def test_last_page(self): paginator = Paginator(Article.objects.all(), 5) p = paginator.page(2) - self.assertEqual("<Page 2 of 2>", unicode(p)) + self.assertEqual("<Page 2 of 2>", six.text_type(p)) self.assertQuerysetEqual(p.object_list, [ "<Article: Article 6>", "<Article: Article 7>", @@ -109,7 +110,7 @@ class PaginationTests(TestCase): self.assertEqual(3, paginator.num_pages) self.assertEqual([1, 2, 3], paginator.page_range) p = paginator.page(2) - self.assertEqual("<Page 2 of 3>", unicode(p)) + self.assertEqual("<Page 2 of 3>", six.text_type(p)) self.assertEqual([4, 5, 6], p.object_list) self.assertTrue(p.has_next()) self.assertTrue(p.has_previous()) diff --git a/tests/modeltests/prefetch_related/tests.py b/tests/modeltests/prefetch_related/tests.py index 43f195d357..8ae0a1e298 100644 --- a/tests/modeltests/prefetch_related/tests.py +++ b/tests/modeltests/prefetch_related/tests.py @@ -4,6 +4,7 @@ from django.contrib.contenttypes.models import ContentType from django.db import connection from django.test import TestCase from django.test.utils import override_settings +from django.utils import six from .models import (Author, Book, Reader, Qualification, Teacher, Department, TaggedItem, Bookmark, AuthorAddress, FavoriteAuthors, AuthorWithAge, @@ -120,7 +121,7 @@ class PrefetchRelatedTests(TestCase): """ with self.assertNumQueries(3): qs = Author.objects.prefetch_related('books__read_by') - lists = [[[unicode(r) for r in b.read_by.all()] + lists = [[[six.text_type(r) for r in b.read_by.all()] for b in a.books.all()] for a in qs] self.assertEqual(lists, @@ -134,7 +135,7 @@ class PrefetchRelatedTests(TestCase): def test_overriding_prefetch(self): with self.assertNumQueries(3): qs = Author.objects.prefetch_related('books', 'books__read_by') - lists = [[[unicode(r) for r in b.read_by.all()] + lists = [[[six.text_type(r) for r in b.read_by.all()] for b in a.books.all()] for a in qs] self.assertEqual(lists, @@ -146,7 +147,7 @@ class PrefetchRelatedTests(TestCase): ]) with self.assertNumQueries(3): qs = Author.objects.prefetch_related('books__read_by', 'books') - lists = [[[unicode(r) for r in b.read_by.all()] + lists = [[[six.text_type(r) for r in b.read_by.all()] for b in a.books.all()] for a in qs] self.assertEqual(lists, @@ -164,7 +165,7 @@ class PrefetchRelatedTests(TestCase): # Need a double with self.assertNumQueries(3): author = Author.objects.prefetch_related('books__read_by').get(name="Charlotte") - lists = [[unicode(r) for r in b.read_by.all()] + lists = [[six.text_type(r) for r in b.read_by.all()] for b in author.books.all()] self.assertEqual(lists, [["Amy"], ["Belinda"]]) # Poems, Jane Eyre @@ -175,7 +176,7 @@ class PrefetchRelatedTests(TestCase): """ with self.assertNumQueries(2): qs = Author.objects.select_related('first_book').prefetch_related('first_book__read_by') - lists = [[unicode(r) for r in a.first_book.read_by.all()] + lists = [[six.text_type(r) for r in a.first_book.read_by.all()] for a in qs] self.assertEqual(lists, [["Amy"], ["Amy"], @@ -227,7 +228,7 @@ class DefaultManagerTests(TestCase): # qualifications, since this will do one query per teacher. qs = Department.objects.prefetch_related('teachers') depts = "".join(["%s department: %s\n" % - (dept.name, ", ".join(unicode(t) for t in dept.teachers.all())) + (dept.name, ", ".join(six.text_type(t) for t in dept.teachers.all())) for dept in qs]) self.assertEqual(depts, @@ -343,9 +344,9 @@ class MultiTableInheritanceTest(TestCase): def test_foreignkey(self): with self.assertNumQueries(2): qs = AuthorWithAge.objects.prefetch_related('addresses') - addresses = [[unicode(address) for address in obj.addresses.all()] + addresses = [[six.text_type(address) for address in obj.addresses.all()] for obj in qs] - self.assertEqual(addresses, [[unicode(self.authorAddress)], [], []]) + self.assertEqual(addresses, [[six.text_type(self.authorAddress)], [], []]) def test_foreignkey_to_inherited(self): with self.assertNumQueries(2): @@ -356,19 +357,19 @@ class MultiTableInheritanceTest(TestCase): def test_m2m_to_inheriting_model(self): qs = AuthorWithAge.objects.prefetch_related('books_with_year') with self.assertNumQueries(2): - lst = [[unicode(book) for book in author.books_with_year.all()] + lst = [[six.text_type(book) for book in author.books_with_year.all()] for author in qs] qs = AuthorWithAge.objects.all() - lst2 = [[unicode(book) for book in author.books_with_year.all()] + lst2 = [[six.text_type(book) for book in author.books_with_year.all()] for author in qs] self.assertEqual(lst, lst2) qs = BookWithYear.objects.prefetch_related('aged_authors') with self.assertNumQueries(2): - lst = [[unicode(author) for author in book.aged_authors.all()] + lst = [[six.text_type(author) for author in book.aged_authors.all()] for book in qs] qs = BookWithYear.objects.all() - lst2 = [[unicode(author) for author in book.aged_authors.all()] + lst2 = [[six.text_type(author) for author in book.aged_authors.all()] for book in qs] self.assertEqual(lst, lst2) @@ -410,23 +411,23 @@ class ForeignKeyToFieldTest(TestCase): def test_foreignkey(self): with self.assertNumQueries(2): qs = Author.objects.prefetch_related('addresses') - addresses = [[unicode(address) for address in obj.addresses.all()] + addresses = [[six.text_type(address) for address in obj.addresses.all()] for obj in qs] - self.assertEqual(addresses, [[unicode(self.authorAddress)], [], []]) + self.assertEqual(addresses, [[six.text_type(self.authorAddress)], [], []]) def test_m2m(self): with self.assertNumQueries(3): qs = Author.objects.all().prefetch_related('favorite_authors', 'favors_me') favorites = [( - [unicode(i_like) for i_like in author.favorite_authors.all()], - [unicode(likes_me) for likes_me in author.favors_me.all()] + [six.text_type(i_like) for i_like in author.favorite_authors.all()], + [six.text_type(likes_me) for likes_me in author.favors_me.all()] ) for author in qs] self.assertEqual( favorites, [ - ([unicode(self.author2)],[unicode(self.author3)]), - ([unicode(self.author3)],[unicode(self.author1)]), - ([unicode(self.author1)],[unicode(self.author2)]) + ([six.text_type(self.author2)],[six.text_type(self.author3)]), + ([six.text_type(self.author3)],[six.text_type(self.author1)]), + ([six.text_type(self.author1)],[six.text_type(self.author2)]) ] ) diff --git a/tests/modeltests/save_delete_hooks/tests.py b/tests/modeltests/save_delete_hooks/tests.py index 377d9eec03..42e0d4a80e 100644 --- a/tests/modeltests/save_delete_hooks/tests.py +++ b/tests/modeltests/save_delete_hooks/tests.py @@ -1,6 +1,7 @@ from __future__ import absolute_import from django.test import TestCase +from django.utils import six from .models import Person @@ -19,7 +20,7 @@ class SaveDeleteHookTests(TestCase): Person.objects.all(), [ "John Smith", ], - unicode + six.text_type ) p.delete() diff --git a/tests/modeltests/select_for_update/tests.py b/tests/modeltests/select_for_update/tests.py index 243f6b50e7..e3e4d9e7e2 100644 --- a/tests/modeltests/select_for_update/tests.py +++ b/tests/modeltests/select_for_update/tests.py @@ -36,6 +36,8 @@ class SelectForUpdateTests(TransactionTestCase): # issuing a SELECT ... FOR UPDATE will block. new_connections = ConnectionHandler(settings.DATABASES) self.new_connection = new_connections[DEFAULT_DB_ALIAS] + self.new_connection.enter_transaction_management() + self.new_connection.managed(True) # We need to set settings.DEBUG to True so we can capture # the output SQL to examine. @@ -48,6 +50,7 @@ class SelectForUpdateTests(TransactionTestCase): # this in the course of their run. transaction.managed(False) transaction.leave_transaction_management() + self.new_connection.leave_transaction_management() except transaction.TransactionManagementError: pass self.new_connection.close() @@ -66,7 +69,7 @@ class SelectForUpdateTests(TransactionTestCase): 'for_update': self.new_connection.ops.for_update_sql(), } self.cursor.execute(sql, ()) - result = self.cursor.fetchone() + self.cursor.fetchone() def end_blocking_transaction(self): # Roll back the blocking transaction. @@ -203,7 +206,7 @@ class SelectForUpdateTests(TransactionTestCase): sanity_count += 1 time.sleep(1) if sanity_count >= 10: - raise ValueError, 'Thread did not run and block' + raise ValueError('Thread did not run and block') # Check the person hasn't been updated. Since this isn't # using FOR UPDATE, it won't block. diff --git a/tests/modeltests/serializers/models.py b/tests/modeltests/serializers/models.py index 3549be1b4f..9da099c027 100644 --- a/tests/modeltests/serializers/models.py +++ b/tests/modeltests/serializers/models.py @@ -10,6 +10,7 @@ from __future__ import unicode_literals from decimal import Decimal from django.db import models +from django.utils import six class Category(models.Model): @@ -100,7 +101,7 @@ class TeamField(models.CharField): super(TeamField, self).__init__(max_length=100) def get_db_prep_save(self, value, connection): - return unicode(value.title) + return six.text_type(value.title) def to_python(self, value): if isinstance(value, Team): diff --git a/tests/modeltests/serializers/tests.py b/tests/modeltests/serializers/tests.py index 13cf1e7e17..9177227539 100644 --- a/tests/modeltests/serializers/tests.py +++ b/tests/modeltests/serializers/tests.py @@ -10,6 +10,7 @@ from django.conf import settings from django.core import serializers from django.db import transaction, connection from django.test import TestCase, TransactionTestCase, Approximate +from django.utils import six from django.utils import unittest from .models import (Category, Author, Article, AuthorProfile, Actor, Movie, @@ -295,7 +296,7 @@ class XmlSerializerTestCase(SerializersTestBase, TestCase): def _comparison_value(value): # The XML serializer handles everything as strings, so comparisons # need to be performed on the stringified value - return unicode(value) + return six.text_type(value) @staticmethod def _validate_output(serial_str): @@ -461,7 +462,7 @@ else: # yaml.safe_load will return non-string objects for some # of the fields we are interested in, this ensures that # everything comes back as a string - if isinstance(field_value, basestring): + if isinstance(field_value, six.string_types): ret_list.append(field_value) else: ret_list.append(str(field_value)) diff --git a/tests/modeltests/signals/tests.py b/tests/modeltests/signals/tests.py index 29563dc363..58f25c2868 100644 --- a/tests/modeltests/signals/tests.py +++ b/tests/modeltests/signals/tests.py @@ -3,6 +3,7 @@ from __future__ import absolute_import from django.db.models import signals from django.dispatch import receiver from django.test import TestCase +from django.utils import six from .models import Person, Car @@ -144,7 +145,7 @@ class SignalTests(TestCase): Person.objects.all(), [ "James Jones", ], - unicode + six.text_type ) signals.post_delete.disconnect(post_delete_test) diff --git a/tests/modeltests/test_client/views.py b/tests/modeltests/test_client/views.py index 6ea7213a02..477a27b178 100644 --- a/tests/modeltests/test_client/views.py +++ b/tests/modeltests/test_client/views.py @@ -1,3 +1,7 @@ +try: + from urllib.parse import urlencode +except ImportError: # Python 2 + from urllib import urlencode from xml.dom.minidom import parseString from django.contrib.auth.decorators import login_required, permission_required @@ -9,7 +13,6 @@ from django.shortcuts import render_to_response from django.template import Context, Template from django.utils.decorators import method_decorator - def get_view(request): "A simple view that expects a GET request, and returns a rendered template" t = Template('This is a test. {{ var }} is the value.', name='GET Template') @@ -58,7 +61,6 @@ def raw_post_view(request): def redirect_view(request): "A view that redirects all requests to the GET view" if request.GET: - from urllib import urlencode query = '?' + urlencode(request.GET, True) else: query = '' diff --git a/tests/modeltests/update/models.py b/tests/modeltests/update/models.py index 92156a5553..b93e4a7aae 100644 --- a/tests/modeltests/update/models.py +++ b/tests/modeltests/update/models.py @@ -4,6 +4,7 @@ updates. """ from django.db import models +from django.utils import six class DataPoint(models.Model): @@ -12,14 +13,14 @@ class DataPoint(models.Model): another_value = models.CharField(max_length=20, blank=True) def __unicode__(self): - return unicode(self.name) + return six.text_type(self.name) class RelatedPoint(models.Model): name = models.CharField(max_length=20) data = models.ForeignKey(DataPoint) def __unicode__(self): - return unicode(self.name) + return six.text_type(self.name) class A(models.Model): diff --git a/tests/modeltests/update_only_fields/tests.py b/tests/modeltests/update_only_fields/tests.py index e843bd7ab9..bce53ca621 100644 --- a/tests/modeltests/update_only_fields/tests.py +++ b/tests/modeltests/update_only_fields/tests.py @@ -55,6 +55,14 @@ class UpdateOnlyFieldsTests(TestCase): self.assertEqual(e3.name, 'Ian') self.assertEqual(e3.profile, profile_receptionist) + with self.assertNumQueries(1): + e3.profile = profile_boss + e3.save(update_fields=['profile_id']) + + e4 = Employee.objects.get(pk=e3.pk) + self.assertEqual(e4.profile, profile_boss) + self.assertEqual(e4.profile_id, profile_boss.pk) + def test_update_fields_inheritance_with_proxy_model(self): profile_boss = Profile.objects.create(name='Boss', salary=3000) profile_receptionist = Profile.objects.create(name='Receptionist', salary=1000) diff --git a/tests/regressiontests/admin_changelist/models.py b/tests/regressiontests/admin_changelist/models.py index dcc343bb6a..487db50689 100644 --- a/tests/regressiontests/admin_changelist/models.py +++ b/tests/regressiontests/admin_changelist/models.py @@ -1,7 +1,8 @@ from django.db import models class Event(models.Model): - date = models.DateField() + # Oracle can have problems with a column named "date" + date = models.DateField(db_column="event_date") class Parent(models.Model): name = models.CharField(max_length=128) diff --git a/tests/regressiontests/admin_changelist/tests.py b/tests/regressiontests/admin_changelist/tests.py index 62166ce174..1ed963aaf2 100644 --- a/tests/regressiontests/admin_changelist/tests.py +++ b/tests/regressiontests/admin_changelist/tests.py @@ -10,6 +10,7 @@ from django.template import Context, Template from django.test import TestCase from django.test.client import RequestFactory from django.utils import formats +from django.utils import six from .admin import (ChildAdmin, QuartetAdmin, BandAdmin, ChordsBandAdmin, GroupAdmin, ParentAdmin, DynamicListDisplayChildAdmin, @@ -339,7 +340,7 @@ class ChangeListTests(TestCase): event = Event.objects.create(date=datetime.date.today()) response = self.client.get('/admin/admin_changelist/event/') self.assertContains(response, formats.localize(event.date)) - self.assertNotContains(response, unicode(event.date)) + self.assertNotContains(response, six.text_type(event.date)) def test_dynamic_list_display(self): """ @@ -443,9 +444,9 @@ class ChangeListTests(TestCase): request = self._mocked_authenticated_request('/swallow/', superuser) response = model_admin.changelist_view(request) # just want to ensure it doesn't blow up during rendering - self.assertContains(response, unicode(swallow.origin)) - self.assertContains(response, unicode(swallow.load)) - self.assertContains(response, unicode(swallow.speed)) + self.assertContains(response, six.text_type(swallow.origin)) + self.assertContains(response, six.text_type(swallow.load)) + self.assertContains(response, six.text_type(swallow.speed)) def test_deterministic_order_for_unordered_model(self): """ diff --git a/tests/regressiontests/admin_scripts/custom_templates/project_template/additional_dir/extra.py b/tests/regressiontests/admin_scripts/custom_templates/project_template/additional_dir/extra.py new file mode 100644 index 0000000000..6b553f190f --- /dev/null +++ b/tests/regressiontests/admin_scripts/custom_templates/project_template/additional_dir/extra.py @@ -0,0 +1 @@ +# this file uses the {{ extra }} variable diff --git a/tests/regressiontests/admin_scripts/management/commands/custom_startproject.py b/tests/regressiontests/admin_scripts/management/commands/custom_startproject.py new file mode 100644 index 0000000000..80c6d6b805 --- /dev/null +++ b/tests/regressiontests/admin_scripts/management/commands/custom_startproject.py @@ -0,0 +1,11 @@ +from optparse import make_option + +from django.core.management.commands.startproject import Command as BaseCommand + + +class Command(BaseCommand): + option_list = BaseCommand.option_list + ( + make_option('--extra', + action='store', dest='extra', + help='An arbitrary extra value passed to the context'), + ) diff --git a/tests/regressiontests/admin_scripts/tests.py b/tests/regressiontests/admin_scripts/tests.py index ecb16df53a..546fa7d79c 100644 --- a/tests/regressiontests/admin_scripts/tests.py +++ b/tests/regressiontests/admin_scripts/tests.py @@ -1541,6 +1541,24 @@ class StartProject(LiveServerTestCase, AdminScriptTestCase): self.assertIn("project_name = 'another_project'", content) self.assertIn("project_directory = '%s'" % testproject_dir, content) + def test_no_escaping_of_project_variables(self): + "Make sure template context variables are not html escaped" + # We're using a custom command so we need the alternate settings + self.write_settings('alternate_settings.py') + template_path = os.path.join(test_dir, 'admin_scripts', 'custom_templates', 'project_template') + args = ['custom_startproject', '--template', template_path, 'another_project', 'project_dir', '--extra', '<&>', '--settings=alternate_settings'] + testproject_dir = os.path.join(test_dir, 'project_dir') + os.mkdir(testproject_dir) + out, err = self.run_manage(args) + self.addCleanup(shutil.rmtree, testproject_dir) + self.assertNoOutput(err) + test_manage_py = os.path.join(testproject_dir, 'additional_dir', 'extra.py') + with open(test_manage_py, 'r') as fp: + content = fp.read() + self.assertIn("<&>", content) + # tidy up alternate settings + self.remove_settings('alternate_settings.py') + def test_custom_project_destination_missing(self): """ Make sure an exception is raised when the provided diff --git a/tests/regressiontests/admin_util/models.py b/tests/regressiontests/admin_util/models.py index 0e81df3817..5541097022 100644 --- a/tests/regressiontests/admin_util/models.py +++ b/tests/regressiontests/admin_util/models.py @@ -1,4 +1,5 @@ from django.db import models +from django.utils import six class Article(models.Model): @@ -22,7 +23,7 @@ class Count(models.Model): parent = models.ForeignKey('self', null=True) def __unicode__(self): - return unicode(self.num) + return six.text_type(self.num) class Event(models.Model): date = models.DateTimeField(auto_now_add=True) diff --git a/tests/regressiontests/admin_util/tests.py b/tests/regressiontests/admin_util/tests.py index ba2be363ca..6b6dad4336 100644 --- a/tests/regressiontests/admin_util/tests.py +++ b/tests/regressiontests/admin_util/tests.py @@ -15,6 +15,7 @@ from django.test import TestCase from django.utils import unittest from django.utils.formats import localize from django.utils.safestring import mark_safe +from django.utils import six from .models import Article, Count, Event, Location @@ -249,17 +250,17 @@ class UtilTests(unittest.TestCase): log_entry.action_flag = admin.models.ADDITION self.assertTrue( - unicode(log_entry).startswith('Added ') + six.text_type(log_entry).startswith('Added ') ) log_entry.action_flag = admin.models.CHANGE self.assertTrue( - unicode(log_entry).startswith('Changed ') + six.text_type(log_entry).startswith('Changed ') ) log_entry.action_flag = admin.models.DELETION self.assertTrue( - unicode(log_entry).startswith('Deleted ') + six.text_type(log_entry).startswith('Deleted ') ) def test_safestring_in_field_label(self): diff --git a/tests/regressiontests/admin_views/admin.py b/tests/regressiontests/admin_views/admin.py index 01a19e6373..6ec933f89b 100644 --- a/tests/regressiontests/admin_views/admin.py +++ b/tests/regressiontests/admin_views/admin.py @@ -27,7 +27,7 @@ from .models import (Article, Chapter, Account, Media, Child, Parent, Picture, Album, Question, Answer, ComplexSortedPerson, PrePopulatedPostLargeSlug, AdminOrderedField, AdminOrderedModelMethod, AdminOrderedAdminMethod, AdminOrderedCallable, Report, Color2, UnorderedObject, MainPrepopulated, - RelatedPrepopulated) + RelatedPrepopulated, UndeletableObject) def callable_year(dt_value): @@ -569,6 +569,11 @@ class UnorderedObjectAdmin(admin.ModelAdmin): list_per_page = 2 +class UndeletableObjectAdmin(admin.ModelAdmin): + def change_view(self, *args, **kwargs): + kwargs['extra_context'] = {'show_delete': False} + return super(UndeletableObjectAdmin, self).change_view(*args, **kwargs) + site = admin.AdminSite(name="admin") site.register(Article, ArticleAdmin) @@ -616,6 +621,7 @@ site.register(OtherStory, OtherStoryAdmin) site.register(Report, ReportAdmin) site.register(MainPrepopulated, MainPrepopulatedAdmin) site.register(UnorderedObject, UnorderedObjectAdmin) +site.register(UndeletableObject, UndeletableObjectAdmin) # We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2. # That way we cover all four cases: diff --git a/tests/regressiontests/admin_views/customadmin.py b/tests/regressiontests/admin_views/customadmin.py index d205e0e290..142527b022 100644 --- a/tests/regressiontests/admin_views/customadmin.py +++ b/tests/regressiontests/admin_views/customadmin.py @@ -48,3 +48,4 @@ site.register(models.Thing, base_admin.ThingAdmin) site.register(models.Fabric, base_admin.FabricAdmin) site.register(models.ChapterXtra1, base_admin.ChapterXtra1Admin) site.register(User, UserLimitedAdmin) +site.register(models.UndeletableObject, base_admin.UndeletableObjectAdmin) diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py index ebb637ac6b..aee193b572 100644 --- a/tests/regressiontests/admin_views/models.py +++ b/tests/regressiontests/admin_views/models.py @@ -101,7 +101,7 @@ class ModelWithStringPrimaryKey(models.Model): return self.string_pk def get_absolute_url(self): - return u'/dummy/%s/' % self.string_pk + return '/dummy/%s/' % self.string_pk class Color(models.Model): @@ -611,3 +611,10 @@ class UnorderedObject(models.Model): """ name = models.CharField(max_length=255) bool = models.BooleanField(default=True) + +class UndeletableObject(models.Model): + """ + Model whose show_delete in admin change_view has been disabled + Refs #10057. + """ + name = models.CharField(max_length=255) diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py index f074d77b11..09be55baba 100644 --- a/tests/regressiontests/admin_views/tests.py +++ b/tests/regressiontests/admin_views/tests.py @@ -4,7 +4,10 @@ from __future__ import absolute_import, unicode_literals import os import re import datetime -import urlparse +try: + from urllib.parse import urljoin +except ImportError: # Python 2 + from urlparse import urljoin from django.conf import settings, global_settings from django.core import mail @@ -30,6 +33,7 @@ from django.utils.cache import get_max_age from django.utils.encoding import iri_to_uri from django.utils.html import escape from django.utils.http import urlencode +from django.utils import six from django.test.utils import override_settings # local test models @@ -41,7 +45,8 @@ from .models import (Article, BarAccount, CustomArticle, EmptyModel, FooAccount, FoodDelivery, RowLevelChangePermissionModel, Paper, CoverLetter, Story, OtherStory, ComplexSortedPerson, Parent, Child, AdminOrderedField, AdminOrderedModelMethod, AdminOrderedAdminMethod, AdminOrderedCallable, - Report, MainPrepopulated, RelatedPrepopulated, UnorderedObject) + Report, MainPrepopulated, RelatedPrepopulated, UnorderedObject, + UndeletableObject) ERROR_MESSAGE = "Please enter the correct username and password \ @@ -588,6 +593,16 @@ class AdminViewBasicTest(TestCase): self.assertFalse(reverse('admin:password_change') in response.content, msg='The "change password" link should not be displayed if a user does not have a usable password.') + def test_change_view_with_show_delete_extra_context(self): + """ + Ensured that the 'show_delete' context variable in the admin's change + view actually controls the display of the delete button. + Refs #10057. + """ + instance = UndeletableObject.objects.create(name='foo') + response = self.client.get('/test_admin/%s/admin_views/undeletableobject/%d/' % + (self.urlbit, instance.pk)) + self.assertNotContains(response, 'deletelink') @override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',)) class AdminViewFormUrlTest(TestCase): @@ -1344,15 +1359,20 @@ class AdminViewStringPrimaryKeyTest(TestCase): def setUp(self): self.client.login(username='super', password='secret') content_type_pk = ContentType.objects.get_for_model(ModelWithStringPrimaryKey).pk - LogEntry.objects.log_action(100, content_type_pk, self.pk, self.pk, 2, change_message='') + LogEntry.objects.log_action(100, content_type_pk, self.pk, self.pk, 2, change_message='Changed something') def tearDown(self): self.client.logout() def test_get_history_view(self): - "Retrieving the history for the object using urlencoded form of primary key should work" + """ + Retrieving the history for an object using urlencoded form of primary + key should work. + Refs #12349, #18550. + """ response = self.client.get('/test_admin/admin/admin_views/modelwithstringprimarykey/%s/history/' % quote(self.pk)) self.assertContains(response, escape(self.pk)) + self.assertContains(response, 'Changed something') self.assertEqual(response.status_code, 200) def test_get_change_view(self): @@ -1364,19 +1384,19 @@ class AdminViewStringPrimaryKeyTest(TestCase): def test_changelist_to_changeform_link(self): "The link from the changelist referring to the changeform of the object should be quoted" response = self.client.get('/test_admin/admin/admin_views/modelwithstringprimarykey/') - should_contain = """<th><a href="%s/">%s</a></th></tr>""" % (quote(self.pk), escape(self.pk)) + should_contain = """<th><a href="%s/">%s</a></th></tr>""" % (escape(quote(self.pk)), escape(self.pk)) self.assertContains(response, should_contain) def test_recentactions_link(self): "The link from the recent actions list referring to the changeform of the object should be quoted" response = self.client.get('/test_admin/admin/') - should_contain = """<a href="admin_views/modelwithstringprimarykey/%s/">%s</a>""" % (quote(self.pk), escape(self.pk)) + should_contain = """<a href="admin_views/modelwithstringprimarykey/%s/">%s</a>""" % (escape(quote(self.pk)), escape(self.pk)) self.assertContains(response, should_contain) def test_recentactions_without_content_type(self): "If a LogEntry is missing content_type it will not display it in span tag under the hyperlink." response = self.client.get('/test_admin/admin/') - should_contain = """<a href="admin_views/modelwithstringprimarykey/%s/">%s</a>""" % (quote(self.pk), escape(self.pk)) + should_contain = """<a href="admin_views/modelwithstringprimarykey/%s/">%s</a>""" % (escape(quote(self.pk)), escape(self.pk)) self.assertContains(response, should_contain) should_contain = "Model with string primary key" # capitalized in Recent Actions self.assertContains(response, should_contain) @@ -1397,7 +1417,7 @@ class AdminViewStringPrimaryKeyTest(TestCase): "The link from the delete confirmation page referring back to the changeform of the object should be quoted" response = self.client.get('/test_admin/admin/admin_views/modelwithstringprimarykey/%s/delete/' % quote(self.pk)) # this URL now comes through reverse(), thus iri_to_uri encoding - should_contain = """/%s/">%s</a>""" % (iri_to_uri(quote(self.pk)), escape(self.pk)) + should_contain = """/%s/">%s</a>""" % (escape(iri_to_uri(quote(self.pk))), escape(self.pk)) self.assertContains(response, should_contain) def test_url_conflicts_with_add(self): @@ -2462,7 +2482,7 @@ class AdminCustomQuerysetTest(TestCase): response = self.client.post('/test_admin/admin/admin_views/paper/%s/' % p.pk, post_data, follow=True) self.assertEqual(response.status_code, 200) - # Message should contain non-ugly model name. Instance representation is set by unicode() (ugly) + # Message should contain non-ugly model name. Instance representation is set by six.text_type() (ugly) self.assertContains(response, '<li class="info">The paper "Paper_Deferred_author object" was changed successfully.</li>', html=True) # defer() is used in ModelAdmin.queryset() @@ -2514,8 +2534,8 @@ class AdminInlineFileUploadTest(TestCase): "pictures-TOTAL_FORMS": "2", "pictures-INITIAL_FORMS": "1", "pictures-MAX_NUM_FORMS": "0", - "pictures-0-id": unicode(self.picture.id), - "pictures-0-gallery": unicode(self.gallery.id), + "pictures-0-id": six.text_type(self.picture.id), + "pictures-0-gallery": six.text_type(self.gallery.id), "pictures-0-name": "Test Picture", "pictures-0-image": "", "pictures-1-id": "", @@ -3182,7 +3202,7 @@ class RawIdFieldsTest(TestCase): popup_url = m.groups()[0].replace("&", "&") # Handle relative links - popup_url = urlparse.urljoin(response.request['PATH_INFO'], popup_url) + popup_url = urljoin(response.request['PATH_INFO'], popup_url) # Get the popup response2 = self.client.get(popup_url) self.assertContains(response2, "Spain") diff --git a/tests/regressiontests/backends/tests.py b/tests/regressiontests/backends/tests.py index c6d28ab135..a6425c5591 100644 --- a/tests/regressiontests/backends/tests.py +++ b/tests/regressiontests/backends/tests.py @@ -16,6 +16,8 @@ from django.db.utils import ConnectionHandler, DatabaseError, load_backend from django.test import (TestCase, skipUnlessDBFeature, skipIfDBFeature, TransactionTestCase) from django.test.utils import override_settings +from django.utils import six +from django.utils.six.moves import xrange from django.utils import unittest from . import models @@ -50,7 +52,7 @@ class OracleChecks(unittest.TestCase): # than 4000 chars and read it properly c = connection.cursor() c.execute('CREATE TABLE ltext ("TEXT" NCLOB)') - long_str = ''.join([unicode(x) for x in xrange(4000)]) + long_str = ''.join([six.text_type(x) for x in xrange(4000)]) c.execute('INSERT INTO ltext VALUES (%s)',[long_str]) c.execute('SELECT text FROM ltext') row = c.fetchone() @@ -66,6 +68,18 @@ class OracleChecks(unittest.TestCase): self.assertEqual(connection.connection.encoding, "UTF-8") self.assertEqual(connection.connection.nencoding, "UTF-8") + @unittest.skipUnless(connection.vendor == 'oracle', + "No need to check Oracle connection semantics") + def test_order_of_nls_parameters(self): + # an 'almost right' datetime should work with configured + # NLS parameters as per #18465. + c = connection.cursor() + query = "select 1 from dual where '1936-12-29 00:00' < sysdate" + # Test that the query succeeds without errors - pre #18465 this + # wasn't the case. + c.execute(query) + self.assertEqual(c.fetchone()[0], 1) + class MySQLTests(TestCase): @unittest.skipUnless(connection.vendor == 'mysql', "Test valid only for MySQL") @@ -142,7 +156,7 @@ class LastExecutedQueryTest(TestCase): sql, params = tags.query.sql_with_params() cursor = tags.query.get_compiler('default').execute_sql(None) last_sql = cursor.db.ops.last_executed_query(cursor, sql, params) - self.assertTrue(isinstance(last_sql, unicode)) + self.assertTrue(isinstance(last_sql, six.text_type)) class ParameterHandlingTest(TestCase): @@ -518,7 +532,7 @@ class ThreadTests(TestCase): from django.db import connection connection.cursor() connections_set.add(connection.connection) - for x in xrange(2): + for x in range(2): t = threading.Thread(target=runner) t.start() t.join() @@ -545,7 +559,7 @@ class ThreadTests(TestCase): # main thread. conn.allow_thread_sharing = True connections_set.add(conn) - for x in xrange(2): + for x in range(2): t = threading.Thread(target=runner) t.start() t.join() diff --git a/tests/regressiontests/bulk_create/models.py b/tests/regressiontests/bulk_create/models.py index a4c611d537..bc685bbbe4 100644 --- a/tests/regressiontests/bulk_create/models.py +++ b/tests/regressiontests/bulk_create/models.py @@ -18,4 +18,8 @@ class Pizzeria(Restaurant): pass class State(models.Model): - two_letter_code = models.CharField(max_length=2, primary_key=True)
\ No newline at end of file + two_letter_code = models.CharField(max_length=2, primary_key=True) + +class TwoFields(models.Model): + f1 = models.IntegerField(unique=True) + f2 = models.IntegerField(unique=True) diff --git a/tests/regressiontests/bulk_create/tests.py b/tests/regressiontests/bulk_create/tests.py index 0b55f637a4..33108ea9b0 100644 --- a/tests/regressiontests/bulk_create/tests.py +++ b/tests/regressiontests/bulk_create/tests.py @@ -2,9 +2,11 @@ from __future__ import absolute_import from operator import attrgetter -from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature +from django.db import connection +from django.test import TestCase, skipIfDBFeature +from django.test.utils import override_settings -from .models import Country, Restaurant, Pizzeria, State +from .models import Country, Restaurant, Pizzeria, State, TwoFields class BulkCreateTests(TestCase): @@ -27,7 +29,6 @@ class BulkCreateTests(TestCase): self.assertEqual(created, []) self.assertEqual(Country.objects.count(), 4) - @skipUnlessDBFeature("has_bulk_insert") def test_efficiency(self): with self.assertNumQueries(1): Country.objects.bulk_create(self.data) @@ -69,3 +70,42 @@ class BulkCreateTests(TestCase): invalid_country = Country(id=0, name='Poland', iso_two_letter='PL') with self.assertRaises(ValueError): Country.objects.bulk_create([valid_country, invalid_country]) + + def test_large_batch(self): + with override_settings(DEBUG=True): + connection.queries = [] + TwoFields.objects.bulk_create([ + TwoFields(f1=i, f2=i+1) for i in range(0, 1001) + ]) + self.assertTrue(len(connection.queries) < 10) + self.assertEqual(TwoFields.objects.count(), 1001) + self.assertEqual( + TwoFields.objects.filter(f1__gte=450, f1__lte=550).count(), + 101) + self.assertEqual(TwoFields.objects.filter(f2__gte=901).count(), 101) + + def test_large_batch_mixed(self): + """ + Test inserting a large batch with objects having primary key set + mixed together with objects without PK set. + """ + with override_settings(DEBUG=True): + connection.queries = [] + TwoFields.objects.bulk_create([ + TwoFields(id=i if i % 2 == 0 else None, f1=i, f2=i+1) + for i in range(100000, 101000)]) + self.assertTrue(len(connection.queries) < 10) + self.assertEqual(TwoFields.objects.count(), 1000) + # We can't assume much about the ID's created, except that the above + # created IDs must exist. + id_range = range(100000, 101000, 2) + self.assertEqual(TwoFields.objects.filter(id__in=id_range).count(), 500) + self.assertEqual(TwoFields.objects.exclude(id__in=id_range).count(), 500) + + def test_explicit_batch_size(self): + objs = [TwoFields(f1=i, f2=i) for i in range(0, 100)] + with self.assertNumQueries(2): + TwoFields.objects.bulk_create(objs, 50) + TwoFields.objects.all().delete() + with self.assertNumQueries(1): + TwoFields.objects.bulk_create(objs, len(objs)) diff --git a/tests/regressiontests/conditional_processing/models.py b/tests/regressiontests/conditional_processing/models.py index 97aeff5eaa..d1a8ac605b 100644 --- a/tests/regressiontests/conditional_processing/models.py +++ b/tests/regressiontests/conditional_processing/models.py @@ -143,14 +143,14 @@ class HttpDateProcessing(unittest.TestCase): def testParsingRfc1123(self): parsed = parse_http_date('Sun, 06 Nov 1994 08:49:37 GMT') self.assertEqual(datetime.utcfromtimestamp(parsed), - datetime(1994, 11, 06, 8, 49, 37)) + datetime(1994, 11, 6, 8, 49, 37)) def testParsingRfc850(self): parsed = parse_http_date('Sunday, 06-Nov-94 08:49:37 GMT') self.assertEqual(datetime.utcfromtimestamp(parsed), - datetime(1994, 11, 06, 8, 49, 37)) + datetime(1994, 11, 6, 8, 49, 37)) def testParsingAsctime(self): parsed = parse_http_date('Sun Nov 6 08:49:37 1994') self.assertEqual(datetime.utcfromtimestamp(parsed), - datetime(1994, 11, 06, 8, 49, 37)) + datetime(1994, 11, 6, 8, 49, 37)) diff --git a/tests/regressiontests/datatypes/tests.py b/tests/regressiontests/datatypes/tests.py index f8f6802041..f0ec5f3c0a 100644 --- a/tests/regressiontests/datatypes/tests.py +++ b/tests/regressiontests/datatypes/tests.py @@ -3,6 +3,7 @@ from __future__ import absolute_import, unicode_literals import datetime from django.test import TestCase, skipIfDBFeature +from django.utils import six from django.utils.timezone import utc from .models import Donut, RumBaba @@ -73,7 +74,7 @@ class DataTypesTestCase(TestCase): database should be unicode.""" d = Donut.objects.create(name='Jelly Donut', review='Outstanding') newd = Donut.objects.get(id=d.id) - self.assertTrue(isinstance(newd.review, unicode)) + self.assertTrue(isinstance(newd.review, six.text_type)) @skipIfDBFeature('supports_timezones') def test_error_on_timezone(self): diff --git a/tests/regressiontests/defaultfilters/tests.py b/tests/regressiontests/defaultfilters/tests.py index ffa0a01132..2852572d32 100644 --- a/tests/regressiontests/defaultfilters/tests.py +++ b/tests/regressiontests/defaultfilters/tests.py @@ -6,6 +6,7 @@ import decimal from django.template.defaultfilters import * from django.test import TestCase +from django.utils import six from django.utils import unittest, translation from django.utils.safestring import SafeData @@ -48,13 +49,13 @@ class DefaultFiltersTests(TestCase): '0.00000000000000000002') pos_inf = float(1e30000) - self.assertEqual(floatformat(pos_inf), unicode(pos_inf)) + self.assertEqual(floatformat(pos_inf), six.text_type(pos_inf)) neg_inf = float(-1e30000) - self.assertEqual(floatformat(neg_inf), unicode(neg_inf)) + self.assertEqual(floatformat(neg_inf), six.text_type(neg_inf)) nan = pos_inf / pos_inf - self.assertEqual(floatformat(nan), unicode(nan)) + self.assertEqual(floatformat(nan), six.text_type(nan)) class FloatWrapper(object): def __init__(self, value): @@ -297,6 +298,10 @@ class DefaultFiltersTests(TestCase): self.assertEqual(urlize('HTTPS://github.com/'), '<a href="https://github.com/" rel="nofollow">HTTPS://github.com/</a>') + # Check urlize trims trailing period when followed by parenthesis - see #18644 + self.assertEqual(urlize('(Go to http://www.example.com/foo.)'), + '(Go to <a href="http://www.example.com/foo" rel="nofollow">http://www.example.com/foo</a>.)') + def test_wordcount(self): self.assertEqual(wordcount(''), 0) self.assertEqual(wordcount('oneword'), 1) diff --git a/tests/regressiontests/defer_regress/models.py b/tests/regressiontests/defer_regress/models.py index 812d2da206..bd4f845f27 100644 --- a/tests/regressiontests/defer_regress/models.py +++ b/tests/regressiontests/defer_regress/models.py @@ -47,3 +47,7 @@ class SimpleItem(models.Model): class Feature(models.Model): item = models.ForeignKey(SimpleItem) + +class ItemAndSimpleItem(models.Model): + item = models.ForeignKey(Item) + simple = models.ForeignKey(SimpleItem) diff --git a/tests/regressiontests/defer_regress/tests.py b/tests/regressiontests/defer_regress/tests.py index 1f07d4c9a8..53bb59f5b3 100644 --- a/tests/regressiontests/defer_regress/tests.py +++ b/tests/regressiontests/defer_regress/tests.py @@ -9,7 +9,7 @@ from django.db.models.loading import cache from django.test import TestCase from .models import (ResolveThis, Item, RelatedItem, Child, Leaf, Proxy, - SimpleItem, Feature) + SimpleItem, Feature, ItemAndSimpleItem) class DeferRegressionTest(TestCase): @@ -109,6 +109,7 @@ class DeferRegressionTest(TestCase): Child, Feature, Item, + ItemAndSimpleItem, Leaf, Proxy, RelatedItem, @@ -125,12 +126,16 @@ class DeferRegressionTest(TestCase): ), ) ) + # FIXME: This is dependent on the order in which tests are run -- + # this test case has to be the first, otherwise a LOT more classes + # appear. self.assertEqual( klasses, [ "Child", "Child_Deferred_value", "Feature", "Item", + "ItemAndSimpleItem", "Item_Deferred_name", "Item_Deferred_name_other_value_text", "Item_Deferred_name_other_value_value", @@ -139,7 +144,7 @@ class DeferRegressionTest(TestCase): "Leaf", "Leaf_Deferred_child_id_second_child_id_value", "Leaf_Deferred_name_value", - "Leaf_Deferred_second_child_value", + "Leaf_Deferred_second_child_id_value", "Leaf_Deferred_value", "Proxy", "RelatedItem", @@ -175,6 +180,23 @@ class DeferRegressionTest(TestCase): self.assertEqual(1, qs.count()) self.assertEqual('Foobar', qs[0].name) + def test_defer_with_select_related(self): + item1 = Item.objects.create(name="first", value=47) + item2 = Item.objects.create(name="second", value=42) + simple = SimpleItem.objects.create(name="simple", value="23") + related = ItemAndSimpleItem.objects.create(item=item1, simple=simple) + + obj = ItemAndSimpleItem.objects.defer('item').select_related('simple').get() + self.assertEqual(obj.item, item1) + self.assertEqual(obj.item_id, item1.id) + + obj.item = item2 + obj.save() + + obj = ItemAndSimpleItem.objects.defer('item').select_related('simple').get() + self.assertEqual(obj.item, item2) + self.assertEqual(obj.item_id, item2.id) + def test_deferred_class_factory(self): from django.db.models.query_utils import deferred_class_factory new_class = deferred_class_factory(Item, diff --git a/tests/regressiontests/dispatch/tests/__init__.py b/tests/regressiontests/dispatch/tests/__init__.py index 447975ab85..b6d26217e1 100644 --- a/tests/regressiontests/dispatch/tests/__init__.py +++ b/tests/regressiontests/dispatch/tests/__init__.py @@ -4,5 +4,5 @@ Unit-tests for the dispatch project from __future__ import absolute_import -from .test_dispatcher import DispatcherTests +from .test_dispatcher import DispatcherTests, ReceiverTestCase from .test_saferef import SaferefTests diff --git a/tests/regressiontests/dispatch/tests/test_dispatcher.py b/tests/regressiontests/dispatch/tests/test_dispatcher.py index 319d6553a0..5f7094d5fa 100644 --- a/tests/regressiontests/dispatch/tests/test_dispatcher.py +++ b/tests/regressiontests/dispatch/tests/test_dispatcher.py @@ -2,7 +2,7 @@ import gc import sys import time -from django.dispatch import Signal +from django.dispatch import Signal, receiver from django.utils import unittest @@ -33,6 +33,8 @@ class Callable(object): return val a_signal = Signal(providing_args=["val"]) +b_signal = Signal(providing_args=["val"]) +c_signal = Signal(providing_args=["val"]) class DispatcherTests(unittest.TestCase): """Test suite for dispatcher (barely started)""" @@ -123,3 +125,29 @@ class DispatcherTests(unittest.TestCase): garbage_collect() a_signal.disconnect(receiver_3) self._testIsClean(a_signal) + + +class ReceiverTestCase(unittest.TestCase): + """ + Test suite for receiver. + + """ + def testReceiverSingleSignal(self): + @receiver(a_signal) + def f(val, **kwargs): + self.state = val + self.state = False + a_signal.send(sender=self, val=True) + self.assertTrue(self.state) + + def testReceiverSignalList(self): + @receiver([a_signal, b_signal, c_signal]) + def f(val, **kwargs): + self.state.append(val) + self.state = [] + a_signal.send(sender=self, val='a') + c_signal.send(sender=self, val='c') + b_signal.send(sender=self, val='b') + self.assertIn('a', self.state) + self.assertIn('b', self.state) + self.assertIn('c', self.state) diff --git a/tests/regressiontests/dispatch/tests/test_saferef.py b/tests/regressiontests/dispatch/tests/test_saferef.py index 99251c5127..cfe6c5df85 100644 --- a/tests/regressiontests/dispatch/tests/test_saferef.py +++ b/tests/regressiontests/dispatch/tests/test_saferef.py @@ -1,7 +1,7 @@ from django.dispatch.saferef import safeRef +from django.utils.six.moves import xrange from django.utils import unittest - class Test1(object): def x(self): pass @@ -70,4 +70,4 @@ class SaferefTests(unittest.TestCase): def _closure(self, ref): """Dumb utility mechanism to increment deletion counter""" - self.closureCount +=1
\ No newline at end of file + self.closureCount +=1 diff --git a/tests/regressiontests/file_storage/tests.py b/tests/regressiontests/file_storage/tests.py index 51b2207867..31e33d915c 100644 --- a/tests/regressiontests/file_storage/tests.py +++ b/tests/regressiontests/file_storage/tests.py @@ -424,7 +424,7 @@ class FileSaveRaceConditionTest(unittest.TestCase): class FileStoragePermissions(unittest.TestCase): def setUp(self): self.old_perms = settings.FILE_UPLOAD_PERMISSIONS - settings.FILE_UPLOAD_PERMISSIONS = 0666 + settings.FILE_UPLOAD_PERMISSIONS = 0o666 self.storage_dir = tempfile.mkdtemp() self.storage = FileSystemStorage(self.storage_dir) @@ -434,8 +434,8 @@ class FileStoragePermissions(unittest.TestCase): def test_file_upload_permissions(self): name = self.storage.save("the_file", ContentFile(b"data")) - actual_mode = os.stat(self.storage.path(name))[0] & 0777 - self.assertEqual(actual_mode, 0666) + actual_mode = os.stat(self.storage.path(name))[0] & 0o777 + self.assertEqual(actual_mode, 0o666) class FileStoragePathParsing(unittest.TestCase): diff --git a/tests/regressiontests/file_uploads/tests.py b/tests/regressiontests/file_uploads/tests.py index a7424639b4..9fe3ca15a7 100644 --- a/tests/regressiontests/file_uploads/tests.py +++ b/tests/regressiontests/file_uploads/tests.py @@ -362,16 +362,16 @@ class DirectoryCreationTests(unittest.TestCase): if not os.path.isdir(temp_storage.location): os.makedirs(temp_storage.location) if os.path.isdir(UPLOAD_TO): - os.chmod(UPLOAD_TO, 0700) + os.chmod(UPLOAD_TO, 0o700) shutil.rmtree(UPLOAD_TO) def tearDown(self): - os.chmod(temp_storage.location, 0700) + os.chmod(temp_storage.location, 0o700) shutil.rmtree(temp_storage.location) def test_readonly_root(self): """Permission errors are not swallowed""" - os.chmod(temp_storage.location, 0500) + os.chmod(temp_storage.location, 0o500) try: self.obj.testfile.save('foo.txt', SimpleUploadedFile('foo.txt', b'x')) except OSError as err: diff --git a/tests/regressiontests/file_uploads/views.py b/tests/regressiontests/file_uploads/views.py index 73b09cbcff..c5d2720e1a 100644 --- a/tests/regressiontests/file_uploads/views.py +++ b/tests/regressiontests/file_uploads/views.py @@ -6,6 +6,7 @@ import os from django.core.files.uploadedfile import UploadedFile from django.http import HttpResponse, HttpResponseServerError +from django.utils import six from .models import FileModel, UPLOAD_TO from .tests import UNICODE_FILENAME @@ -19,7 +20,7 @@ def file_upload_view(request): """ form_data = request.POST.copy() form_data.update(request.FILES) - if isinstance(form_data.get('file_field'), UploadedFile) and isinstance(form_data['name'], unicode): + if isinstance(form_data.get('file_field'), UploadedFile) and isinstance(form_data['name'], six.text_type): # If a file is posted, the dummy client should only post the file name, # not the full path. if os.path.dirname(form_data['file_field'].name) != '': diff --git a/tests/regressiontests/fixtures_regress/fixtures/forward_ref_lookup.json b/tests/regressiontests/fixtures_regress/fixtures/forward_ref_lookup.json index fe50c653cc..42e8ec0877 100644 --- a/tests/regressiontests/fixtures_regress/fixtures/forward_ref_lookup.json +++ b/tests/regressiontests/fixtures_regress/fixtures/forward_ref_lookup.json @@ -10,6 +10,7 @@ "pk": "2", "model": "fixtures_regress.store", "fields": { + "main": null, "name": "Amazon" } }, @@ -17,6 +18,7 @@ "pk": "3", "model": "fixtures_regress.store", "fields": { + "main": null, "name": "Borders" } }, @@ -29,4 +31,4 @@ "stores": [["Amazon"], ["Borders"]] } } -]
\ No newline at end of file +] diff --git a/tests/regressiontests/fixtures_regress/models.py b/tests/regressiontests/fixtures_regress/models.py index 5d23a21dcd..7151cb0ed9 100644 --- a/tests/regressiontests/fixtures_regress/models.py +++ b/tests/regressiontests/fixtures_regress/models.py @@ -2,6 +2,7 @@ from __future__ import absolute_import, unicode_literals from django.contrib.auth.models import User from django.db import models +from django.utils import six class Animal(models.Model): @@ -29,7 +30,7 @@ class Stuff(models.Model): owner = models.ForeignKey(User, null=True) def __unicode__(self): - return unicode(self.name) + ' is owned by ' + unicode(self.owner) + return six.text_type(self.name) + ' is owned by ' + six.text_type(self.owner) class Absolute(models.Model): @@ -91,6 +92,7 @@ class TestManager(models.Manager): class Store(models.Model): objects = TestManager() name = models.CharField(max_length=255) + main = models.ForeignKey('self', null=True) class Meta: ordering = ('name',) diff --git a/tests/regressiontests/fixtures_regress/tests.py b/tests/regressiontests/fixtures_regress/tests.py index 405c566826..ab93341699 100644 --- a/tests/regressiontests/fixtures_regress/tests.py +++ b/tests/regressiontests/fixtures_regress/tests.py @@ -478,7 +478,7 @@ class NaturalKeyFixtureTests(TestCase): ) self.assertEqual( stdout.getvalue(), - """[{"pk": 2, "model": "fixtures_regress.store", "fields": {"name": "Amazon"}}, {"pk": 3, "model": "fixtures_regress.store", "fields": {"name": "Borders"}}, {"pk": 4, "model": "fixtures_regress.person", "fields": {"name": "Neal Stephenson"}}, {"pk": 1, "model": "fixtures_regress.book", "fields": {"stores": [["Amazon"], ["Borders"]], "name": "Cryptonomicon", "author": ["Neal Stephenson"]}}]""" + """[{"pk": 2, "model": "fixtures_regress.store", "fields": {"main": null, "name": "Amazon"}}, {"pk": 3, "model": "fixtures_regress.store", "fields": {"main": null, "name": "Borders"}}, {"pk": 4, "model": "fixtures_regress.person", "fields": {"name": "Neal Stephenson"}}, {"pk": 1, "model": "fixtures_regress.book", "fields": {"stores": [["Amazon"], ["Borders"]], "name": "Cryptonomicon", "author": ["Neal Stephenson"]}}]""" ) def test_dependency_sorting(self): diff --git a/tests/regressiontests/forms/tests/extra.py b/tests/regressiontests/forms/tests/extra.py index 25b21123c4..28b6c12453 100644 --- a/tests/regressiontests/forms/tests/extra.py +++ b/tests/regressiontests/forms/tests/extra.py @@ -554,7 +554,7 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin): def test_smart_unicode(self): class Test: def __str__(self): - return b'ŠĐĆŽćžšđ' + return 'ŠĐĆŽćžšđ'.encode('utf-8') class TestU: def __str__(self): diff --git a/tests/regressiontests/forms/tests/fields.py b/tests/regressiontests/forms/tests/fields.py index ebeb19c8fc..feb2ade458 100644 --- a/tests/regressiontests/forms/tests/fields.py +++ b/tests/regressiontests/forms/tests/fields.py @@ -35,10 +35,11 @@ from decimal import Decimal from django.core.files.uploadedfile import SimpleUploadedFile from django.forms import * from django.test import SimpleTestCase +from django.utils import six def fix_os_paths(x): - if isinstance(x, basestring): + if isinstance(x, six.string_types): return x.replace('\\', '/') elif isinstance(x, tuple): return tuple(fix_os_paths(list(x))) @@ -486,7 +487,7 @@ class FieldsTests(SimpleTestCase): Refs #. """ f = RegexField('^\w+$') - self.assertEqual(u'éèøçÎÎ你好', f.clean(u'éèøçÎÎ你好')) + self.assertEqual('éèøçÎÎ你好', f.clean('éèøçÎÎ你好')) def test_change_regex_after_init(self): f = RegexField('^[a-z]+$') diff --git a/tests/regressiontests/forms/tests/models.py b/tests/regressiontests/forms/tests/models.py index 5bea49b840..7687335b48 100644 --- a/tests/regressiontests/forms/tests/models.py +++ b/tests/regressiontests/forms/tests/models.py @@ -8,6 +8,7 @@ from django.db import models from django.forms import Form, ModelForm, FileField, ModelChoiceField from django.forms.models import ModelFormMetaclass from django.test import TestCase +from django.utils import six from ..models import (ChoiceOptionModel, ChoiceFieldModel, FileModel, Group, BoundaryModel, Defaults) @@ -40,7 +41,7 @@ class ModelFormCallableModelDefault(TestCase): choices = list(ChoiceFieldForm().fields['choice'].choices) self.assertEqual(len(choices), 1) - self.assertEqual(choices[0], (option.pk, unicode(option))) + self.assertEqual(choices[0], (option.pk, six.text_type(option))) def test_callable_initial_value(self): "The initial value for a callable default returning a queryset is the pk (refs #13769)" diff --git a/tests/regressiontests/forms/tests/util.py b/tests/regressiontests/forms/tests/util.py index 280049c97b..b7cc4ec809 100644 --- a/tests/regressiontests/forms/tests/util.py +++ b/tests/regressiontests/forms/tests/util.py @@ -5,6 +5,7 @@ from django.core.exceptions import ValidationError from django.forms.util import flatatt, ErrorDict, ErrorList from django.test import TestCase from django.utils.safestring import mark_safe +from django.utils import six from django.utils.translation import ugettext_lazy @@ -30,7 +31,7 @@ class FormsUtilTestCase(TestCase): '<ul class="errorlist"><li>There was an error.</li></ul>') # Can take a unicode string. - self.assertHTMLEqual(unicode(ErrorList(ValidationError("Not \u03C0.").messages)), + self.assertHTMLEqual(six.text_type(ErrorList(ValidationError("Not \u03C0.").messages)), '<ul class="errorlist"><li>Not π.</li></ul>') # Can take a lazy string. diff --git a/tests/regressiontests/forms/tests/widgets.py b/tests/regressiontests/forms/tests/widgets.py index d5f6334fe9..3ea42cf549 100644 --- a/tests/regressiontests/forms/tests/widgets.py +++ b/tests/regressiontests/forms/tests/widgets.py @@ -10,6 +10,7 @@ from django.forms import * from django.forms.widgets import RadioFieldRenderer from django.utils import formats from django.utils.safestring import mark_safe +from django.utils import six from django.utils.translation import activate, deactivate from django.test import TestCase @@ -676,7 +677,7 @@ beatle J R Ringo False""") # You can create your own custom renderers for RadioSelect to use. class MyRenderer(RadioFieldRenderer): def render(self): - return '<br />\n'.join([unicode(choice) for choice in self]) + return '<br />\n'.join([six.text_type(choice) for choice in self]) w = RadioSelect(renderer=MyRenderer) self.assertHTMLEqual(w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<label><input type="radio" name="beatle" value="J" /> John</label><br /> <label><input type="radio" name="beatle" value="P" /> Paul</label><br /> @@ -716,7 +717,7 @@ beatle J R Ringo False""") # Unicode choices are correctly rendered as HTML w = RadioSelect() - self.assertHTMLEqual(unicode(w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])), '<ul>\n<li><label><input checked="checked" type="radio" name="email" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /> \u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</label></li>\n<li><label><input type="radio" name="email" value="\u0107\u017e\u0161\u0111" /> abc\u0107\u017e\u0161\u0111</label></li>\n</ul>') + self.assertHTMLEqual(six.text_type(w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])), '<ul>\n<li><label><input checked="checked" type="radio" name="email" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /> \u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</label></li>\n<li><label><input type="radio" name="email" value="\u0107\u017e\u0161\u0111" /> abc\u0107\u017e\u0161\u0111</label></li>\n</ul>') # Attributes provided at instantiation are passed to the constituent inputs w = RadioSelect(attrs={'id':'foo'}) @@ -1135,7 +1136,7 @@ class ClearableFileInputTests(TestCase): output = widget.render('my<div>file', field) self.assertFalse(field.url in output) self.assertTrue('href="something?chapter=1&sect=2&copy=3&lang=en"' in output) - self.assertFalse(unicode(field) in output) + self.assertFalse(six.text_type(field) in output) self.assertTrue('something<div onclick="alert('oops')">.jpg' in output) self.assertTrue('my<div>file' in output) self.assertFalse('my<div>file' in output) diff --git a/tests/regressiontests/httpwrappers/tests.py b/tests/regressiontests/httpwrappers/tests.py index 870324bffb..9b599db6d0 100644 --- a/tests/regressiontests/httpwrappers/tests.py +++ b/tests/regressiontests/httpwrappers/tests.py @@ -1,3 +1,4 @@ +# -*- encoding: utf-8 -*- from __future__ import unicode_literals import copy @@ -189,7 +190,7 @@ class QueryDictTests(unittest.TestCase): self.assertEqual(q == q1, True) q = QueryDict('a=b&c=d&a=1') q1 = pickle.loads(pickle.dumps(q, 2)) - self.assertEqual(q == q1 , True) + self.assertEqual(q == q1, True) def test_update_from_querydict(self): """Regression test for #8278: QueryDict.update(QueryDict)""" @@ -298,6 +299,17 @@ class HttpResponseTests(unittest.TestCase): self.assertRaises(UnicodeEncodeError, getattr, r, 'content') + def test_file_interface(self): + r = HttpResponse() + r.write(b"hello") + self.assertEqual(r.tell(), 5) + r.write("привет") + self.assertEqual(r.tell(), 17) + + r = HttpResponse(['abc']) + self.assertRaises(Exception, r.write, 'def') + + class CookieTests(unittest.TestCase): def test_encode(self): """ diff --git a/tests/regressiontests/i18n/commands/code.sample b/tests/regressiontests/i18n/commands/code.sample new file mode 100644 index 0000000000..bbcb83164b --- /dev/null +++ b/tests/regressiontests/i18n/commands/code.sample @@ -0,0 +1,4 @@ +from django.utils.translation import ugettext + +# This will generate an xgettext warning +my_string = ugettext("This string contain two placeholders: %s and %s" % ('a', 'b')) diff --git a/tests/regressiontests/i18n/commands/extraction.py b/tests/regressiontests/i18n/commands/extraction.py index fb9ca4ed08..cd6d50893a 100644 --- a/tests/regressiontests/i18n/commands/extraction.py +++ b/tests/regressiontests/i18n/commands/extraction.py @@ -117,6 +117,14 @@ class BasicExtractorTests(ExtractorTests): # Check that the temporary file was cleaned up self.assertFalse(os.path.exists('./templates/template_with_error.html.py')) + def test_extraction_warning(self): + os.chdir(self.test_dir) + shutil.copyfile('./code.sample', './code_sample.py') + stdout = StringIO() + management.call_command('makemessages', locale=LOCALE, stdout=stdout) + os.remove('./code_sample.py') + self.assertIn("code_sample.py:4", stdout.getvalue()) + def test_template_message_context_extractor(self): """ Ensure that message contexts are correctly extracted for the diff --git a/tests/regressiontests/i18n/commands/tests.py b/tests/regressiontests/i18n/commands/tests.py index 38e8af1d0d..e00ef72d59 100644 --- a/tests/regressiontests/i18n/commands/tests.py +++ b/tests/regressiontests/i18n/commands/tests.py @@ -2,13 +2,15 @@ import os import re from subprocess import Popen, PIPE +from django.utils import six + can_run_extraction_tests = False can_run_compilation_tests = False def find_command(cmd, path=None, pathext=None): if path is None: path = os.environ.get('PATH', []).split(os.pathsep) - if isinstance(path, basestring): + if isinstance(path, six.string_types): path = [path] # check if there are funny path extensions for executables, e.g. Windows if pathext is None: diff --git a/tests/regressiontests/i18n/contenttypes/tests.py b/tests/regressiontests/i18n/contenttypes/tests.py index bed94da8b8..178232f543 100644 --- a/tests/regressiontests/i18n/contenttypes/tests.py +++ b/tests/regressiontests/i18n/contenttypes/tests.py @@ -6,6 +6,7 @@ import os from django.contrib.contenttypes.models import ContentType from django.test import TestCase from django.test.utils import override_settings +from django.utils import six from django.utils import translation @@ -24,11 +25,11 @@ class ContentTypeTests(TestCase): def test_verbose_name(self): company_type = ContentType.objects.get(app_label='i18n', model='company') with translation.override('en'): - self.assertEqual(unicode(company_type), 'Company') + self.assertEqual(six.text_type(company_type), 'Company') with translation.override('fr'): - self.assertEqual(unicode(company_type), 'Société') + self.assertEqual(six.text_type(company_type), 'Société') def test_field_override(self): company_type = ContentType.objects.get(app_label='i18n', model='company') company_type.name = 'Other' - self.assertEqual(unicode(company_type), 'Other') + self.assertEqual(six.text_type(company_type), 'Other') diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py index f91d7c042b..9ca66bdb9b 100644 --- a/tests/regressiontests/i18n/tests.py +++ b/tests/regressiontests/i18n/tests.py @@ -19,6 +19,8 @@ from django.utils.formats import (get_format, date_format, time_format, from django.utils.importlib import import_module from django.utils.numberformat import format as nformat from django.utils.safestring import mark_safe, SafeString, SafeUnicode +from django.utils import six +from django.utils.six import PY3 from django.utils.translation import (ugettext, ugettext_lazy, activate, deactivate, gettext_lazy, pgettext, npgettext, to_locale, get_language_info, get_language, get_language_from_request) @@ -80,9 +82,9 @@ class TranslationTests(TestCase): def test_lazy_pickle(self): s1 = ugettext_lazy("test") - self.assertEqual(unicode(s1), "test") + self.assertEqual(six.text_type(s1), "test") s2 = pickle.loads(pickle.dumps(s1)) - self.assertEqual(unicode(s2), "test") + self.assertEqual(six.text_type(s2), "test") def test_pgettext(self): # Reset translation catalog to include other/locale/de @@ -221,10 +223,10 @@ class TranslationTests(TestCase): def test_string_concat(self): """ - unicode(string_concat(...)) should not raise a TypeError - #4796 + six.text_type(string_concat(...)) should not raise a TypeError - #4796 """ import django.utils.translation - self.assertEqual('django', unicode(django.utils.translation.string_concat("dja", "ngo"))) + self.assertEqual('django', six.text_type(django.utils.translation.string_concat("dja", "ngo"))) def test_safe_status(self): """ @@ -309,7 +311,7 @@ class FormattingTests(TestCase): self.d = datetime.date(2009, 12, 31) self.dt = datetime.datetime(2009, 12, 31, 20, 50) self.t = datetime.time(10, 15, 48) - self.l = 10000L + self.l = 10000 if PY3 else long(10000) self.ctxt = Context({ 'n': self.n, 't': self.t, diff --git a/tests/regressiontests/initial_sql_regress/sql/simple.sql b/tests/regressiontests/initial_sql_regress/sql/simple.sql index ca9bd40dab..39363baa9a 100644 --- a/tests/regressiontests/initial_sql_regress/sql/simple.sql +++ b/tests/regressiontests/initial_sql_regress/sql/simple.sql @@ -1,4 +1,6 @@ -INSERT INTO initial_sql_regress_simple (name) VALUES ('John'); +-- a comment +INSERT INTO initial_sql_regress_simple (name) VALUES ('John'); -- another comment +INSERT INTO initial_sql_regress_simple (name) VALUES ('-- Comment Man'); INSERT INTO initial_sql_regress_simple (name) VALUES ('Paul'); INSERT INTO initial_sql_regress_simple (name) VALUES ('Ringo'); INSERT INTO initial_sql_regress_simple (name) VALUES ('George'); diff --git a/tests/regressiontests/initial_sql_regress/tests.py b/tests/regressiontests/initial_sql_regress/tests.py index 815b75a9bb..03a91cb807 100644 --- a/tests/regressiontests/initial_sql_regress/tests.py +++ b/tests/regressiontests/initial_sql_regress/tests.py @@ -4,12 +4,26 @@ from .models import Simple class InitialSQLTests(TestCase): - def test_initial_sql(self): - # The format of the included SQL file for this test suite is important. - # It must end with a trailing newline in order to test the fix for #2161. + # The format of the included SQL file for this test suite is important. + # It must end with a trailing newline in order to test the fix for #2161. - # However, as pointed out by #14661, test data loaded by custom SQL + def test_initial_sql(self): + # As pointed out by #14661, test data loaded by custom SQL # can't be relied upon; as a result, the test framework flushes the # data contents before every test. This test validates that this has # occurred. self.assertEqual(Simple.objects.count(), 0) + + def test_custom_sql(self): + from django.core.management.sql import custom_sql_for_model + from django.core.management.color import no_style + from django.db import connections, DEFAULT_DB_ALIAS + + # Simulate the custom SQL loading by syncdb + connection = connections[DEFAULT_DB_ALIAS] + custom_sql = custom_sql_for_model(Simple, no_style(), connection) + self.assertEqual(len(custom_sql), 8) + cursor = connection.cursor() + for sql in custom_sql: + cursor.execute(sql) + self.assertEqual(Simple.objects.count(), 8) diff --git a/tests/regressiontests/inline_formsets/tests.py b/tests/regressiontests/inline_formsets/tests.py index 8ad84f221f..6e63f34ed0 100644 --- a/tests/regressiontests/inline_formsets/tests.py +++ b/tests/regressiontests/inline_formsets/tests.py @@ -2,6 +2,7 @@ from __future__ import absolute_import, unicode_literals from django.forms.models import inlineformset_factory from django.test import TestCase +from django.utils import six from .models import Poet, Poem, School, Parent, Child @@ -66,8 +67,8 @@ class DeletionTests(TestCase): 'poem_set-TOTAL_FORMS': '1', 'poem_set-INITIAL_FORMS': '1', 'poem_set-MAX_NUM_FORMS': '0', - 'poem_set-0-id': unicode(poem.id), - 'poem_set-0-poem': unicode(poem.id), + 'poem_set-0-id': six.text_type(poem.id), + 'poem_set-0-poem': six.text_type(poem.id), 'poem_set-0-name': 'x' * 1000, } formset = PoemFormSet(data, instance=poet) diff --git a/tests/regressiontests/localflavor/ar/tests.py b/tests/regressiontests/localflavor/ar/tests.py index 0731c3ce9b..0bc228eae9 100644 --- a/tests/regressiontests/localflavor/ar/tests.py +++ b/tests/regressiontests/localflavor/ar/tests.py @@ -81,20 +81,23 @@ class ARLocalFlavorTests(SimpleTestCase): def test_ARCUITField(self): error_format = ['Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.'] error_invalid = ['Invalid CUIT.'] + error_legal_type = ['Invalid legal type. Type must be 27, 20, 23 or 30.'] valid = { '20-10123456-9': '20-10123456-9', '20-10123456-9': '20-10123456-9', '27-10345678-4': '27-10345678-4', '20101234569': '20-10123456-9', '27103456784': '27-10345678-4', + '30011111110': '30-01111111-0', } invalid = { '2-10123456-9': error_format, '210123456-9': error_format, '20-10123456': error_format, '20-10123456-': error_format, - '20-10123456-5': error_invalid, - '27-10345678-1': error_invalid, - '27-10345678-1': error_invalid, + '20-10123456-5': error_invalid, + '27-10345678-1': error_invalid, + '27-10345678-1': error_invalid, + '11211111110': error_legal_type, } self.assertFieldOutput(ARCUITField, valid, invalid) diff --git a/tests/regressiontests/localflavor/fr/tests.py b/tests/regressiontests/localflavor/fr/tests.py index 55f8a68b3b..8e99ef462b 100644 --- a/tests/regressiontests/localflavor/fr/tests.py +++ b/tests/regressiontests/localflavor/fr/tests.py @@ -16,7 +16,8 @@ class FRLocalFlavorTests(SimpleTestCase): } invalid = { '2A200': error_format, - '980001': error_format, + '980001': ['Ensure this value has at most 5 characters (it has 6).' + ] + error_format, } self.assertFieldOutput(FRZipCodeField, valid, invalid) diff --git a/tests/regressiontests/mail/tests.py b/tests/regressiontests/mail/tests.py index cdd6dd1b9e..2215f56523 100644 --- a/tests/regressiontests/mail/tests.py +++ b/tests/regressiontests/mail/tests.py @@ -603,21 +603,16 @@ class FakeSMTPServer(smtpd.SMTPServer, threading.Thread): maddr = email.Utils.parseaddr(m.get('from'))[1] if mailfrom != maddr: return "553 '%s' != '%s'" % (mailfrom, maddr) - self.sink_lock.acquire() - self._sink.append(m) - self.sink_lock.release() + with self.sink_lock: + self._sink.append(m) def get_sink(self): - self.sink_lock.acquire() - try: + with self.sink_lock: return self._sink[:] - finally: - self.sink_lock.release() def flush_sink(self): - self.sink_lock.acquire() - self._sink[:] = [] - self.sink_lock.release() + with self.sink_lock: + self._sink[:] = [] def start(self): assert not self.active @@ -629,9 +624,8 @@ class FakeSMTPServer(smtpd.SMTPServer, threading.Thread): self.active = True self.__flag.set() while self.active and asyncore.socket_map: - self.active_lock.acquire() - asyncore.loop(timeout=0.1, count=1) - self.active_lock.release() + with self.active_lock: + asyncore.loop(timeout=0.1, count=1) asyncore.close_all() def stop(self): diff --git a/tests/regressiontests/middleware/tests.py b/tests/regressiontests/middleware/tests.py index 47fca03ba3..ead34f46db 100644 --- a/tests/regressiontests/middleware/tests.py +++ b/tests/regressiontests/middleware/tests.py @@ -15,6 +15,7 @@ from django.middleware.http import ConditionalGetMiddleware from django.middleware.gzip import GZipMiddleware from django.test import TestCase, RequestFactory from django.test.utils import override_settings +from django.utils.six.moves import xrange class CommonMiddlewareTest(TestCase): def setUp(self): diff --git a/tests/regressiontests/model_fields/imagefield.py b/tests/regressiontests/model_fields/imagefield.py index 09c1bd76d3..7446f222ff 100644 --- a/tests/regressiontests/model_fields/imagefield.py +++ b/tests/regressiontests/model_fields/imagefield.py @@ -6,416 +6,428 @@ import shutil from django.core.files import File from django.core.files.images import ImageFile from django.test import TestCase +from django.utils.unittest import skipIf -from .models import (Image, Person, PersonWithHeight, PersonWithHeightAndWidth, - PersonDimensionsFirst, PersonTwoImages, TestImageFieldFile) +from .models import Image - -# If PIL available, do these tests. if Image: - + from .models import (Person, PersonWithHeight, PersonWithHeightAndWidth, + PersonDimensionsFirst, PersonTwoImages, TestImageFieldFile) from .models import temp_storage_dir +else: + # PIL not available, create dummy classes (tests will be skipped anyway) + class Person(): + pass + PersonWithHeight = PersonWithHeightAndWidth = PersonDimensionsFirst = Person + PersonTwoImages = Person - class ImageFieldTestMixin(object): - """ - Mixin class to provide common functionality to ImageField test classes. - """ +class ImageFieldTestMixin(object): + """ + Mixin class to provide common functionality to ImageField test classes. + """ - # Person model to use for tests. - PersonModel = PersonWithHeightAndWidth - # File class to use for file instances. - File = ImageFile + # Person model to use for tests. + PersonModel = PersonWithHeightAndWidth + # File class to use for file instances. + File = ImageFile - def setUp(self): - """ - Creates a pristine temp directory (or deletes and recreates if it - already exists) that the model uses as its storage directory. + def setUp(self): + """ + Creates a pristine temp directory (or deletes and recreates if it + already exists) that the model uses as its storage directory. - Sets up two ImageFile instances for use in tests. - """ - if os.path.exists(temp_storage_dir): - shutil.rmtree(temp_storage_dir) - os.mkdir(temp_storage_dir) + Sets up two ImageFile instances for use in tests. + """ + if os.path.exists(temp_storage_dir): + shutil.rmtree(temp_storage_dir) + os.mkdir(temp_storage_dir) - file_path1 = os.path.join(os.path.dirname(__file__), "4x8.png") - self.file1 = self.File(open(file_path1, 'rb')) + file_path1 = os.path.join(os.path.dirname(__file__), "4x8.png") + self.file1 = self.File(open(file_path1, 'rb')) - file_path2 = os.path.join(os.path.dirname(__file__), "8x4.png") - self.file2 = self.File(open(file_path2, 'rb')) + file_path2 = os.path.join(os.path.dirname(__file__), "8x4.png") + self.file2 = self.File(open(file_path2, 'rb')) - def tearDown(self): - """ - Removes temp directory and all its contents. - """ - shutil.rmtree(temp_storage_dir) + def tearDown(self): + """ + Removes temp directory and all its contents. + """ + shutil.rmtree(temp_storage_dir) - def check_dimensions(self, instance, width, height, - field_name='mugshot'): - """ - Asserts that the given width and height values match both the - field's height and width attributes and the height and width fields - (if defined) the image field is caching to. + def check_dimensions(self, instance, width, height, + field_name='mugshot'): + """ + Asserts that the given width and height values match both the + field's height and width attributes and the height and width fields + (if defined) the image field is caching to. - Note, this method will check for dimension fields named by adding - "_width" or "_height" to the name of the ImageField. So, the - models used in these tests must have their fields named - accordingly. + Note, this method will check for dimension fields named by adding + "_width" or "_height" to the name of the ImageField. So, the + models used in these tests must have their fields named + accordingly. - By default, we check the field named "mugshot", but this can be - specified by passing the field_name parameter. - """ - field = getattr(instance, field_name) - # Check height/width attributes of field. - if width is None and height is None: - self.assertRaises(ValueError, getattr, field, 'width') - self.assertRaises(ValueError, getattr, field, 'height') - else: - self.assertEqual(field.width, width) - self.assertEqual(field.height, height) + By default, we check the field named "mugshot", but this can be + specified by passing the field_name parameter. + """ + field = getattr(instance, field_name) + # Check height/width attributes of field. + if width is None and height is None: + self.assertRaises(ValueError, getattr, field, 'width') + self.assertRaises(ValueError, getattr, field, 'height') + else: + self.assertEqual(field.width, width) + self.assertEqual(field.height, height) - # Check height/width fields of model, if defined. - width_field_name = field_name + '_width' - if hasattr(instance, width_field_name): - self.assertEqual(getattr(instance, width_field_name), width) - height_field_name = field_name + '_height' - if hasattr(instance, height_field_name): - self.assertEqual(getattr(instance, height_field_name), height) + # Check height/width fields of model, if defined. + width_field_name = field_name + '_width' + if hasattr(instance, width_field_name): + self.assertEqual(getattr(instance, width_field_name), width) + height_field_name = field_name + '_height' + if hasattr(instance, height_field_name): + self.assertEqual(getattr(instance, height_field_name), height) - class ImageFieldTests(ImageFieldTestMixin, TestCase): +@skipIf(Image is None, "PIL is required to test ImageField") +class ImageFieldTests(ImageFieldTestMixin, TestCase): + """ + Tests for ImageField that don't need to be run with each of the + different test model classes. + """ + + def test_equal_notequal_hash(self): """ - Tests for ImageField that don't need to be run with each of the - different test model classes. + Bug #9786: Ensure '==' and '!=' work correctly. + Bug #9508: make sure hash() works as expected (equal items must + hash to the same value). """ + # Create two Persons with different mugshots. + p1 = self.PersonModel(name="Joe") + p1.mugshot.save("mug", self.file1) + p2 = self.PersonModel(name="Bob") + p2.mugshot.save("mug", self.file2) + self.assertEqual(p1.mugshot == p2.mugshot, False) + self.assertEqual(p1.mugshot != p2.mugshot, True) - def test_equal_notequal_hash(self): - """ - Bug #9786: Ensure '==' and '!=' work correctly. - Bug #9508: make sure hash() works as expected (equal items must - hash to the same value). - """ - # Create two Persons with different mugshots. - p1 = self.PersonModel(name="Joe") - p1.mugshot.save("mug", self.file1) - p2 = self.PersonModel(name="Bob") - p2.mugshot.save("mug", self.file2) - self.assertEqual(p1.mugshot == p2.mugshot, False) - self.assertEqual(p1.mugshot != p2.mugshot, True) + # Test again with an instance fetched from the db. + p1_db = self.PersonModel.objects.get(name="Joe") + self.assertEqual(p1_db.mugshot == p2.mugshot, False) + self.assertEqual(p1_db.mugshot != p2.mugshot, True) - # Test again with an instance fetched from the db. - p1_db = self.PersonModel.objects.get(name="Joe") - self.assertEqual(p1_db.mugshot == p2.mugshot, False) - self.assertEqual(p1_db.mugshot != p2.mugshot, True) + # Instance from db should match the local instance. + self.assertEqual(p1_db.mugshot == p1.mugshot, True) + self.assertEqual(hash(p1_db.mugshot), hash(p1.mugshot)) + self.assertEqual(p1_db.mugshot != p1.mugshot, False) - # Instance from db should match the local instance. - self.assertEqual(p1_db.mugshot == p1.mugshot, True) - self.assertEqual(hash(p1_db.mugshot), hash(p1.mugshot)) - self.assertEqual(p1_db.mugshot != p1.mugshot, False) + def test_instantiate_missing(self): + """ + If the underlying file is unavailable, still create instantiate the + object without error. + """ + p = self.PersonModel(name="Joan") + p.mugshot.save("shot", self.file1) + p = self.PersonModel.objects.get(name="Joan") + path = p.mugshot.path + shutil.move(path, path + '.moved') + p2 = self.PersonModel.objects.get(name="Joan") - def test_instantiate_missing(self): - """ - If the underlying file is unavailable, still create instantiate the - object without error. - """ - p = self.PersonModel(name="Joan") - p.mugshot.save("shot", self.file1) - p = self.PersonModel.objects.get(name="Joan") - path = p.mugshot.path - shutil.move(path, path + '.moved') - p2 = self.PersonModel.objects.get(name="Joan") + def test_delete_when_missing(self): + """ + Bug #8175: correctly delete an object where the file no longer + exists on the file system. + """ + p = self.PersonModel(name="Fred") + p.mugshot.save("shot", self.file1) + os.remove(p.mugshot.path) + p.delete() - def test_delete_when_missing(self): - """ - Bug #8175: correctly delete an object where the file no longer - exists on the file system. - """ - p = self.PersonModel(name="Fred") - p.mugshot.save("shot", self.file1) - os.remove(p.mugshot.path) - p.delete() + def test_size_method(self): + """ + Bug #8534: FileField.size should not leave the file open. + """ + p = self.PersonModel(name="Joan") + p.mugshot.save("shot", self.file1) - def test_size_method(self): - """ - Bug #8534: FileField.size should not leave the file open. - """ - p = self.PersonModel(name="Joan") - p.mugshot.save("shot", self.file1) + # Get a "clean" model instance + p = self.PersonModel.objects.get(name="Joan") + # It won't have an opened file. + self.assertEqual(p.mugshot.closed, True) - # Get a "clean" model instance - p = self.PersonModel.objects.get(name="Joan") - # It won't have an opened file. - self.assertEqual(p.mugshot.closed, True) + # After asking for the size, the file should still be closed. + _ = p.mugshot.size + self.assertEqual(p.mugshot.closed, True) - # After asking for the size, the file should still be closed. - _ = p.mugshot.size - self.assertEqual(p.mugshot.closed, True) + def test_pickle(self): + """ + Tests that ImageField can be pickled, unpickled, and that the + image of the unpickled version is the same as the original. + """ + import pickle - def test_pickle(self): - """ - Tests that ImageField can be pickled, unpickled, and that the - image of the unpickled version is the same as the original. - """ - import pickle + p = Person(name="Joe") + p.mugshot.save("mug", self.file1) + dump = pickle.dumps(p) - p = Person(name="Joe") - p.mugshot.save("mug", self.file1) - dump = pickle.dumps(p) + p2 = Person(name="Bob") + p2.mugshot = self.file1 - p2 = Person(name="Bob") - p2.mugshot = self.file1 + loaded_p = pickle.loads(dump) + self.assertEqual(p.mugshot, loaded_p.mugshot) - loaded_p = pickle.loads(dump) - self.assertEqual(p.mugshot, loaded_p.mugshot) +@skipIf(Image is None, "PIL is required to test ImageField") +class ImageFieldTwoDimensionsTests(ImageFieldTestMixin, TestCase): + """ + Tests behavior of an ImageField and its dimensions fields. + """ - class ImageFieldTwoDimensionsTests(ImageFieldTestMixin, TestCase): + def test_constructor(self): """ - Tests behavior of an ImageField and its dimensions fields. + Tests assigning an image field through the model's constructor. """ + p = self.PersonModel(name='Joe', mugshot=self.file1) + self.check_dimensions(p, 4, 8) + p.save() + self.check_dimensions(p, 4, 8) - def test_constructor(self): - """ - Tests assigning an image field through the model's constructor. - """ - p = self.PersonModel(name='Joe', mugshot=self.file1) - self.check_dimensions(p, 4, 8) - p.save() - self.check_dimensions(p, 4, 8) - - def test_image_after_constructor(self): - """ - Tests behavior when image is not passed in constructor. - """ - p = self.PersonModel(name='Joe') - # TestImageField value will default to being an instance of its - # attr_class, a TestImageFieldFile, with name == None, which will - # cause it to evaluate as False. - self.assertEqual(isinstance(p.mugshot, TestImageFieldFile), True) - self.assertEqual(bool(p.mugshot), False) + def test_image_after_constructor(self): + """ + Tests behavior when image is not passed in constructor. + """ + p = self.PersonModel(name='Joe') + # TestImageField value will default to being an instance of its + # attr_class, a TestImageFieldFile, with name == None, which will + # cause it to evaluate as False. + self.assertEqual(isinstance(p.mugshot, TestImageFieldFile), True) + self.assertEqual(bool(p.mugshot), False) - # Test setting a fresh created model instance. - p = self.PersonModel(name='Joe') - p.mugshot = self.file1 - self.check_dimensions(p, 4, 8) + # Test setting a fresh created model instance. + p = self.PersonModel(name='Joe') + p.mugshot = self.file1 + self.check_dimensions(p, 4, 8) - def test_create(self): - """ - Tests assigning an image in Manager.create(). - """ - p = self.PersonModel.objects.create(name='Joe', mugshot=self.file1) - self.check_dimensions(p, 4, 8) + def test_create(self): + """ + Tests assigning an image in Manager.create(). + """ + p = self.PersonModel.objects.create(name='Joe', mugshot=self.file1) + self.check_dimensions(p, 4, 8) - def test_default_value(self): - """ - Tests that the default value for an ImageField is an instance of - the field's attr_class (TestImageFieldFile in this case) with no - name (name set to None). - """ - p = self.PersonModel() - self.assertEqual(isinstance(p.mugshot, TestImageFieldFile), True) - self.assertEqual(bool(p.mugshot), False) + def test_default_value(self): + """ + Tests that the default value for an ImageField is an instance of + the field's attr_class (TestImageFieldFile in this case) with no + name (name set to None). + """ + p = self.PersonModel() + self.assertEqual(isinstance(p.mugshot, TestImageFieldFile), True) + self.assertEqual(bool(p.mugshot), False) - def test_assignment_to_None(self): - """ - Tests that assigning ImageField to None clears dimensions. - """ - p = self.PersonModel(name='Joe', mugshot=self.file1) - self.check_dimensions(p, 4, 8) + def test_assignment_to_None(self): + """ + Tests that assigning ImageField to None clears dimensions. + """ + p = self.PersonModel(name='Joe', mugshot=self.file1) + self.check_dimensions(p, 4, 8) - # If image assigned to None, dimension fields should be cleared. - p.mugshot = None - self.check_dimensions(p, None, None) + # If image assigned to None, dimension fields should be cleared. + p.mugshot = None + self.check_dimensions(p, None, None) - p.mugshot = self.file2 - self.check_dimensions(p, 8, 4) + p.mugshot = self.file2 + self.check_dimensions(p, 8, 4) - def test_field_save_and_delete_methods(self): - """ - Tests assignment using the field's save method and deletion using - the field's delete method. - """ - p = self.PersonModel(name='Joe') - p.mugshot.save("mug", self.file1) - self.check_dimensions(p, 4, 8) + def test_field_save_and_delete_methods(self): + """ + Tests assignment using the field's save method and deletion using + the field's delete method. + """ + p = self.PersonModel(name='Joe') + p.mugshot.save("mug", self.file1) + self.check_dimensions(p, 4, 8) - # A new file should update dimensions. - p.mugshot.save("mug", self.file2) - self.check_dimensions(p, 8, 4) + # A new file should update dimensions. + p.mugshot.save("mug", self.file2) + self.check_dimensions(p, 8, 4) - # Field and dimensions should be cleared after a delete. - p.mugshot.delete(save=False) - self.assertEqual(p.mugshot, None) - self.check_dimensions(p, None, None) + # Field and dimensions should be cleared after a delete. + p.mugshot.delete(save=False) + self.assertEqual(p.mugshot, None) + self.check_dimensions(p, None, None) - def test_dimensions(self): - """ - Checks that dimensions are updated correctly in various situations. - """ - p = self.PersonModel(name='Joe') + def test_dimensions(self): + """ + Checks that dimensions are updated correctly in various situations. + """ + p = self.PersonModel(name='Joe') - # Dimensions should get set if file is saved. - p.mugshot.save("mug", self.file1) - self.check_dimensions(p, 4, 8) + # Dimensions should get set if file is saved. + p.mugshot.save("mug", self.file1) + self.check_dimensions(p, 4, 8) - # Test dimensions after fetching from database. - p = self.PersonModel.objects.get(name='Joe') - # Bug 11084: Dimensions should not get recalculated if file is - # coming from the database. We test this by checking if the file - # was opened. - self.assertEqual(p.mugshot.was_opened, False) - self.check_dimensions(p, 4, 8) - # After checking dimensions on the image field, the file will have - # opened. - self.assertEqual(p.mugshot.was_opened, True) - # Dimensions should now be cached, and if we reset was_opened and - # check dimensions again, the file should not have opened. - p.mugshot.was_opened = False - self.check_dimensions(p, 4, 8) - self.assertEqual(p.mugshot.was_opened, False) + # Test dimensions after fetching from database. + p = self.PersonModel.objects.get(name='Joe') + # Bug 11084: Dimensions should not get recalculated if file is + # coming from the database. We test this by checking if the file + # was opened. + self.assertEqual(p.mugshot.was_opened, False) + self.check_dimensions(p, 4, 8) + # After checking dimensions on the image field, the file will have + # opened. + self.assertEqual(p.mugshot.was_opened, True) + # Dimensions should now be cached, and if we reset was_opened and + # check dimensions again, the file should not have opened. + p.mugshot.was_opened = False + self.check_dimensions(p, 4, 8) + self.assertEqual(p.mugshot.was_opened, False) - # If we assign a new image to the instance, the dimensions should - # update. - p.mugshot = self.file2 - self.check_dimensions(p, 8, 4) - # Dimensions were recalculated, and hence file should have opened. - self.assertEqual(p.mugshot.was_opened, True) + # If we assign a new image to the instance, the dimensions should + # update. + p.mugshot = self.file2 + self.check_dimensions(p, 8, 4) + # Dimensions were recalculated, and hence file should have opened. + self.assertEqual(p.mugshot.was_opened, True) - class ImageFieldNoDimensionsTests(ImageFieldTwoDimensionsTests): - """ - Tests behavior of an ImageField with no dimension fields. - """ +@skipIf(Image is None, "PIL is required to test ImageField") +class ImageFieldNoDimensionsTests(ImageFieldTwoDimensionsTests): + """ + Tests behavior of an ImageField with no dimension fields. + """ - PersonModel = Person + PersonModel = Person - class ImageFieldOneDimensionTests(ImageFieldTwoDimensionsTests): - """ - Tests behavior of an ImageField with one dimensions field. - """ +@skipIf(Image is None, "PIL is required to test ImageField") +class ImageFieldOneDimensionTests(ImageFieldTwoDimensionsTests): + """ + Tests behavior of an ImageField with one dimensions field. + """ - PersonModel = PersonWithHeight + PersonModel = PersonWithHeight - class ImageFieldDimensionsFirstTests(ImageFieldTwoDimensionsTests): - """ - Tests behavior of an ImageField where the dimensions fields are - defined before the ImageField. - """ +@skipIf(Image is None, "PIL is required to test ImageField") +class ImageFieldDimensionsFirstTests(ImageFieldTwoDimensionsTests): + """ + Tests behavior of an ImageField where the dimensions fields are + defined before the ImageField. + """ - PersonModel = PersonDimensionsFirst + PersonModel = PersonDimensionsFirst - class ImageFieldUsingFileTests(ImageFieldTwoDimensionsTests): - """ - Tests behavior of an ImageField when assigning it a File instance - rather than an ImageFile instance. - """ +@skipIf(Image is None, "PIL is required to test ImageField") +class ImageFieldUsingFileTests(ImageFieldTwoDimensionsTests): + """ + Tests behavior of an ImageField when assigning it a File instance + rather than an ImageFile instance. + """ - PersonModel = PersonDimensionsFirst - File = File + PersonModel = PersonDimensionsFirst + File = File - class TwoImageFieldTests(ImageFieldTestMixin, TestCase): - """ - Tests a model with two ImageFields. - """ +@skipIf(Image is None, "PIL is required to test ImageField") +class TwoImageFieldTests(ImageFieldTestMixin, TestCase): + """ + Tests a model with two ImageFields. + """ - PersonModel = PersonTwoImages + PersonModel = PersonTwoImages - def test_constructor(self): - p = self.PersonModel(mugshot=self.file1, headshot=self.file2) - self.check_dimensions(p, 4, 8, 'mugshot') - self.check_dimensions(p, 8, 4, 'headshot') - p.save() - self.check_dimensions(p, 4, 8, 'mugshot') - self.check_dimensions(p, 8, 4, 'headshot') + def test_constructor(self): + p = self.PersonModel(mugshot=self.file1, headshot=self.file2) + self.check_dimensions(p, 4, 8, 'mugshot') + self.check_dimensions(p, 8, 4, 'headshot') + p.save() + self.check_dimensions(p, 4, 8, 'mugshot') + self.check_dimensions(p, 8, 4, 'headshot') - def test_create(self): - p = self.PersonModel.objects.create(mugshot=self.file1, - headshot=self.file2) - self.check_dimensions(p, 4, 8) - self.check_dimensions(p, 8, 4, 'headshot') + def test_create(self): + p = self.PersonModel.objects.create(mugshot=self.file1, + headshot=self.file2) + self.check_dimensions(p, 4, 8) + self.check_dimensions(p, 8, 4, 'headshot') - def test_assignment(self): - p = self.PersonModel() - self.check_dimensions(p, None, None, 'mugshot') - self.check_dimensions(p, None, None, 'headshot') + def test_assignment(self): + p = self.PersonModel() + self.check_dimensions(p, None, None, 'mugshot') + self.check_dimensions(p, None, None, 'headshot') - p.mugshot = self.file1 - self.check_dimensions(p, 4, 8, 'mugshot') - self.check_dimensions(p, None, None, 'headshot') - p.headshot = self.file2 - self.check_dimensions(p, 4, 8, 'mugshot') - self.check_dimensions(p, 8, 4, 'headshot') + p.mugshot = self.file1 + self.check_dimensions(p, 4, 8, 'mugshot') + self.check_dimensions(p, None, None, 'headshot') + p.headshot = self.file2 + self.check_dimensions(p, 4, 8, 'mugshot') + self.check_dimensions(p, 8, 4, 'headshot') - # Clear the ImageFields one at a time. - p.mugshot = None - self.check_dimensions(p, None, None, 'mugshot') - self.check_dimensions(p, 8, 4, 'headshot') - p.headshot = None - self.check_dimensions(p, None, None, 'mugshot') - self.check_dimensions(p, None, None, 'headshot') + # Clear the ImageFields one at a time. + p.mugshot = None + self.check_dimensions(p, None, None, 'mugshot') + self.check_dimensions(p, 8, 4, 'headshot') + p.headshot = None + self.check_dimensions(p, None, None, 'mugshot') + self.check_dimensions(p, None, None, 'headshot') - def test_field_save_and_delete_methods(self): - p = self.PersonModel(name='Joe') - p.mugshot.save("mug", self.file1) - self.check_dimensions(p, 4, 8, 'mugshot') - self.check_dimensions(p, None, None, 'headshot') - p.headshot.save("head", self.file2) - self.check_dimensions(p, 4, 8, 'mugshot') - self.check_dimensions(p, 8, 4, 'headshot') + def test_field_save_and_delete_methods(self): + p = self.PersonModel(name='Joe') + p.mugshot.save("mug", self.file1) + self.check_dimensions(p, 4, 8, 'mugshot') + self.check_dimensions(p, None, None, 'headshot') + p.headshot.save("head", self.file2) + self.check_dimensions(p, 4, 8, 'mugshot') + self.check_dimensions(p, 8, 4, 'headshot') - # We can use save=True when deleting the image field with null=True - # dimension fields and the other field has an image. - p.headshot.delete(save=True) - self.check_dimensions(p, 4, 8, 'mugshot') - self.check_dimensions(p, None, None, 'headshot') - p.mugshot.delete(save=False) - self.check_dimensions(p, None, None, 'mugshot') - self.check_dimensions(p, None, None, 'headshot') + # We can use save=True when deleting the image field with null=True + # dimension fields and the other field has an image. + p.headshot.delete(save=True) + self.check_dimensions(p, 4, 8, 'mugshot') + self.check_dimensions(p, None, None, 'headshot') + p.mugshot.delete(save=False) + self.check_dimensions(p, None, None, 'mugshot') + self.check_dimensions(p, None, None, 'headshot') - def test_dimensions(self): - """ - Checks that dimensions are updated correctly in various situations. - """ - p = self.PersonModel(name='Joe') + def test_dimensions(self): + """ + Checks that dimensions are updated correctly in various situations. + """ + p = self.PersonModel(name='Joe') - # Dimensions should get set for the saved file. - p.mugshot.save("mug", self.file1) - p.headshot.save("head", self.file2) - self.check_dimensions(p, 4, 8, 'mugshot') - self.check_dimensions(p, 8, 4, 'headshot') + # Dimensions should get set for the saved file. + p.mugshot.save("mug", self.file1) + p.headshot.save("head", self.file2) + self.check_dimensions(p, 4, 8, 'mugshot') + self.check_dimensions(p, 8, 4, 'headshot') - # Test dimensions after fetching from database. - p = self.PersonModel.objects.get(name='Joe') - # Bug 11084: Dimensions should not get recalculated if file is - # coming from the database. We test this by checking if the file - # was opened. - self.assertEqual(p.mugshot.was_opened, False) - self.assertEqual(p.headshot.was_opened, False) - self.check_dimensions(p, 4, 8,'mugshot') - self.check_dimensions(p, 8, 4, 'headshot') - # After checking dimensions on the image fields, the files will - # have been opened. - self.assertEqual(p.mugshot.was_opened, True) - self.assertEqual(p.headshot.was_opened, True) - # Dimensions should now be cached, and if we reset was_opened and - # check dimensions again, the file should not have opened. - p.mugshot.was_opened = False - p.headshot.was_opened = False - self.check_dimensions(p, 4, 8,'mugshot') - self.check_dimensions(p, 8, 4, 'headshot') - self.assertEqual(p.mugshot.was_opened, False) - self.assertEqual(p.headshot.was_opened, False) + # Test dimensions after fetching from database. + p = self.PersonModel.objects.get(name='Joe') + # Bug 11084: Dimensions should not get recalculated if file is + # coming from the database. We test this by checking if the file + # was opened. + self.assertEqual(p.mugshot.was_opened, False) + self.assertEqual(p.headshot.was_opened, False) + self.check_dimensions(p, 4, 8,'mugshot') + self.check_dimensions(p, 8, 4, 'headshot') + # After checking dimensions on the image fields, the files will + # have been opened. + self.assertEqual(p.mugshot.was_opened, True) + self.assertEqual(p.headshot.was_opened, True) + # Dimensions should now be cached, and if we reset was_opened and + # check dimensions again, the file should not have opened. + p.mugshot.was_opened = False + p.headshot.was_opened = False + self.check_dimensions(p, 4, 8,'mugshot') + self.check_dimensions(p, 8, 4, 'headshot') + self.assertEqual(p.mugshot.was_opened, False) + self.assertEqual(p.headshot.was_opened, False) - # If we assign a new image to the instance, the dimensions should - # update. - p.mugshot = self.file2 - p.headshot = self.file1 - self.check_dimensions(p, 8, 4, 'mugshot') - self.check_dimensions(p, 4, 8, 'headshot') - # Dimensions were recalculated, and hence file should have opened. - self.assertEqual(p.mugshot.was_opened, True) - self.assertEqual(p.headshot.was_opened, True) + # If we assign a new image to the instance, the dimensions should + # update. + p.mugshot = self.file2 + p.headshot = self.file1 + self.check_dimensions(p, 8, 4, 'mugshot') + self.check_dimensions(p, 4, 8, 'headshot') + # Dimensions were recalculated, and hence file should have opened. + self.assertEqual(p.mugshot.was_opened, True) + self.assertEqual(p.headshot.was_opened, True) diff --git a/tests/regressiontests/model_fields/tests.py b/tests/regressiontests/model_fields/tests.py index 5d3d42ef2a..e86159463d 100644 --- a/tests/regressiontests/model_fields/tests.py +++ b/tests/regressiontests/model_fields/tests.py @@ -8,17 +8,16 @@ from django import forms from django.core.exceptions import ValidationError from django.db import models from django.db.models.fields.files import FieldFile +from django.utils import six from django.utils import unittest from .models import (Foo, Bar, Whiz, BigD, BigS, Image, BigInt, Post, NullBooleanModel, BooleanModel, Document, RenamedField) -# If PIL available, do these tests. -if Image: - from .imagefield import (ImageFieldTests, ImageFieldTwoDimensionsTests, - TwoImageFieldTests, ImageFieldNoDimensionsTests, - ImageFieldOneDimensionTests, ImageFieldDimensionsFirstTests, - ImageFieldUsingFileTests) +from .imagefield import (ImageFieldTests, ImageFieldTwoDimensionsTests, + TwoImageFieldTests, ImageFieldNoDimensionsTests, + ImageFieldOneDimensionTests, ImageFieldDimensionsFirstTests, + ImageFieldUsingFileTests) class BasicFieldTests(test.TestCase): @@ -305,11 +304,11 @@ class BigIntegerFieldTests(test.TestCase): def test_types(self): b = BigInt(value = 0) - self.assertTrue(isinstance(b.value, (int, long))) + self.assertTrue(isinstance(b.value, six.integer_types)) b.save() - self.assertTrue(isinstance(b.value, (int, long))) + self.assertTrue(isinstance(b.value, six.integer_types)) b = BigInt.objects.all()[0] - self.assertTrue(isinstance(b.value, (int, long))) + self.assertTrue(isinstance(b.value, six.integer_types)) def test_coercing(self): BigInt.objects.create(value ='10') @@ -365,15 +364,3 @@ class FileFieldTests(unittest.TestCase): field = d._meta.get_field('myfile') field.save_form_data(d, 'else.txt') self.assertEqual(d.myfile, 'else.txt') - - def test_max_length(self): - """ - Test that FileField validates the length of the generated file name - that will be stored in the database. Regression for #9893. - - """ - # upload_to = 'unused', so file names are saved as 'unused/xxxxx'. - # max_length = 100, so names longer than 93 characters are rejected. - Document(myfile=93 * 'x').full_clean() - with self.assertRaises(ValidationError): - Document(myfile=94 * 'x').full_clean() diff --git a/tests/regressiontests/model_forms_regress/tests.py b/tests/regressiontests/model_forms_regress/tests.py index a0f9bba170..3cb129f84e 100644 --- a/tests/regressiontests/model_forms_regress/tests.py +++ b/tests/regressiontests/model_forms_regress/tests.py @@ -7,6 +7,7 @@ from django.core.exceptions import FieldError, ValidationError from django.core.files.uploadedfile import SimpleUploadedFile from django.forms.models import (modelform_factory, ModelChoiceField, fields_for_model, construct_instance, ModelFormMetaclass) +from django.utils import six from django.utils import unittest from django.test import TestCase @@ -392,14 +393,14 @@ class FileFieldTests(unittest.TestCase): """ form = DocumentForm() - self.assertTrue('name="myfile"' in unicode(form)) - self.assertTrue('myfile-clear' not in unicode(form)) + self.assertTrue('name="myfile"' in six.text_type(form)) + self.assertTrue('myfile-clear' not in six.text_type(form)) form = DocumentForm(files={'myfile': SimpleUploadedFile('something.txt', b'content')}) self.assertTrue(form.is_valid()) doc = form.save(commit=False) self.assertEqual(doc.myfile.name, 'something.txt') form = DocumentForm(instance=doc) - self.assertTrue('myfile-clear' in unicode(form)) + self.assertTrue('myfile-clear' in six.text_type(form)) form = DocumentForm(instance=doc, data={'myfile-clear': 'true'}) doc = form.save(commit=False) self.assertEqual(bool(doc.myfile), False) @@ -420,7 +421,7 @@ class FileFieldTests(unittest.TestCase): self.assertTrue(not form.is_valid()) self.assertEqual(form.errors['myfile'], ['Please either submit a file or check the clear checkbox, not both.']) - rendered = unicode(form) + rendered = six.text_type(form) self.assertTrue('something.txt' in rendered) self.assertTrue('myfile-clear' in rendered) diff --git a/tests/regressiontests/model_formsets_regress/tests.py b/tests/regressiontests/model_formsets_regress/tests.py index 68ebe48bde..1fbdb9744f 100644 --- a/tests/regressiontests/model_formsets_regress/tests.py +++ b/tests/regressiontests/model_formsets_regress/tests.py @@ -5,6 +5,7 @@ from django.forms.formsets import BaseFormSet, DELETION_FIELD_NAME from django.forms.util import ErrorDict, ErrorList from django.forms.models import modelform_factory, inlineformset_factory, modelformset_factory, BaseModelFormSet from django.test import TestCase +from django.utils import six from .models import User, UserSite, Restaurant, Manager, Network, Host @@ -51,7 +52,7 @@ class InlineFormsetTests(TestCase): 'usersite_set-TOTAL_FORMS': '1', 'usersite_set-INITIAL_FORMS': '1', 'usersite_set-MAX_NUM_FORMS': '0', - 'usersite_set-0-id': unicode(usersite[0]['id']), + 'usersite_set-0-id': six.text_type(usersite[0]['id']), 'usersite_set-0-data': '11', 'usersite_set-0-user': 'apollo13' } @@ -69,7 +70,7 @@ class InlineFormsetTests(TestCase): 'usersite_set-TOTAL_FORMS': '2', 'usersite_set-INITIAL_FORMS': '1', 'usersite_set-MAX_NUM_FORMS': '0', - 'usersite_set-0-id': unicode(usersite[0]['id']), + 'usersite_set-0-id': six.text_type(usersite[0]['id']), 'usersite_set-0-data': '11', 'usersite_set-0-user': 'apollo13', 'usersite_set-1-data': '42', @@ -124,7 +125,7 @@ class InlineFormsetTests(TestCase): 'manager_set-TOTAL_FORMS': '1', 'manager_set-INITIAL_FORMS': '1', 'manager_set-MAX_NUM_FORMS': '0', - 'manager_set-0-id': unicode(manager[0]['id']), + 'manager_set-0-id': six.text_type(manager[0]['id']), 'manager_set-0-name': 'Terry Gilliam' } form_set = FormSet(data, instance=restaurant) @@ -140,7 +141,7 @@ class InlineFormsetTests(TestCase): 'manager_set-TOTAL_FORMS': '2', 'manager_set-INITIAL_FORMS': '1', 'manager_set-MAX_NUM_FORMS': '0', - 'manager_set-0-id': unicode(manager[0]['id']), + 'manager_set-0-id': six.text_type(manager[0]['id']), 'manager_set-0-name': 'Terry Gilliam', 'manager_set-1-name': 'John Cleese' } @@ -188,7 +189,7 @@ class InlineFormsetTests(TestCase): 'host_set-TOTAL_FORMS': '2', 'host_set-INITIAL_FORMS': '1', 'host_set-MAX_NUM_FORMS': '0', - 'host_set-0-id': unicode(host1.id), + 'host_set-0-id': six.text_type(host1.id), 'host_set-0-hostname': 'tranquility.hub.dal.net', 'host_set-1-hostname': 'matrix.de.eu.dal.net' } diff --git a/tests/regressiontests/model_regress/tests.py b/tests/regressiontests/model_regress/tests.py index 7f9f514c7a..6a45a83052 100644 --- a/tests/regressiontests/model_regress/tests.py +++ b/tests/regressiontests/model_regress/tests.py @@ -5,6 +5,7 @@ from operator import attrgetter from django.core.exceptions import ValidationError from django.test import TestCase, skipUnlessDBFeature +from django.utils import six from django.utils import tzinfo from .models import (Worker, Article, Party, Event, Department, @@ -38,7 +39,7 @@ class ModelTests(TestCase): # Empty strings should be returned as Unicode a = Article.objects.get(pk=a.pk) self.assertEqual(a.misc_data, '') - self.assertIs(type(a.misc_data), unicode) + self.assertIs(type(a.misc_data), six.text_type) def test_long_textfield(self): # TextFields can hold more than 4000 characters (this was broken in @@ -138,7 +139,7 @@ class ModelTests(TestCase): # Check Department and Worker (non-default PK type) d = Department.objects.create(id=10, name="IT") w = Worker.objects.create(department=d, name="Full-time") - self.assertEqual(unicode(w), "Full-time") + self.assertEqual(six.text_type(w), "Full-time") def test_broken_unicode(self): # Models with broken unicode methods should still have a printable repr diff --git a/tests/regressiontests/queries/models.py b/tests/regressiontests/queries/models.py index 8c34b50e93..6328776e91 100644 --- a/tests/regressiontests/queries/models.py +++ b/tests/regressiontests/queries/models.py @@ -6,6 +6,7 @@ from __future__ import unicode_literals import threading from django.db import models +from django.utils import six class DumbCategory(models.Model): @@ -122,7 +123,7 @@ class Number(models.Model): num = models.IntegerField() def __unicode__(self): - return unicode(self.num) + return six.text_type(self.num) # Symmetrical m2m field with a normal field using the reverse accesor name # ("valid"). diff --git a/tests/regressiontests/queries/tests.py b/tests/regressiontests/queries/tests.py index 4cc7208a96..1582993dfc 100644 --- a/tests/regressiontests/queries/tests.py +++ b/tests/regressiontests/queries/tests.py @@ -10,6 +10,8 @@ from django.core.exceptions import FieldError from django.db import DatabaseError, connection, connections, DEFAULT_DB_ALIAS from django.db.models import Count from django.db.models.query import Q, ITER_CHUNK_SIZE, EmptyQuerySet +from django.db.models.sql.where import WhereNode, EverythingNode, NothingNode +from django.db.models.sql.datastructures import EmptyResultSet from django.test import TestCase, skipUnlessDBFeature from django.test.utils import str_prefix from django.utils import unittest @@ -1316,10 +1318,23 @@ class Queries5Tests(TestCase): ) def test_ticket5261(self): + # Test different empty excludes. self.assertQuerysetEqual( Note.objects.exclude(Q()), ['<Note: n1>', '<Note: n2>'] ) + self.assertQuerysetEqual( + Note.objects.filter(~Q()), + ['<Note: n1>', '<Note: n2>'] + ) + self.assertQuerysetEqual( + Note.objects.filter(~Q()|~Q()), + ['<Note: n1>', '<Note: n2>'] + ) + self.assertQuerysetEqual( + Note.objects.exclude(~Q()&~Q()), + ['<Note: n1>', '<Note: n2>'] + ) class SelectRelatedTests(TestCase): @@ -1864,8 +1879,7 @@ class ConditionalTests(BaseQuerysetTest): # Test that the "in" lookup works with lists of 1000 items or more. Number.objects.all().delete() numbers = range(2500) - for num in numbers: - _ = Number.objects.create(num=num) + Number.objects.bulk_create(Number(num=num) for num in numbers) self.assertEqual( Number.objects.filter(num__in=numbers[:1000]).count(), 1000 @@ -2020,3 +2034,74 @@ class ProxyQueryCleanupTest(TestCase): self.assertEqual(qs.count(), 1) str(qs.query) self.assertEqual(qs.count(), 1) + +class WhereNodeTest(TestCase): + class DummyNode(object): + def as_sql(self, qn, connection): + return 'dummy', [] + + def test_empty_full_handling_conjunction(self): + qn = connection.ops.quote_name + w = WhereNode(children=[EverythingNode()]) + self.assertEquals(w.as_sql(qn, connection), ('', [])) + w.negate() + self.assertRaises(EmptyResultSet, w.as_sql, qn, connection) + w = WhereNode(children=[NothingNode()]) + self.assertRaises(EmptyResultSet, w.as_sql, qn, connection) + w.negate() + self.assertEquals(w.as_sql(qn, connection), ('', [])) + w = WhereNode(children=[EverythingNode(), EverythingNode()]) + self.assertEquals(w.as_sql(qn, connection), ('', [])) + w.negate() + self.assertRaises(EmptyResultSet, w.as_sql, qn, connection) + w = WhereNode(children=[EverythingNode(), self.DummyNode()]) + self.assertEquals(w.as_sql(qn, connection), ('dummy', [])) + w = WhereNode(children=[self.DummyNode(), self.DummyNode()]) + self.assertEquals(w.as_sql(qn, connection), ('(dummy AND dummy)', [])) + w.negate() + self.assertEquals(w.as_sql(qn, connection), ('NOT (dummy AND dummy)', [])) + w = WhereNode(children=[NothingNode(), self.DummyNode()]) + self.assertRaises(EmptyResultSet, w.as_sql, qn, connection) + w.negate() + self.assertEquals(w.as_sql(qn, connection), ('', [])) + + def test_empty_full_handling_disjunction(self): + qn = connection.ops.quote_name + w = WhereNode(children=[EverythingNode()], connector='OR') + self.assertEquals(w.as_sql(qn, connection), ('', [])) + w.negate() + self.assertRaises(EmptyResultSet, w.as_sql, qn, connection) + w = WhereNode(children=[NothingNode()], connector='OR') + self.assertRaises(EmptyResultSet, w.as_sql, qn, connection) + w.negate() + self.assertEquals(w.as_sql(qn, connection), ('', [])) + w = WhereNode(children=[EverythingNode(), EverythingNode()], connector='OR') + self.assertEquals(w.as_sql(qn, connection), ('', [])) + w.negate() + self.assertRaises(EmptyResultSet, w.as_sql, qn, connection) + w = WhereNode(children=[EverythingNode(), self.DummyNode()], connector='OR') + self.assertEquals(w.as_sql(qn, connection), ('', [])) + w.negate() + self.assertRaises(EmptyResultSet, w.as_sql, qn, connection) + w = WhereNode(children=[self.DummyNode(), self.DummyNode()], connector='OR') + self.assertEquals(w.as_sql(qn, connection), ('(dummy OR dummy)', [])) + w.negate() + self.assertEquals(w.as_sql(qn, connection), ('NOT (dummy OR dummy)', [])) + w = WhereNode(children=[NothingNode(), self.DummyNode()], connector='OR') + self.assertEquals(w.as_sql(qn, connection), ('dummy', [])) + w.negate() + self.assertEquals(w.as_sql(qn, connection), ('NOT (dummy)', [])) + + def test_empty_nodes(self): + qn = connection.ops.quote_name + empty_w = WhereNode() + w = WhereNode(children=[empty_w, empty_w]) + self.assertEquals(w.as_sql(qn, connection), (None, [])) + w.negate() + self.assertEquals(w.as_sql(qn, connection), (None, [])) + w.connector = 'OR' + self.assertEquals(w.as_sql(qn, connection), (None, [])) + w.negate() + self.assertEquals(w.as_sql(qn, connection), (None, [])) + w = WhereNode(children=[empty_w, NothingNode()], connector='OR') + self.assertRaises(EmptyResultSet, w.as_sql, qn, connection) diff --git a/tests/regressiontests/queryset_pickle/tests.py b/tests/regressiontests/queryset_pickle/tests.py index f73e61a900..ab32e8f647 100644 --- a/tests/regressiontests/queryset_pickle/tests.py +++ b/tests/regressiontests/queryset_pickle/tests.py @@ -36,3 +36,13 @@ class PickleabilityTestCase(TestCase): def test_membermethod_as_default(self): self.assert_pickles(Happening.objects.filter(number4=1)) + + def test_doesnotexist_exception(self): + # Ticket #17776 + original = Event.DoesNotExist("Doesn't exist") + unpickled = pickle.loads(pickle.dumps(original)) + + # Exceptions are not equal to equivalent instances of themselves, so + # can't just use assertEqual(original, unpickled) + self.assertEqual(original.__class__, unpickled.__class__) + self.assertEqual(original.args, unpickled.args) diff --git a/tests/regressiontests/select_related_regress/tests.py b/tests/regressiontests/select_related_regress/tests.py index e35157dbaf..7f93a1c33c 100644 --- a/tests/regressiontests/select_related_regress/tests.py +++ b/tests/regressiontests/select_related_regress/tests.py @@ -1,6 +1,7 @@ from __future__ import absolute_import, unicode_literals from django.test import TestCase +from django.utils import six from .models import (Building, Child, Device, Port, Item, Country, Connection, ClientStatus, State, Client, SpecialClient, TUser, Person, Student, @@ -33,11 +34,11 @@ class SelectRelatedRegressTests(TestCase): c2=Connection.objects.create(start=port2, end=port3) connections=Connection.objects.filter(start__device__building=b, end__device__building=b).order_by('id') - self.assertEqual([(c.id, unicode(c.start), unicode(c.end)) for c in connections], + self.assertEqual([(c.id, six.text_type(c.start), six.text_type(c.end)) for c in connections], [(c1.id, 'router/4', 'switch/7'), (c2.id, 'switch/7', 'server/1')]) connections=Connection.objects.filter(start__device__building=b, end__device__building=b).select_related().order_by('id') - self.assertEqual([(c.id, unicode(c.start), unicode(c.end)) for c in connections], + self.assertEqual([(c.id, six.text_type(c.start), six.text_type(c.end)) for c in connections], [(c1.id, 'router/4', 'switch/7'), (c2.id, 'switch/7', 'server/1')]) # This final query should only have seven tables (port, device and building @@ -133,7 +134,7 @@ class SelectRelatedRegressTests(TestCase): self.assertEqual(troy.state.name, 'Western Australia') # Also works if you use only, rather than defer - troy = SpecialClient.objects.select_related('state').only('name').get(name='Troy Buswell') + troy = SpecialClient.objects.select_related('state').only('name', 'state').get(name='Troy Buswell') self.assertEqual(troy.name, 'Troy Buswell') self.assertEqual(troy.value, 42) diff --git a/tests/regressiontests/serializers_regress/tests.py b/tests/regressiontests/serializers_regress/tests.py index f1b70a1d2e..4e73be015c 100644 --- a/tests/regressiontests/serializers_regress/tests.py +++ b/tests/regressiontests/serializers_regress/tests.py @@ -21,6 +21,7 @@ from django.core import serializers from django.core.serializers import SerializerDoesNotExist from django.core.serializers.base import DeserializationError from django.db import connection, models +from django.http import HttpResponse from django.test import TestCase from django.utils.functional import curry from django.utils.unittest import skipUnless @@ -501,15 +502,18 @@ def streamTest(format, self): obj.save_base(raw=True) # Serialize the test database to a stream - stream = BytesIO() - serializers.serialize(format, [obj], indent=2, stream=stream) + for stream in (BytesIO(), HttpResponse()): + serializers.serialize(format, [obj], indent=2, stream=stream) - # Serialize normally for a comparison - string_data = serializers.serialize(format, [obj], indent=2) + # Serialize normally for a comparison + string_data = serializers.serialize(format, [obj], indent=2) - # Check that the two are the same - self.assertEqual(string_data, stream.getvalue()) - stream.close() + # Check that the two are the same + if isinstance(stream, BytesIO): + self.assertEqual(string_data, stream.getvalue()) + else: + self.assertEqual(string_data, stream.content) + stream.close() for format in serializers.get_serializer_formats(): setattr(SerializerTests, 'test_' + format + '_serializer', curry(serializerTest, format)) diff --git a/tests/regressiontests/servers/tests.py b/tests/regressiontests/servers/tests.py index 9537e1feb3..b98b4b73c2 100644 --- a/tests/regressiontests/servers/tests.py +++ b/tests/regressiontests/servers/tests.py @@ -2,7 +2,10 @@ Tests for django.core.servers. """ import os -import urllib2 +try: + from urllib.request import urlopen, HTTPError +except ImportError: # Python 2 + from urllib2 import urlopen, HTTPError from django.core.exceptions import ImproperlyConfigured from django.test import LiveServerTestCase @@ -39,7 +42,7 @@ class LiveServerBase(LiveServerTestCase): super(LiveServerBase, cls).tearDownClass() def urlopen(self, url): - return urllib2.urlopen(self.live_server_url + url) + return urlopen(self.live_server_url + url) class LiveServerAddress(LiveServerBase): @@ -102,7 +105,7 @@ class LiveServerViews(LiveServerBase): """ try: self.urlopen('/') - except urllib2.HTTPError as err: + except HTTPError as err: self.assertEqual(err.code, 404, 'Expected 404 response') else: self.fail('Expected 404 response') diff --git a/tests/regressiontests/staticfiles_tests/apps/test/static/test/nonascii.css b/tests/regressiontests/staticfiles_tests/apps/test/static/test/nonascii.css new file mode 100644 index 0000000000..a5358f6ede --- /dev/null +++ b/tests/regressiontests/staticfiles_tests/apps/test/static/test/nonascii.css @@ -0,0 +1,5 @@ +body { + background: url('window.png'); +} + +.snowman:before { content: "☃"; } diff --git a/tests/regressiontests/staticfiles_tests/apps/test/static/test/window.png b/tests/regressiontests/staticfiles_tests/apps/test/static/test/window.png Binary files differnew file mode 100644 index 0000000000..ba48325c0a --- /dev/null +++ b/tests/regressiontests/staticfiles_tests/apps/test/static/test/window.png diff --git a/tests/regressiontests/staticfiles_tests/project/documents/cached/css/ignored.css b/tests/regressiontests/staticfiles_tests/project/documents/cached/css/ignored.css new file mode 100644 index 0000000000..fe7b022215 --- /dev/null +++ b/tests/regressiontests/staticfiles_tests/project/documents/cached/css/ignored.css @@ -0,0 +1,8 @@ +body { + background: url("#foobar"); + background: url("http:foobar"); + background: url("https:foobar"); + background: url("data:foobar"); + background: url("//foobar"); +} + diff --git a/tests/regressiontests/staticfiles_tests/project/documents/cached/import.css b/tests/regressiontests/staticfiles_tests/project/documents/cached/import.css new file mode 100644 index 0000000000..6bc7ce04c4 --- /dev/null +++ b/tests/regressiontests/staticfiles_tests/project/documents/cached/import.css @@ -0,0 +1 @@ +@import 'styles.css'; diff --git a/tests/regressiontests/staticfiles_tests/tests.py b/tests/regressiontests/staticfiles_tests/tests.py index 8321fc2365..2c038e1713 100644 --- a/tests/regressiontests/staticfiles_tests/tests.py +++ b/tests/regressiontests/staticfiles_tests/tests.py @@ -20,6 +20,7 @@ from django.test.utils import override_settings from django.utils.encoding import smart_unicode from django.utils.functional import empty from django.utils._os import rmtree_errorhandler +from django.utils import six from django.contrib.staticfiles import finders, storage @@ -53,6 +54,9 @@ class BaseStaticFilesTestCase(object): # since we're planning on changing that we need to clear out the cache. default_storage._wrapped = empty storage.staticfiles_storage._wrapped = empty + # Clear the cached staticfile finders, so they are reinitialized every + # run and pick up changes in settings.STATICFILES_DIRS. + finders._finders.clear() testfiles_path = os.path.join(TEST_ROOT, 'apps', 'test', 'static', 'test') # To make sure SVN doesn't hangs itself with the non-ASCII characters @@ -83,18 +87,20 @@ class BaseStaticFilesTestCase(object): self.assertRaises(IOError, self._get_file, filepath) def render_template(self, template, **kwargs): - if isinstance(template, basestring): + if isinstance(template, six.string_types): template = loader.get_template_from_string(template) return template.render(Context(kwargs)).strip() - def static_template_snippet(self, path): + def static_template_snippet(self, path, asvar=False): + if asvar: + return "{%% load static from staticfiles %%}{%% static '%s' as var %%}{{ var }}" % path return "{%% load static from staticfiles %%}{%% static '%s' %%}" % path - def assertStaticRenders(self, path, result, **kwargs): - template = self.static_template_snippet(path) + def assertStaticRenders(self, path, result, asvar=False, **kwargs): + template = self.static_template_snippet(path, asvar) self.assertEqual(self.render_template(template, **kwargs), result) - def assertStaticRaises(self, exc, path, result, **kwargs): + def assertStaticRaises(self, exc, path, result, asvar=False, **kwargs): self.assertRaises(exc, self.assertStaticRenders, path, result, **kwargs) @@ -368,6 +374,8 @@ class TestCollectionCachedStorage(BaseCollectionTestCase, "/static/does/not/exist.png") self.assertStaticRenders("test/file.txt", "/static/test/file.dad0999e4f8f.txt") + self.assertStaticRenders("test/file.txt", + "/static/test/file.dad0999e4f8f.txt", asvar=True) self.assertStaticRenders("cached/styles.css", "/static/cached/styles.93b1147e8552.css") self.assertStaticRenders("path/", @@ -383,6 +391,17 @@ class TestCollectionCachedStorage(BaseCollectionTestCase, self.assertNotIn(b"cached/other.css", content) self.assertIn(b"other.d41d8cd98f00.css", content) + def test_path_ignored_completely(self): + relpath = self.cached_file_path("cached/css/ignored.css") + self.assertEqual(relpath, "cached/css/ignored.6c77f2643390.css") + with storage.staticfiles_storage.open(relpath) as relfile: + content = relfile.read() + self.assertIn(b'#foobar', content) + self.assertIn(b'http:foobar', content) + self.assertIn(b'https:foobar', content) + self.assertIn(b'data:foobar', content) + self.assertIn(b'//foobar', content) + def test_path_with_querystring(self): relpath = self.cached_file_path("cached/styles.css?spam=eggs") self.assertEqual(relpath, @@ -442,6 +461,13 @@ class TestCollectionCachedStorage(BaseCollectionTestCase, self.assertIn(b'url("img/relative.acae32e4532b.png")', content) self.assertIn(b"../cached/styles.93b1147e8552.css", content) + def test_import_replacement(self): + "See #18050" + relpath = self.cached_file_path("cached/import.css") + self.assertEqual(relpath, "cached/import.2b1d40b0bbd4.css") + with storage.staticfiles_storage.open(relpath) as relfile: + self.assertIn(b"""import url("styles.93b1147e8552.css")""", relfile.read()) + def test_template_tag_deep_relative(self): relpath = self.cached_file_path("cached/css/window.css") self.assertEqual(relpath, "cached/css/window.9db38d5169f3.css") @@ -494,8 +520,9 @@ class TestCollectionCachedStorage(BaseCollectionTestCase, collectstatic_cmd = CollectstaticCommand() collectstatic_cmd.set_options(**collectstatic_args) stats = collectstatic_cmd.collect() - self.assertTrue(os.path.join('cached', 'css', 'window.css') in stats['post_processed']) - self.assertTrue(os.path.join('cached', 'css', 'img', 'window.png') in stats['unmodified']) + self.assertIn(os.path.join('cached', 'css', 'window.css'), stats['post_processed']) + self.assertIn(os.path.join('cached', 'css', 'img', 'window.png'), stats['unmodified']) + self.assertIn(os.path.join('test', 'nonascii.css'), stats['post_processed']) def test_cache_key_memcache_validation(self): """ diff --git a/tests/regressiontests/templates/templatetags/custom.py b/tests/regressiontests/templates/templatetags/custom.py index 7f788311c6..95fcd551de 100644 --- a/tests/regressiontests/templates/templatetags/custom.py +++ b/tests/regressiontests/templates/templatetags/custom.py @@ -3,6 +3,7 @@ import operator from django import template from django.template.defaultfilters import stringfilter from django.template.loader import get_template +from django.utils import six register = template.Library() @@ -56,13 +57,13 @@ simple_one_default.anything = "Expected simple_one_default __dict__" @register.simple_tag def simple_unlimited_args(one, two='hi', *args): """Expected simple_unlimited_args __doc__""" - return "simple_unlimited_args - Expected result: %s" % (', '.join([unicode(arg) for arg in [one, two] + list(args)])) + return "simple_unlimited_args - Expected result: %s" % (', '.join([six.text_type(arg) for arg in [one, two] + list(args)])) simple_unlimited_args.anything = "Expected simple_unlimited_args __dict__" @register.simple_tag def simple_only_unlimited_args(*args): """Expected simple_only_unlimited_args __doc__""" - return "simple_only_unlimited_args - Expected result: %s" % ', '.join([unicode(arg) for arg in args]) + return "simple_only_unlimited_args - Expected result: %s" % ', '.join([six.text_type(arg) for arg in args]) simple_only_unlimited_args.anything = "Expected simple_only_unlimited_args __dict__" @register.simple_tag @@ -71,7 +72,7 @@ def simple_unlimited_args_kwargs(one, two='hi', *args, **kwargs): # Sort the dictionary by key to guarantee the order for testing. sorted_kwarg = sorted(kwargs.iteritems(), key=operator.itemgetter(0)) return "simple_unlimited_args_kwargs - Expected result: %s / %s" % ( - ', '.join([unicode(arg) for arg in [one, two] + list(args)]), + ', '.join([six.text_type(arg) for arg in [one, two] + list(args)]), ', '.join(['%s=%s' % (k, v) for (k, v) in sorted_kwarg]) ) simple_unlimited_args_kwargs.anything = "Expected simple_unlimited_args_kwargs __dict__" @@ -183,25 +184,25 @@ inclusion_one_default_from_template.anything = "Expected inclusion_one_default_f @register.inclusion_tag('inclusion.html') def inclusion_unlimited_args(one, two='hi', *args): """Expected inclusion_unlimited_args __doc__""" - return {"result": "inclusion_unlimited_args - Expected result: %s" % (', '.join([unicode(arg) for arg in [one, two] + list(args)]))} + return {"result": "inclusion_unlimited_args - Expected result: %s" % (', '.join([six.text_type(arg) for arg in [one, two] + list(args)]))} inclusion_unlimited_args.anything = "Expected inclusion_unlimited_args __dict__" @register.inclusion_tag(get_template('inclusion.html')) def inclusion_unlimited_args_from_template(one, two='hi', *args): """Expected inclusion_unlimited_args_from_template __doc__""" - return {"result": "inclusion_unlimited_args_from_template - Expected result: %s" % (', '.join([unicode(arg) for arg in [one, two] + list(args)]))} + return {"result": "inclusion_unlimited_args_from_template - Expected result: %s" % (', '.join([six.text_type(arg) for arg in [one, two] + list(args)]))} inclusion_unlimited_args_from_template.anything = "Expected inclusion_unlimited_args_from_template __dict__" @register.inclusion_tag('inclusion.html') def inclusion_only_unlimited_args(*args): """Expected inclusion_only_unlimited_args __doc__""" - return {"result": "inclusion_only_unlimited_args - Expected result: %s" % (', '.join([unicode(arg) for arg in args]))} + return {"result": "inclusion_only_unlimited_args - Expected result: %s" % (', '.join([six.text_type(arg) for arg in args]))} inclusion_only_unlimited_args.anything = "Expected inclusion_only_unlimited_args __dict__" @register.inclusion_tag(get_template('inclusion.html')) def inclusion_only_unlimited_args_from_template(*args): """Expected inclusion_only_unlimited_args_from_template __doc__""" - return {"result": "inclusion_only_unlimited_args_from_template - Expected result: %s" % (', '.join([unicode(arg) for arg in args]))} + return {"result": "inclusion_only_unlimited_args_from_template - Expected result: %s" % (', '.join([six.text_type(arg) for arg in args]))} inclusion_only_unlimited_args_from_template.anything = "Expected inclusion_only_unlimited_args_from_template __dict__" @register.inclusion_tag('test_incl_tag_current_app.html', takes_context=True) @@ -222,7 +223,7 @@ def inclusion_unlimited_args_kwargs(one, two='hi', *args, **kwargs): # Sort the dictionary by key to guarantee the order for testing. sorted_kwarg = sorted(kwargs.iteritems(), key=operator.itemgetter(0)) return {"result": "inclusion_unlimited_args_kwargs - Expected result: %s / %s" % ( - ', '.join([unicode(arg) for arg in [one, two] + list(args)]), + ', '.join([six.text_type(arg) for arg in [one, two] + list(args)]), ', '.join(['%s=%s' % (k, v) for (k, v) in sorted_kwarg]) )} inclusion_unlimited_args_kwargs.anything = "Expected inclusion_unlimited_args_kwargs __dict__" @@ -278,13 +279,13 @@ assignment_one_default.anything = "Expected assignment_one_default __dict__" @register.assignment_tag def assignment_unlimited_args(one, two='hi', *args): """Expected assignment_unlimited_args __doc__""" - return "assignment_unlimited_args - Expected result: %s" % (', '.join([unicode(arg) for arg in [one, two] + list(args)])) + return "assignment_unlimited_args - Expected result: %s" % (', '.join([six.text_type(arg) for arg in [one, two] + list(args)])) assignment_unlimited_args.anything = "Expected assignment_unlimited_args __dict__" @register.assignment_tag def assignment_only_unlimited_args(*args): """Expected assignment_only_unlimited_args __doc__""" - return "assignment_only_unlimited_args - Expected result: %s" % ', '.join([unicode(arg) for arg in args]) + return "assignment_only_unlimited_args - Expected result: %s" % ', '.join([six.text_type(arg) for arg in args]) assignment_only_unlimited_args.anything = "Expected assignment_only_unlimited_args __dict__" @register.assignment_tag @@ -293,7 +294,7 @@ def assignment_unlimited_args_kwargs(one, two='hi', *args, **kwargs): # Sort the dictionary by key to guarantee the order for testing. sorted_kwarg = sorted(kwargs.iteritems(), key=operator.itemgetter(0)) return "assignment_unlimited_args_kwargs - Expected result: %s / %s" % ( - ', '.join([unicode(arg) for arg in [one, two] + list(args)]), + ', '.join([six.text_type(arg) for arg in [one, two] + list(args)]), ', '.join(['%s=%s' % (k, v) for (k, v) in sorted_kwarg]) ) assignment_unlimited_args_kwargs.anything = "Expected assignment_unlimited_args_kwargs __dict__" diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py index 989fd72d94..402cbb19d2 100644 --- a/tests/regressiontests/templates/tests.py +++ b/tests/regressiontests/templates/tests.py @@ -13,7 +13,10 @@ import time import os import sys import traceback -from urlparse import urljoin +try: + from urllib.parse import urljoin +except ImportError: # Python 2 + from urlparse import urljoin from django import template from django.template import base as template_base, RequestContext, Template, Context @@ -1616,6 +1619,8 @@ class Templates(unittest.TestCase): 'static-prefixtag04': ('{% load static %}{% get_media_prefix as media_prefix %}{{ media_prefix }}', {}, settings.MEDIA_URL), 'static-statictag01': ('{% load static %}{% static "admin/base.css" %}', {}, urljoin(settings.STATIC_URL, 'admin/base.css')), 'static-statictag02': ('{% load static %}{% static base_css %}', {'base_css': 'admin/base.css'}, urljoin(settings.STATIC_URL, 'admin/base.css')), + 'static-statictag03': ('{% load static %}{% static "admin/base.css" as foo %}{{ foo }}', {}, urljoin(settings.STATIC_URL, 'admin/base.css')), + 'static-statictag04': ('{% load static %}{% static base_css as foo %}{{ foo }}', {'base_css': 'admin/base.css'}, urljoin(settings.STATIC_URL, 'admin/base.css')), # Verbatim template tag outputs contents without rendering. 'verbatim-tag01': ('{% verbatim %}{{bare }}{% endverbatim %}', {}, '{{bare }}'), @@ -1623,7 +1628,7 @@ class Templates(unittest.TestCase): 'verbatim-tag03': ("{% verbatim %}It's the {% verbatim %} tag{% endverbatim %}", {}, "It's the {% verbatim %} tag"), 'verbatim-tag04': ('{% verbatim %}{% verbatim %}{% endverbatim %}{% endverbatim %}', {}, template.TemplateSyntaxError), 'verbatim-tag05': ('{% verbatim %}{% endverbatim %}{% verbatim %}{% endverbatim %}', {}, ''), - 'verbatim-tag06': ("{% verbatim -- %}Don't {% endverbatim %} just yet{% -- %}", {}, "Don't {% endverbatim %} just yet"), + 'verbatim-tag06': ("{% verbatim special %}Don't {% endverbatim %} just yet{% endverbatim special %}", {}, "Don't {% endverbatim %} just yet"), } return tests diff --git a/tests/regressiontests/templates/unicode.py b/tests/regressiontests/templates/unicode.py index 2c41176b01..7cb2a28d15 100644 --- a/tests/regressiontests/templates/unicode.py +++ b/tests/regressiontests/templates/unicode.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals from django.template import Template, TemplateEncodingError, Context from django.utils.safestring import SafeData +from django.utils import six from django.utils.unittest import TestCase @@ -27,5 +28,5 @@ class UnicodeTests(TestCase): # they all render the same (and are returned as unicode objects and # "safe" objects as well, for auto-escaping purposes). self.assertEqual(t1.render(c3), t2.render(c3)) - self.assertIsInstance(t1.render(c3), unicode) + self.assertIsInstance(t1.render(c3), six.text_type) self.assertIsInstance(t1.render(c3), SafeData) diff --git a/tests/regressiontests/test_client_regress/views.py b/tests/regressiontests/test_client_regress/views.py index 3a934ea047..8792a97dc0 100644 --- a/tests/regressiontests/test_client_regress/views.py +++ b/tests/regressiontests/test_client_regress/views.py @@ -84,7 +84,7 @@ def return_json_file(request): cls=DjangoJSONEncoder, ensure_ascii=False) response = HttpResponse(obj_json.encode(charset), status=200, - mimetype='application/json; charset=%s' % charset) + content_type='application/json; charset=%s' % charset) response['Content-Disposition'] = 'attachment; filename=testfile.json' return response diff --git a/tests/regressiontests/test_runner/tests.py b/tests/regressiontests/test_runner/tests.py index 8c6dabf771..c723f162a4 100644 --- a/tests/regressiontests/test_runner/tests.py +++ b/tests/regressiontests/test_runner/tests.py @@ -267,6 +267,9 @@ class AutoIncrementResetTest(TransactionTestCase): and check that both times they get "1" as their PK value. That is, we test that AutoField values start from 1 for each transactional test case. """ + + reset_sequences = True + @skipUnlessDBFeature('supports_sequence_reset') def test_autoincrement_reset1(self): p = Person.objects.create(first_name='Jack', last_name='Smith') diff --git a/tests/regressiontests/transactions_regress/tests.py b/tests/regressiontests/transactions_regress/tests.py index abd7a4ceaa..90b3df03d4 100644 --- a/tests/regressiontests/transactions_regress/tests.py +++ b/tests/regressiontests/transactions_regress/tests.py @@ -1,11 +1,11 @@ from __future__ import absolute_import from django.core.exceptions import ImproperlyConfigured -from django.db import connection, transaction +from django.db import connection, connections, transaction, DEFAULT_DB_ALIAS from django.db.transaction import commit_on_success, commit_manually, TransactionManagementError from django.test import TransactionTestCase, skipUnlessDBFeature from django.test.utils import override_settings -from django.utils.unittest import skipIf +from django.utils.unittest import skipIf, skipUnless from .models import Mod, M2mA, M2mB @@ -175,6 +175,59 @@ class TestTransactionClosing(TransactionTestCase): self.test_failing_query_transaction_closed() +@skipUnless(connection.vendor == 'postgresql', + "This test only valid for PostgreSQL") +class TestPostgresAutocommit(TransactionTestCase): + """ + Tests to make sure psycopg2's autocommit mode is restored after entering + and leaving transaction management. Refs #16047. + """ + def setUp(self): + from psycopg2.extensions import (ISOLATION_LEVEL_AUTOCOMMIT, + ISOLATION_LEVEL_READ_COMMITTED) + self._autocommit = ISOLATION_LEVEL_AUTOCOMMIT + self._read_committed = ISOLATION_LEVEL_READ_COMMITTED + + # We want a clean backend with autocommit = True, so + # first we need to do a bit of work to have that. + self._old_backend = connections[DEFAULT_DB_ALIAS] + settings = self._old_backend.settings_dict.copy() + opts = settings['OPTIONS'].copy() + opts['autocommit'] = True + settings['OPTIONS'] = opts + new_backend = self._old_backend.__class__(settings, DEFAULT_DB_ALIAS) + connections[DEFAULT_DB_ALIAS] = new_backend + + def tearDown(self): + connections[DEFAULT_DB_ALIAS] = self._old_backend + + def test_initial_autocommit_state(self): + self.assertTrue(connection.features.uses_autocommit) + self.assertEqual(connection.isolation_level, self._autocommit) + + def test_transaction_management(self): + transaction.enter_transaction_management() + transaction.managed(True) + self.assertEqual(connection.isolation_level, self._read_committed) + + transaction.leave_transaction_management() + self.assertEqual(connection.isolation_level, self._autocommit) + + def test_transaction_stacking(self): + transaction.enter_transaction_management() + transaction.managed(True) + self.assertEqual(connection.isolation_level, self._read_committed) + + transaction.enter_transaction_management() + self.assertEqual(connection.isolation_level, self._read_committed) + + transaction.leave_transaction_management() + self.assertEqual(connection.isolation_level, self._read_committed) + + transaction.leave_transaction_management() + self.assertEqual(connection.isolation_level, self._autocommit) + + class TestManyToManyAddTransaction(TransactionTestCase): def test_manyrelated_add_commit(self): "Test for https://code.djangoproject.com/ticket/16818" diff --git a/tests/regressiontests/urlpatterns_reverse/erroneous_urls.py b/tests/regressiontests/urlpatterns_reverse/erroneous_urls.py index 8e6433e16e..d1e4f3db5d 100644 --- a/tests/regressiontests/urlpatterns_reverse/erroneous_urls.py +++ b/tests/regressiontests/urlpatterns_reverse/erroneous_urls.py @@ -11,4 +11,6 @@ urlpatterns = patterns('', url(r'uncallable/$', 'regressiontests.urlpatterns_reverse.views.uncallable'), # Module does not exist url(r'missing_outer/$', 'regressiontests.urlpatterns_reverse.missing_module.missing_view'), + # Regex contains an error (refs #6170) + url(r'(regex_error/$', 'regressiontestes.urlpatterns_reverse.views.empty_view'), ) diff --git a/tests/regressiontests/urlpatterns_reverse/tests.py b/tests/regressiontests/urlpatterns_reverse/tests.py index bb25806830..500a0e0327 100644 --- a/tests/regressiontests/urlpatterns_reverse/tests.py +++ b/tests/regressiontests/urlpatterns_reverse/tests.py @@ -511,3 +511,11 @@ class ErroneousViewTests(TestCase): self.assertRaises(ViewDoesNotExist, self.client.get, '/missing_outer/') self.assertRaises(ViewDoesNotExist, self.client.get, '/uncallable/') + def test_erroneous_reverse(self): + """ + Ensure that a useful exception is raised when a regex is invalid in the + URLConf. + Refs #6170. + """ + # The regex error will be hit before NoReverseMatch can be raised + self.assertRaises(ImproperlyConfigured, reverse, 'whatever blah blah') diff --git a/tests/regressiontests/utils/datastructures.py b/tests/regressiontests/utils/datastructures.py index 000f7f76a1..dbc65d37a8 100644 --- a/tests/regressiontests/utils/datastructures.py +++ b/tests/regressiontests/utils/datastructures.py @@ -4,10 +4,12 @@ Tests for stuff in django.utils.datastructures. import copy import pickle +import warnings from django.test import SimpleTestCase -from django.utils.datastructures import (DictWrapper, DotExpandedDict, - ImmutableList, MultiValueDict, MultiValueDictKeyError, MergeDict, SortedDict) +from django.utils.datastructures import (DictWrapper, ImmutableList, + MultiValueDict, MultiValueDictKeyError, MergeDict, SortedDict) +from django.utils import six class SortedDictTests(SimpleTestCase): @@ -24,19 +26,19 @@ class SortedDictTests(SimpleTestCase): self.d2[7] = 'seven' def test_basic_methods(self): - self.assertEqual(self.d1.keys(), [7, 1, 9]) - self.assertEqual(self.d1.values(), ['seven', 'one', 'nine']) - self.assertEqual(self.d1.items(), [(7, 'seven'), (1, 'one'), (9, 'nine')]) + self.assertEqual(list(six.iterkeys(self.d1)), [7, 1, 9]) + self.assertEqual(list(six.itervalues(self.d1)), ['seven', 'one', 'nine']) + self.assertEqual(list(six.iteritems(self.d1)), [(7, 'seven'), (1, 'one'), (9, 'nine')]) def test_overwrite_ordering(self): - """ Overwriting an item keeps it's place. """ + """ Overwriting an item keeps its place. """ self.d1[1] = 'ONE' - self.assertEqual(self.d1.values(), ['seven', 'ONE', 'nine']) + self.assertEqual(list(six.itervalues(self.d1)), ['seven', 'ONE', 'nine']) def test_append_items(self): """ New items go to the end. """ self.d1[0] = 'nil' - self.assertEqual(self.d1.keys(), [7, 1, 9, 0]) + self.assertEqual(list(six.iterkeys(self.d1)), [7, 1, 9, 0]) def test_delete_and_insert(self): """ @@ -44,18 +46,22 @@ class SortedDictTests(SimpleTestCase): at the end. """ del self.d2[7] - self.assertEqual(self.d2.keys(), [1, 9, 0]) + self.assertEqual(list(six.iterkeys(self.d2)), [1, 9, 0]) self.d2[7] = 'lucky number 7' - self.assertEqual(self.d2.keys(), [1, 9, 0, 7]) + self.assertEqual(list(six.iterkeys(self.d2)), [1, 9, 0, 7]) - def test_change_keys(self): - """ - Changing the keys won't do anything, it's only a copy of the - keys dict. - """ - k = self.d2.keys() - k.remove(9) - self.assertEqual(self.d2.keys(), [1, 9, 0, 7]) + if not six.PY3: + def test_change_keys(self): + """ + Changing the keys won't do anything, it's only a copy of the + keys dict. + + This test doesn't make sense under Python 3 because keys is + an iterator. + """ + k = self.d2.keys() + k.remove(9) + self.assertEqual(self.d2.keys(), [1, 9, 0, 7]) def test_init_keys(self): """ @@ -67,18 +73,18 @@ class SortedDictTests(SimpleTestCase): tuples = ((2, 'two'), (1, 'one'), (2, 'second-two')) d = SortedDict(tuples) - self.assertEqual(d.keys(), [2, 1]) + self.assertEqual(list(six.iterkeys(d)), [2, 1]) real_dict = dict(tuples) - self.assertEqual(sorted(real_dict.values()), ['one', 'second-two']) + self.assertEqual(sorted(six.itervalues(real_dict)), ['one', 'second-two']) # Here the order of SortedDict values *is* what we are testing - self.assertEqual(d.values(), ['second-two', 'one']) + self.assertEqual(list(six.itervalues(d)), ['second-two', 'one']) def test_overwrite(self): self.d1[1] = 'not one' self.assertEqual(self.d1[1], 'not one') - self.assertEqual(self.d1.keys(), self.d1.copy().keys()) + self.assertEqual(list(six.iterkeys(self.d1)), list(six.iterkeys(self.d1.copy()))) def test_append(self): self.d1[13] = 'thirteen' @@ -98,7 +104,7 @@ class SortedDictTests(SimpleTestCase): self.assertEqual(l - len(self.d1), 1) def test_dict_equality(self): - d = SortedDict((i, i) for i in xrange(3)) + d = SortedDict((i, i) for i in range(3)) self.assertEqual(d, {0: 0, 1: 1, 2: 2}) def test_tuple_init(self): @@ -114,14 +120,29 @@ class SortedDictTests(SimpleTestCase): def test_copy(self): orig = SortedDict(((1, "one"), (0, "zero"), (2, "two"))) copied = copy.copy(orig) - self.assertEqual(orig.keys(), [1, 0, 2]) - self.assertEqual(copied.keys(), [1, 0, 2]) + self.assertEqual(list(six.iterkeys(orig)), [1, 0, 2]) + self.assertEqual(list(six.iterkeys(copied)), [1, 0, 2]) def test_clear(self): self.d1.clear() self.assertEqual(self.d1, {}) self.assertEqual(self.d1.keyOrder, []) + def test_insert(self): + d = SortedDict() + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + d.insert(0, "hello", "world") + assert w[0].category is PendingDeprecationWarning + + def test_value_for_index(self): + d = SortedDict({"a": 3}) + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + self.assertEqual(d.value_for_index(0), 3) + assert w[0].category is PendingDeprecationWarning + + class MergeDictTests(SimpleTestCase): def test_simple_mergedict(self): @@ -162,12 +183,12 @@ class MergeDictTests(SimpleTestCase): self.assertEqual(mm.getlist('key4'), ['value5', 'value6']) self.assertEqual(mm.getlist('undefined'), []) - self.assertEqual(sorted(mm.keys()), ['key1', 'key2', 'key4']) - self.assertEqual(len(mm.values()), 3) + self.assertEqual(sorted(six.iterkeys(mm)), ['key1', 'key2', 'key4']) + self.assertEqual(len(list(six.itervalues(mm))), 3) - self.assertTrue('value1' in mm.values()) + self.assertTrue('value1' in six.itervalues(mm)) - self.assertEqual(sorted(mm.items(), key=lambda k: k[0]), + self.assertEqual(sorted(six.iteritems(mm), key=lambda k: k[0]), [('key1', 'value1'), ('key2', 'value3'), ('key4', 'value6')]) @@ -185,10 +206,10 @@ class MultiValueDictTests(SimpleTestCase): self.assertEqual(d['name'], 'Simon') self.assertEqual(d.get('name'), 'Simon') self.assertEqual(d.getlist('name'), ['Adrian', 'Simon']) - self.assertEqual(list(d.iteritems()), + self.assertEqual(list(six.iteritems(d)), [('position', 'Developer'), ('name', 'Simon')]) - self.assertEqual(list(d.iterlists()), + self.assertEqual(list(six.iterlists(d)), [('position', ['Developer']), ('name', ['Adrian', 'Simon'])]) @@ -208,8 +229,7 @@ class MultiValueDictTests(SimpleTestCase): d.setlist('lastname', ['Holovaty', 'Willison']) self.assertEqual(d.getlist('lastname'), ['Holovaty', 'Willison']) - self.assertEqual(d.values(), ['Developer', 'Simon', 'Willison']) - self.assertEqual(list(d.itervalues()), + self.assertEqual(list(six.itervalues(d)), ['Developer', 'Simon', 'Willison']) def test_appendlist(self): @@ -244,27 +264,13 @@ class MultiValueDictTests(SimpleTestCase): 'pm': ['Rory'], }) d = mvd.dict() - self.assertEqual(d.keys(), mvd.keys()) - for key in mvd.keys(): + self.assertEqual(list(six.iterkeys(d)), list(six.iterkeys(mvd))) + for key in six.iterkeys(mvd): self.assertEqual(d[key], mvd[key]) self.assertEqual({}, MultiValueDict().dict()) -class DotExpandedDictTests(SimpleTestCase): - - def test_dotexpandeddict(self): - - d = DotExpandedDict({'person.1.firstname': ['Simon'], - 'person.1.lastname': ['Willison'], - 'person.2.firstname': ['Adrian'], - 'person.2.lastname': ['Holovaty']}) - - self.assertEqual(d['person']['1']['lastname'], ['Willison']) - self.assertEqual(d['person']['2']['lastname'], ['Holovaty']) - self.assertEqual(d['person']['2']['firstname'], ['Adrian']) - - class ImmutableListTests(SimpleTestCase): def test_sort(self): diff --git a/tests/regressiontests/utils/html.py b/tests/regressiontests/utils/html.py index 434873b9e0..fe40d4eaae 100644 --- a/tests/regressiontests/utils/html.py +++ b/tests/regressiontests/utils/html.py @@ -34,6 +34,17 @@ class TestUtilsHtml(unittest.TestCase): # Verify it doesn't double replace &. self.check_output(f, '<&', '<&') + def test_format_html(self): + self.assertEqual( + html.format_html("{0} {1} {third} {fourth}", + "< Dangerous >", + html.mark_safe("<b>safe</b>"), + third="< dangerous again", + fourth=html.mark_safe("<i>safe again</i>") + ), + "< Dangerous > <b>safe</b> < dangerous again <i>safe again</i>" + ) + def test_linebreaks(self): f = html.linebreaks items = ( diff --git a/tests/regressiontests/utils/simplelazyobject.py b/tests/regressiontests/utils/simplelazyobject.py index 982d2226e6..960a5e3201 100644 --- a/tests/regressiontests/utils/simplelazyobject.py +++ b/tests/regressiontests/utils/simplelazyobject.py @@ -4,6 +4,7 @@ import copy import pickle from django.test.utils import str_prefix +from django.utils import six from django.utils.unittest import TestCase from django.utils.functional import SimpleLazyObject, empty @@ -22,7 +23,7 @@ class _ComplexObject(object): return "I am _ComplexObject(%r)" % self.name def __unicode__(self): - return unicode(self.name) + return six.text_type(self.name) def __repr__(self): return "_ComplexObject(%r)" % self.name @@ -58,7 +59,7 @@ class TestUtilsSimpleLazyObject(TestCase): str(SimpleLazyObject(complex_object))) def test_unicode(self): - self.assertEqual("joe", unicode(SimpleLazyObject(complex_object))) + self.assertEqual("joe", six.text_type(SimpleLazyObject(complex_object))) def test_class(self): # This is important for classes that use __class__ in things like @@ -108,5 +109,5 @@ class TestUtilsSimpleLazyObject(TestCase): pickled = pickle.dumps(x) unpickled = pickle.loads(pickled) self.assertEqual(unpickled, x) - self.assertEqual(unicode(unpickled), unicode(x)) + self.assertEqual(six.text_type(unpickled), six.text_type(x)) self.assertEqual(unpickled.name, x.name) diff --git a/tests/regressiontests/utils/tests.py b/tests/regressiontests/utils/tests.py index f5ca06ef1e..a7deeeefae 100644 --- a/tests/regressiontests/utils/tests.py +++ b/tests/regressiontests/utils/tests.py @@ -16,7 +16,7 @@ from .decorators import DecoratorFromMiddlewareTests from .functional import FunctionalTestCase from .timesince import TimesinceTests from .datastructures import (MultiValueDictTests, SortedDictTests, - DictWrapperTests, ImmutableListTests, DotExpandedDictTests, MergeDictTests) + DictWrapperTests, ImmutableListTests, MergeDictTests) from .tzinfo import TzinfoTests from .datetime_safe import DatetimeTests from .baseconv import TestBaseConv diff --git a/tests/regressiontests/wsgi/tests.py b/tests/regressiontests/wsgi/tests.py index 9614a81c67..a482a5c1eb 100644 --- a/tests/regressiontests/wsgi/tests.py +++ b/tests/regressiontests/wsgi/tests.py @@ -6,6 +6,7 @@ from django.core.wsgi import get_wsgi_application from django.test import TestCase from django.test.client import RequestFactory from django.test.utils import override_settings +from django.utils import six from django.utils import unittest @@ -39,7 +40,7 @@ class WSGITest(TestCase): response_data["headers"], [('Content-Type', 'text/html; charset=utf-8')]) self.assertEqual( - unicode(response), + six.text_type(response), "Content-Type: text/html; charset=utf-8\n\nHello World!") diff --git a/tests/runtests.py b/tests/runtests.py index b71cf98b13..c548d2745b 100755 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -7,6 +7,7 @@ import tempfile import warnings from django import contrib +from django.utils import six # databrowse is deprecated, but we still want to run its tests warnings.filterwarnings('ignore', "The Databrowse contrib app is deprecated", @@ -142,7 +143,7 @@ def teardown(state): # so that it will successfully remove temp trees containing # non-ASCII filenames on Windows. (We're assuming the temp dir # name itself does not contain non-ASCII characters.) - shutil.rmtree(unicode(TEMP_DIR)) + shutil.rmtree(six.text_type(TEMP_DIR)) # Restore the old settings. for key, value in state.items(): setattr(settings, key, value) |
