diff options
author | django-bot <ops@djangoproject.com> | 2022-02-03 20:24:19 +0100 |
---|---|---|
committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2022-02-07 20:37:05 +0100 |
commit | 9c19aff7c7561e3a82978a272ecdaad40dda5c00 (patch) | |
tree | f0506b668a013d0063e5fba3dbf4863b466713ba /tests/model_fields | |
parent | f68fa8b45dfac545cfc4111d4e52804c86db68d3 (diff) | |
download | django-9c19aff7c7561e3a82978a272ecdaad40dda5c00.tar.gz |
Refs #33476 -- Reformatted code with Black.
Diffstat (limited to 'tests/model_fields')
22 files changed, 1078 insertions, 843 deletions
diff --git a/tests/model_fields/models.py b/tests/model_fields/models.py index 9e8baeb565..647916e360 100644 --- a/tests/model_fields/models.py +++ b/tests/model_fields/models.py @@ -3,9 +3,7 @@ import os import tempfile import uuid -from django.contrib.contenttypes.fields import ( - GenericForeignKey, GenericRelation, -) +from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation from django.contrib.contenttypes.models import ContentType from django.core.files.storage import FileSystemStorage from django.core.serializers.json import DjangoJSONEncoder @@ -30,23 +28,27 @@ def get_foo(): class Bar(models.Model): b = models.CharField(max_length=10) - a = models.ForeignKey(Foo, models.CASCADE, default=get_foo, related_name='bars') + a = models.ForeignKey(Foo, models.CASCADE, default=get_foo, related_name="bars") class Whiz(models.Model): CHOICES = ( - ('Group 1', ( - (1, 'First'), - (2, 'Second'), - ) + ( + "Group 1", + ( + (1, "First"), + (2, "Second"), + ), ), - ('Group 2', ( - (3, 'Third'), - (4, 'Fourth'), - ) + ( + "Group 2", + ( + (3, "Third"), + (4, "Fourth"), + ), ), - (0, 'Other'), - (5, _('translated')), + (0, "Other"), + (5, _("translated")), ) c = models.IntegerField(choices=CHOICES, null=True) @@ -56,7 +58,7 @@ class WhizDelayed(models.Model): # Contrived way of adding choices later. -WhizDelayed._meta.get_field('c').choices = Whiz.CHOICES +WhizDelayed._meta.get_field("c").choices = Whiz.CHOICES class WhizIter(models.Model): @@ -70,7 +72,7 @@ class WhizIterEmpty(models.Model): class Choiceful(models.Model): no_choices = models.IntegerField(null=True) empty_choices = models.IntegerField(choices=(), null=True) - with_choices = models.IntegerField(choices=[(1, 'A')], null=True) + with_choices = models.IntegerField(choices=[(1, "A")], null=True) empty_choices_bool = models.BooleanField(choices=()) empty_choices_text = models.TextField(choices=()) @@ -139,7 +141,7 @@ class NullBooleanModel(models.Model): class BooleanModel(models.Model): bfield = models.BooleanField() - string = models.CharField(max_length=10, default='abc') + string = models.CharField(max_length=10, default="abc") class DateTimeModel(models.Model): @@ -162,17 +164,19 @@ class PrimaryKeyCharModel(models.Model): class FksToBooleans(models.Model): """Model with FKs to models with {Null,}BooleanField's, #15040""" + bf = models.ForeignKey(BooleanModel, models.CASCADE) nbf = models.ForeignKey(NullBooleanModel, models.CASCADE) class FkToChar(models.Model): """Model with FK to a model with a CharField primary key, #19299""" + out = models.ForeignKey(PrimaryKeyCharModel, models.CASCADE) class RenamedField(models.Model): - modelname = models.IntegerField(name="fieldname", choices=((1, 'One'),)) + modelname = models.IntegerField(name="fieldname", choices=((1, "One"),)) class VerboseNameField(models.Model): @@ -203,7 +207,7 @@ class VerboseNameField(models.Model): class GenericIPAddress(models.Model): - ip = models.GenericIPAddressField(null=True, protocol='ipv4') + ip = models.GenericIPAddressField(null=True, protocol="ipv4") ############################################################################### @@ -219,19 +223,21 @@ class DecimalLessThanOne(models.Model): class FieldClassAttributeModel(models.Model): field_class = models.CharField + ############################################################################### class DataModel(models.Model): - short_data = models.BinaryField(max_length=10, default=b'\x08') + short_data = models.BinaryField(max_length=10, default=b"\x08") data = models.BinaryField() + ############################################################################### # FileField class Document(models.Model): - myfile = models.FileField(upload_to='unused', unique=True) + myfile = models.FileField(upload_to="unused", unique=True) ############################################################################### @@ -239,11 +245,13 @@ class Document(models.Model): # If Pillow available, do these tests. if Image: + class TestImageFieldFile(ImageFieldFile): """ Custom Field File class that records whether or not the underlying file was opened. """ + def __init__(self, *args, **kwargs): self.was_opened = False super().__init__(*args, **kwargs) @@ -258,14 +266,15 @@ if Image: # Set up a temp directory for file storage. temp_storage_dir = tempfile.mkdtemp() temp_storage = FileSystemStorage(temp_storage_dir) - temp_upload_to_dir = os.path.join(temp_storage.location, 'tests') + temp_upload_to_dir = os.path.join(temp_storage.location, "tests") class Person(models.Model): """ Model that defines an ImageField with no dimension fields. """ + name = models.CharField(max_length=50) - mugshot = TestImageField(storage=temp_storage, upload_to='tests') + mugshot = TestImageField(storage=temp_storage, upload_to="tests") class AbstractPersonWithHeight(models.Model): """ @@ -273,8 +282,10 @@ if Image: to make sure the dimension update is correctly run on concrete subclass instance post-initialization. """ - mugshot = TestImageField(storage=temp_storage, upload_to='tests', - height_field='mugshot_height') + + mugshot = TestImageField( + storage=temp_storage, upload_to="tests", height_field="mugshot_height" + ) mugshot_height = models.PositiveSmallIntegerField() class Meta: @@ -285,16 +296,21 @@ if Image: Concrete model that subclass an abstract one with only on dimension field. """ + name = models.CharField(max_length=50) class PersonWithHeightAndWidth(models.Model): """ Model that defines height and width fields after the ImageField. """ + name = models.CharField(max_length=50) - mugshot = TestImageField(storage=temp_storage, upload_to='tests', - height_field='mugshot_height', - width_field='mugshot_width') + mugshot = TestImageField( + storage=temp_storage, + upload_to="tests", + height_field="mugshot_height", + width_field="mugshot_width", + ) mugshot_height = models.PositiveSmallIntegerField() mugshot_width = models.PositiveSmallIntegerField() @@ -302,12 +318,16 @@ if Image: """ Model that defines height and width fields before the ImageField. """ + name = models.CharField(max_length=50) mugshot_height = models.PositiveSmallIntegerField() mugshot_width = models.PositiveSmallIntegerField() - mugshot = TestImageField(storage=temp_storage, upload_to='tests', - height_field='mugshot_height', - width_field='mugshot_width') + mugshot = TestImageField( + storage=temp_storage, + upload_to="tests", + height_field="mugshot_height", + width_field="mugshot_width", + ) class PersonTwoImages(models.Model): """ @@ -316,20 +336,26 @@ if Image: * Defines the height/width fields before the ImageFields * Has a nullable ImageField """ + name = models.CharField(max_length=50) mugshot_height = models.PositiveSmallIntegerField() mugshot_width = models.PositiveSmallIntegerField() - mugshot = TestImageField(storage=temp_storage, upload_to='tests', - height_field='mugshot_height', - width_field='mugshot_width') - headshot_height = models.PositiveSmallIntegerField( - blank=True, null=True) - headshot_width = models.PositiveSmallIntegerField( - blank=True, null=True) - headshot = TestImageField(blank=True, null=True, - storage=temp_storage, upload_to='tests', - height_field='headshot_height', - width_field='headshot_width') + mugshot = TestImageField( + storage=temp_storage, + upload_to="tests", + height_field="mugshot_height", + width_field="mugshot_width", + ) + headshot_height = models.PositiveSmallIntegerField(blank=True, null=True) + headshot_width = models.PositiveSmallIntegerField(blank=True, null=True) + headshot = TestImageField( + blank=True, + null=True, + storage=temp_storage, + upload_to="tests", + height_field="headshot_height", + width_field="headshot_width", + ) class CustomJSONDecoder(json.JSONDecoder): @@ -337,8 +363,8 @@ class CustomJSONDecoder(json.JSONDecoder): return super().__init__(object_hook=self.as_uuid, *args, **kwargs) def as_uuid(self, dct): - if 'uuid' in dct: - dct['uuid'] = uuid.UUID(dct['uuid']) + if "uuid" in dct: + dct["uuid"] = uuid.UUID(dct["uuid"]) return dct @@ -346,7 +372,7 @@ class JSONModel(models.Model): value = models.JSONField() class Meta: - required_db_features = {'supports_json_field'} + required_db_features = {"supports_json_field"} class NullableJSONModel(models.Model): @@ -358,7 +384,7 @@ class NullableJSONModel(models.Model): ) class Meta: - required_db_features = {'supports_json_field'} + required_db_features = {"supports_json_field"} class RelatedJSONModel(models.Model): @@ -366,7 +392,7 @@ class RelatedJSONModel(models.Model): json_model = models.ForeignKey(NullableJSONModel, models.CASCADE) class Meta: - required_db_features = {'supports_json_field'} + required_db_features = {"supports_json_field"} class AllFieldsModel(models.Model): @@ -393,19 +419,15 @@ class AllFieldsModel(models.Model): uuid = models.UUIDField() fo = models.ForeignObject( - 'self', + "self", on_delete=models.CASCADE, - from_fields=['positive_integer'], - to_fields=['id'], - related_name='reverse' - ) - fk = models.ForeignKey( - 'self', - models.CASCADE, - related_name='reverse2' + from_fields=["positive_integer"], + to_fields=["id"], + related_name="reverse", ) - m2m = models.ManyToManyField('self') - oto = models.OneToOneField('self', models.CASCADE) + fk = models.ForeignKey("self", models.CASCADE, related_name="reverse2") + m2m = models.ManyToManyField("self") + oto = models.OneToOneField("self", models.CASCADE) object_id = models.PositiveIntegerField() content_type = models.ForeignKey(ContentType, models.CASCADE) @@ -414,7 +436,7 @@ class AllFieldsModel(models.Model): class ManyToMany(models.Model): - m2m = models.ManyToManyField('self') + m2m = models.ManyToManyField("self") ############################################################################### @@ -433,7 +455,7 @@ class PrimaryKeyUUIDModel(models.Model): class RelatedToUUIDModel(models.Model): - uuid_fk = models.ForeignKey('PrimaryKeyUUIDModel', models.CASCADE) + uuid_fk = models.ForeignKey("PrimaryKeyUUIDModel", models.CASCADE) class UUIDChild(PrimaryKeyUUIDModel): diff --git a/tests/model_fields/test_autofield.py b/tests/model_fields/test_autofield.py index 0ae981c3d9..d2fe5d6125 100644 --- a/tests/model_fields/test_autofield.py +++ b/tests/model_fields/test_autofield.py @@ -3,7 +3,9 @@ from django.test import SimpleTestCase from .models import AutoModel, BigAutoModel, SmallAutoModel from .test_integerfield import ( - BigIntegerFieldTests, IntegerFieldTests, SmallIntegerFieldTests, + BigIntegerFieldTests, + IntegerFieldTests, + SmallIntegerFieldTests, ) @@ -23,7 +25,6 @@ class SmallAutoFieldTests(SmallIntegerFieldTests): class AutoFieldInheritanceTests(SimpleTestCase): - def test_isinstance_of_autofield(self): for field in (models.BigAutoField, models.SmallAutoField): with self.subTest(field.__name__): diff --git a/tests/model_fields/test_binaryfield.py b/tests/model_fields/test_binaryfield.py index 7796be70a6..05ebce3aab 100644 --- a/tests/model_fields/test_binaryfield.py +++ b/tests/model_fields/test_binaryfield.py @@ -6,10 +6,14 @@ from .models import DataModel class BinaryFieldTests(TestCase): - binary_data = b'\x00\x46\xFE' + binary_data = b"\x00\x46\xFE" def test_set_and_retrieve(self): - data_set = (self.binary_data, bytearray(self.binary_data), memoryview(self.binary_data)) + data_set = ( + self.binary_data, + bytearray(self.binary_data), + memoryview(self.binary_data), + ) for bdata in data_set: with self.subTest(data=repr(bdata)): dm = DataModel(data=bdata) @@ -21,7 +25,7 @@ class BinaryFieldTests(TestCase): dm = DataModel.objects.get(pk=dm.pk) self.assertEqual(bytes(dm.data), bytes(bdata)) # Test default value - self.assertEqual(bytes(dm.short_data), b'\x08') + self.assertEqual(bytes(dm.short_data), b"\x08") def test_max_length(self): dm = DataModel(short_data=self.binary_data * 4) @@ -38,15 +42,19 @@ class BinaryFieldTests(TestCase): def test_filter(self): dm = DataModel.objects.create(data=self.binary_data) - DataModel.objects.create(data=b'\xef\xbb\xbf') + DataModel.objects.create(data=b"\xef\xbb\xbf") self.assertSequenceEqual(DataModel.objects.filter(data=self.binary_data), [dm]) def test_filter_bytearray(self): dm = DataModel.objects.create(data=self.binary_data) - DataModel.objects.create(data=b'\xef\xbb\xbf') - self.assertSequenceEqual(DataModel.objects.filter(data=bytearray(self.binary_data)), [dm]) + DataModel.objects.create(data=b"\xef\xbb\xbf") + self.assertSequenceEqual( + DataModel.objects.filter(data=bytearray(self.binary_data)), [dm] + ) def test_filter_memoryview(self): dm = DataModel.objects.create(data=self.binary_data) - DataModel.objects.create(data=b'\xef\xbb\xbf') - self.assertSequenceEqual(DataModel.objects.filter(data=memoryview(self.binary_data)), [dm]) + DataModel.objects.create(data=b"\xef\xbb\xbf") + self.assertSequenceEqual( + DataModel.objects.filter(data=memoryview(self.binary_data)), [dm] + ) diff --git a/tests/model_fields/test_booleanfield.py b/tests/model_fields/test_booleanfield.py index 907385534b..91357b9b20 100644 --- a/tests/model_fields/test_booleanfield.py +++ b/tests/model_fields/test_booleanfield.py @@ -9,10 +9,10 @@ from .models import BooleanModel, FksToBooleans, NullBooleanModel class BooleanFieldTests(TestCase): def _test_get_prep_value(self, f): self.assertIs(f.get_prep_value(True), True) - self.assertIs(f.get_prep_value('1'), True) + self.assertIs(f.get_prep_value("1"), True) self.assertIs(f.get_prep_value(1), True) self.assertIs(f.get_prep_value(False), False) - self.assertIs(f.get_prep_value('0'), False) + self.assertIs(f.get_prep_value("0"), False) self.assertIs(f.get_prep_value(0), False) self.assertIsNone(f.get_prep_value(None)) @@ -37,7 +37,7 @@ class BooleanFieldTests(TestCase): BooleanField with choices and defaults doesn't generate a formfield with the blank option (#9640, #10549). """ - choices = [(1, 'Si'), (2, 'No')] + choices = [(1, "Si"), (2, "No")] f = models.BooleanField(choices=choices, default=1, null=False) self.assertEqual(f.formfield().choices, choices) @@ -46,9 +46,9 @@ class BooleanFieldTests(TestCase): BooleanField with choices and no default should generated a formfield with the blank option. """ - choices = [(1, 'Si'), (2, 'No')] + choices = [(1, "Si"), (2, "No")] f = models.BooleanField(choices=choices) - self.assertEqual(f.formfield().choices, [('', '---------')] + choices) + self.assertEqual(f.formfield().choices, [("", "---------")] + choices) def test_nullbooleanfield_formfield(self): f = models.BooleanField(null=True) @@ -73,7 +73,7 @@ class BooleanFieldTests(TestCase): # When an extra clause exists, the boolean conversions are applied with # an offset (#13293). - b5 = BooleanModel.objects.all().extra(select={'string_col': 'string'})[0] + b5 = BooleanModel.objects.all().extra(select={"string_col": "string"})[0] self.assertNotIsInstance(b5.pk, bool) def test_select_related(self): @@ -88,7 +88,7 @@ class BooleanFieldTests(TestCase): m2 = FksToBooleans.objects.create(bf=bmf, nbf=nbmf) # select_related('fk_field_name') - ma = FksToBooleans.objects.select_related('bf').get(pk=m1.id) + ma = FksToBooleans.objects.select_related("bf").get(pk=m1.id) self.assertIs(ma.bf.bfield, True) self.assertIs(ma.nbf.nbfield, True) @@ -104,7 +104,7 @@ class BooleanFieldTests(TestCase): """ A BooleanField defaults to None, which isn't a valid value (#15124). """ - boolean_field = BooleanModel._meta.get_field('bfield') + boolean_field = BooleanModel._meta.get_field("bfield") self.assertFalse(boolean_field.has_default()) b = BooleanModel() self.assertIsNone(b.bfield) @@ -118,7 +118,6 @@ class BooleanFieldTests(TestCase): class ValidationTest(SimpleTestCase): - def test_boolean_field_doesnt_accept_empty_input(self): f = models.BooleanField() with self.assertRaises(ValidationError): diff --git a/tests/model_fields/test_charfield.py b/tests/model_fields/test_charfield.py index 17c230c776..e9c1444f16 100644 --- a/tests/model_fields/test_charfield.py +++ b/tests/model_fields/test_charfield.py @@ -6,7 +6,6 @@ from .models import Post class TestCharField(TestCase): - def test_max_length_passed_to_formfield(self): """ CharField passes its max_length attribute to form fields created using @@ -21,22 +20,22 @@ class TestCharField(TestCase): self.assertEqual(Post.objects.filter(title=9).count(), 0) def test_emoji(self): - p = Post.objects.create(title='Smile 😀', body='Whatever.') + p = Post.objects.create(title="Smile 😀", body="Whatever.") p.refresh_from_db() - self.assertEqual(p.title, 'Smile 😀') + self.assertEqual(p.title, "Smile 😀") def test_assignment_from_choice_enum(self): class Event(models.TextChoices): - C = 'Carnival!' - F = 'Festival!' + C = "Carnival!" + F = "Festival!" p1 = Post.objects.create(title=Event.C, body=Event.F) p1.refresh_from_db() - self.assertEqual(p1.title, 'Carnival!') - self.assertEqual(p1.body, 'Festival!') + self.assertEqual(p1.title, "Carnival!") + self.assertEqual(p1.body, "Festival!") self.assertEqual(p1.title, Event.C) self.assertEqual(p1.body, Event.F) - p2 = Post.objects.get(title='Carnival!') + p2 = Post.objects.get(title="Carnival!") self.assertEqual(p1, p2) self.assertEqual(p2.title, Event.C) @@ -46,48 +45,47 @@ class TestMethods(SimpleTestCase): field = models.CharField() *_, kwargs = field.deconstruct() self.assertEqual(kwargs, {}) - field = models.CharField(db_collation='utf8_esperanto_ci') + field = models.CharField(db_collation="utf8_esperanto_ci") *_, kwargs = field.deconstruct() - self.assertEqual(kwargs, {'db_collation': 'utf8_esperanto_ci'}) + self.assertEqual(kwargs, {"db_collation": "utf8_esperanto_ci"}) class ValidationTests(SimpleTestCase): - class Choices(models.TextChoices): - C = 'c', 'C' + C = "c", "C" def test_charfield_raises_error_on_empty_string(self): f = models.CharField() - msg = 'This field cannot be blank.' + msg = "This field cannot be blank." with self.assertRaisesMessage(ValidationError, msg): - f.clean('', None) + f.clean("", None) def test_charfield_cleans_empty_string_when_blank_true(self): f = models.CharField(blank=True) - self.assertEqual('', f.clean('', None)) + self.assertEqual("", f.clean("", None)) def test_charfield_with_choices_cleans_valid_choice(self): - f = models.CharField(max_length=1, choices=[('a', 'A'), ('b', 'B')]) - self.assertEqual('a', f.clean('a', None)) + f = models.CharField(max_length=1, choices=[("a", "A"), ("b", "B")]) + self.assertEqual("a", f.clean("a", None)) def test_charfield_with_choices_raises_error_on_invalid_choice(self): - f = models.CharField(choices=[('a', 'A'), ('b', 'B')]) + f = models.CharField(choices=[("a", "A"), ("b", "B")]) msg = "Value 'not a' is not a valid choice." with self.assertRaisesMessage(ValidationError, msg): - f.clean('not a', None) + f.clean("not a", None) def test_enum_choices_cleans_valid_string(self): f = models.CharField(choices=self.Choices.choices, max_length=1) - self.assertEqual(f.clean('c', None), 'c') + self.assertEqual(f.clean("c", None), "c") def test_enum_choices_invalid_input(self): f = models.CharField(choices=self.Choices.choices, max_length=1) msg = "Value 'a' is not a valid choice." with self.assertRaisesMessage(ValidationError, msg): - f.clean('a', None) + f.clean("a", None) def test_charfield_raises_error_on_empty_input(self): f = models.CharField(null=False) - msg = 'This field cannot be null.' + msg = "This field cannot be null." with self.assertRaisesMessage(ValidationError, msg): f.clean(None, None) diff --git a/tests/model_fields/test_datetimefield.py b/tests/model_fields/test_datetimefield.py index 1c37760711..26efd481e1 100644 --- a/tests/model_fields/test_datetimefield.py +++ b/tests/model_fields/test_datetimefield.py @@ -1,9 +1,7 @@ import datetime from django.db import models -from django.test import ( - SimpleTestCase, TestCase, override_settings, skipUnlessDBFeature, -) +from django.test import SimpleTestCase, TestCase, override_settings, skipUnlessDBFeature from django.test.utils import requires_tz_support from django.utils import timezone @@ -11,18 +9,23 @@ from .models import DateTimeModel class DateTimeFieldTests(TestCase): - def test_datetimefield_to_python_microseconds(self): """DateTimeField.to_python() supports microseconds.""" f = models.DateTimeField() - self.assertEqual(f.to_python('2001-01-02 03:04:05.000006'), datetime.datetime(2001, 1, 2, 3, 4, 5, 6)) - self.assertEqual(f.to_python('2001-01-02 03:04:05.999999'), datetime.datetime(2001, 1, 2, 3, 4, 5, 999999)) + self.assertEqual( + f.to_python("2001-01-02 03:04:05.000006"), + datetime.datetime(2001, 1, 2, 3, 4, 5, 6), + ) + self.assertEqual( + f.to_python("2001-01-02 03:04:05.999999"), + datetime.datetime(2001, 1, 2, 3, 4, 5, 999999), + ) def test_timefield_to_python_microseconds(self): """TimeField.to_python() supports microseconds.""" f = models.TimeField() - self.assertEqual(f.to_python('01:02:03.000004'), datetime.time(1, 2, 3, 4)) - self.assertEqual(f.to_python('01:02:03.999999'), datetime.time(1, 2, 3, 999999)) + self.assertEqual(f.to_python("01:02:03.000004"), datetime.time(1, 2, 3, 4)) + self.assertEqual(f.to_python("01:02:03.999999"), datetime.time(1, 2, 3, 999999)) def test_datetimes_save_completely(self): dat = datetime.date(2014, 3, 12) @@ -47,14 +50,18 @@ class DateTimeFieldTests(TestCase): self.assertEqual(m, DateTimeModel.objects.get(dt__date=d)) @requires_tz_support - @skipUnlessDBFeature('has_zoneinfo_database') - @override_settings(USE_TZ=True, TIME_ZONE='America/Vancouver') + @skipUnlessDBFeature("has_zoneinfo_database") + @override_settings(USE_TZ=True, TIME_ZONE="America/Vancouver") def test_lookup_date_with_use_tz(self): d = datetime.date(2014, 3, 12) # The following is equivalent to UTC 2014-03-12 18:34:23.24000. - dt1 = datetime.datetime(2014, 3, 12, 10, 22, 23, 240000, tzinfo=timezone.get_current_timezone()) + dt1 = datetime.datetime( + 2014, 3, 12, 10, 22, 23, 240000, tzinfo=timezone.get_current_timezone() + ) # The following is equivalent to UTC 2014-03-13 05:34:23.24000. - dt2 = datetime.datetime(2014, 3, 12, 21, 22, 23, 240000, tzinfo=timezone.get_current_timezone()) + dt2 = datetime.datetime( + 2014, 3, 12, 21, 22, 23, 240000, tzinfo=timezone.get_current_timezone() + ) t = datetime.time(21, 22, 23, 240000) m1 = DateTimeModel.objects.create(d=d, dt=dt1, t=t) m2 = DateTimeModel.objects.create(d=d, dt=dt2, t=t) @@ -63,13 +70,12 @@ class DateTimeFieldTests(TestCase): DateTimeModel.objects.filter(dt__date=d), [m1, m2], ) - with self.settings(TIME_ZONE='UTC'): + with self.settings(TIME_ZONE="UTC"): # But in UTC, the __date only matches one of them. self.assertCountEqual(DateTimeModel.objects.filter(dt__date=d), [m1]) class ValidationTest(SimpleTestCase): - def test_datefield_cleans_date(self): f = models.DateField() - self.assertEqual(datetime.date(2008, 10, 10), f.clean('2008-10-10', None)) + self.assertEqual(datetime.date(2008, 10, 10), f.clean("2008-10-10", None)) diff --git a/tests/model_fields/test_decimalfield.py b/tests/model_fields/test_decimalfield.py index ea06ab9fa2..912d55af72 100644 --- a/tests/model_fields/test_decimalfield.py +++ b/tests/model_fields/test_decimalfield.py @@ -10,21 +10,20 @@ from .models import BigD, Foo class DecimalFieldTests(TestCase): - def test_to_python(self): f = models.DecimalField(max_digits=4, decimal_places=2) - self.assertEqual(f.to_python(3), Decimal('3')) - self.assertEqual(f.to_python('3.14'), Decimal('3.14')) + self.assertEqual(f.to_python(3), Decimal("3")) + self.assertEqual(f.to_python("3.14"), Decimal("3.14")) # to_python() converts floats and honors max_digits. - self.assertEqual(f.to_python(3.1415926535897), Decimal('3.142')) - self.assertEqual(f.to_python(2.4), Decimal('2.400')) + self.assertEqual(f.to_python(3.1415926535897), Decimal("3.142")) + self.assertEqual(f.to_python(2.4), Decimal("2.400")) # Uses default rounding of ROUND_HALF_EVEN. - self.assertEqual(f.to_python(2.0625), Decimal('2.062')) - self.assertEqual(f.to_python(2.1875), Decimal('2.188')) + self.assertEqual(f.to_python(2.0625), Decimal("2.062")) + self.assertEqual(f.to_python(2.1875), Decimal("2.188")) def test_invalid_value(self): field = models.DecimalField(max_digits=4, decimal_places=2) - msg = '“%s” value must be a decimal number.' + msg = "“%s” value must be a decimal number." tests = [ (), [], @@ -32,8 +31,8 @@ class DecimalFieldTests(TestCase): set(), object(), complex(), - 'non-numeric string', - b'non-numeric byte-string', + "non-numeric string", + b"non-numeric byte-string", ] for value in tests: with self.subTest(value): @@ -41,42 +40,42 @@ class DecimalFieldTests(TestCase): field.clean(value, None) def test_default(self): - f = models.DecimalField(default=Decimal('0.00')) - self.assertEqual(f.get_default(), Decimal('0.00')) + f = models.DecimalField(default=Decimal("0.00")) + self.assertEqual(f.get_default(), Decimal("0.00")) def test_get_prep_value(self): f = models.DecimalField(max_digits=5, decimal_places=1) self.assertIsNone(f.get_prep_value(None)) - self.assertEqual(f.get_prep_value('2.4'), Decimal('2.4')) + self.assertEqual(f.get_prep_value("2.4"), Decimal("2.4")) def test_filter_with_strings(self): """ Should be able to filter decimal fields using strings (#8023). """ - foo = Foo.objects.create(a='abc', d=Decimal('12.34')) - self.assertEqual(list(Foo.objects.filter(d='12.34')), [foo]) + foo = Foo.objects.create(a="abc", d=Decimal("12.34")) + self.assertEqual(list(Foo.objects.filter(d="12.34")), [foo]) def test_save_without_float_conversion(self): """ Ensure decimals don't go through a corrupting float conversion during save (#5079). """ - bd = BigD(d='12.9') + bd = BigD(d="12.9") bd.save() bd = BigD.objects.get(pk=bd.pk) - self.assertEqual(bd.d, Decimal('12.9')) + self.assertEqual(bd.d, Decimal("12.9")) def test_save_nan_invalid(self): - msg = '“nan” value must be a decimal number.' + msg = "“nan” value must be a decimal number." with self.assertRaisesMessage(ValidationError, msg): - BigD.objects.create(d=float('nan')) + BigD.objects.create(d=float("nan")) with self.assertRaisesMessage(ValidationError, msg): BigD.objects.create(d=math.nan) def test_fetch_from_db_without_float_rounding(self): - big_decimal = BigD.objects.create(d=Decimal('.100000000000000000000000000005')) + big_decimal = BigD.objects.create(d=Decimal(".100000000000000000000000000005")) big_decimal.refresh_from_db() - self.assertEqual(big_decimal.d, Decimal('.100000000000000000000000000005')) + self.assertEqual(big_decimal.d, Decimal(".100000000000000000000000000005")) def test_lookup_really_big_value(self): """ @@ -87,24 +86,30 @@ class DecimalFieldTests(TestCase): def test_max_digits_validation(self): field = models.DecimalField(max_digits=2) - expected_message = validators.DecimalValidator.messages['max_digits'] % {'max': 2} + expected_message = validators.DecimalValidator.messages["max_digits"] % { + "max": 2 + } with self.assertRaisesMessage(ValidationError, expected_message): field.clean(100, None) def test_max_decimal_places_validation(self): field = models.DecimalField(decimal_places=1) - expected_message = validators.DecimalValidator.messages['max_decimal_places'] % {'max': 1} + expected_message = validators.DecimalValidator.messages[ + "max_decimal_places" + ] % {"max": 1} with self.assertRaisesMessage(ValidationError, expected_message): - field.clean(Decimal('0.99'), None) + field.clean(Decimal("0.99"), None) def test_max_whole_digits_validation(self): field = models.DecimalField(max_digits=3, decimal_places=1) - expected_message = validators.DecimalValidator.messages['max_whole_digits'] % {'max': 2} + expected_message = validators.DecimalValidator.messages["max_whole_digits"] % { + "max": 2 + } with self.assertRaisesMessage(ValidationError, expected_message): - field.clean(Decimal('999'), None) + field.clean(Decimal("999"), None) def test_roundtrip_with_trailing_zeros(self): """Trailing zeros in the fractional part aren't truncated.""" - obj = Foo.objects.create(a='bar', d=Decimal('8.320')) + obj = Foo.objects.create(a="bar", d=Decimal("8.320")) obj.refresh_from_db() - self.assertEqual(obj.d.compare_total(Decimal('8.320')), Decimal('0')) + self.assertEqual(obj.d.compare_total(Decimal("8.320")), Decimal("0")) diff --git a/tests/model_fields/test_durationfield.py b/tests/model_fields/test_durationfield.py index 58768ab1c7..f4e13711d6 100644 --- a/tests/model_fields/test_durationfield.py +++ b/tests/model_fields/test_durationfield.py @@ -10,7 +10,6 @@ from .models import DurationModel, NullDurationModel class TestSaveLoad(TestCase): - def test_simple_roundtrip(self): duration = datetime.timedelta(microseconds=8999999999999999) DurationModel.objects.create(field=duration) @@ -30,7 +29,6 @@ class TestSaveLoad(TestCase): class TestQuerying(TestCase): - @classmethod def setUpTestData(cls): cls.objs = [ @@ -42,13 +40,13 @@ class TestQuerying(TestCase): def test_exact(self): self.assertSequenceEqual( DurationModel.objects.filter(field=datetime.timedelta(days=1)), - [self.objs[0]] + [self.objs[0]], ) def test_gt(self): self.assertSequenceEqual( DurationModel.objects.filter(field__gt=datetime.timedelta(days=0)), - [self.objs[0], self.objs[1]] + [self.objs[0], self.objs[1]], ) @@ -57,25 +55,24 @@ class TestSerialization(SimpleTestCase): def test_dumping(self): instance = DurationModel(field=datetime.timedelta(days=1, hours=1)) - data = serializers.serialize('json', [instance]) + data = serializers.serialize("json", [instance]) self.assertEqual(json.loads(data), json.loads(self.test_data)) def test_loading(self): - instance = list(serializers.deserialize('json', self.test_data))[0].object + instance = list(serializers.deserialize("json", self.test_data))[0].object self.assertEqual(instance.field, datetime.timedelta(days=1, hours=1)) class TestValidation(SimpleTestCase): - def test_invalid_string(self): field = models.DurationField() with self.assertRaises(exceptions.ValidationError) as cm: - field.clean('not a datetime', None) - self.assertEqual(cm.exception.code, 'invalid') + field.clean("not a datetime", None) + self.assertEqual(cm.exception.code, "invalid") self.assertEqual( cm.exception.message % cm.exception.params, - '“not a datetime” value has an invalid format. ' - 'It must be in [DD] [[HH:]MM:]ss[.uuuuuu] format.' + "“not a datetime” value has an invalid format. " + "It must be in [DD] [[HH:]MM:]ss[.uuuuuu] format.", ) diff --git a/tests/model_fields/test_field_flags.py b/tests/model_fields/test_field_flags.py index cbc066ac58..33f3334567 100644 --- a/tests/model_fields/test_field_flags.py +++ b/tests/model_fields/test_field_flags.py @@ -1,7 +1,5 @@ from django import test -from django.contrib.contenttypes.fields import ( - GenericForeignKey, GenericRelation, -) +from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation from django.db import models from .models import AllFieldsModel @@ -48,23 +46,23 @@ ONE_TO_ONE_CLASSES = { } FLAG_PROPERTIES = ( - 'concrete', - 'editable', - 'is_relation', - 'model', - 'hidden', - 'one_to_many', - 'many_to_one', - 'many_to_many', - 'one_to_one', - 'related_model', + "concrete", + "editable", + "is_relation", + "model", + "hidden", + "one_to_many", + "many_to_one", + "many_to_many", + "one_to_one", + "related_model", ) FLAG_PROPERTIES_FOR_RELATIONS = ( - 'one_to_many', - 'many_to_one', - 'many_to_many', - 'one_to_one', + "one_to_many", + "many_to_one", + "many_to_many", + "one_to_one", ) @@ -99,7 +97,10 @@ class FieldFlagsTests(test.SimpleTestCase): def test_each_object_should_have_auto_created(self): self.assertTrue( - all(f.auto_created.__class__ == bool for f in self.fields_and_reverse_objects) + all( + f.auto_created.__class__ == bool + for f in self.fields_and_reverse_objects + ) ) def test_non_concrete_fields(self): @@ -130,7 +131,10 @@ class FieldFlagsTests(test.SimpleTestCase): def test_all_field_types_should_have_flags(self): for field in self.fields_and_reverse_objects: for flag in FLAG_PROPERTIES: - self.assertTrue(hasattr(field, flag), "Field %s does not have flag %s" % (field, flag)) + self.assertTrue( + hasattr(field, flag), + "Field %s does not have flag %s" % (field, flag), + ) if field.is_relation: true_cardinality_flags = sum( getattr(field, flag) is True @@ -142,8 +146,7 @@ class FieldFlagsTests(test.SimpleTestCase): def test_cardinality_m2m(self): m2m_type_fields = [ - f for f in self.all_fields - if f.is_relation and f.many_to_many + f for f in self.all_fields if f.is_relation and f.many_to_many ] # Test classes are what we expect self.assertEqual(MANY_TO_MANY_CLASSES, {f.__class__ for f in m2m_type_fields}) @@ -157,7 +160,8 @@ class FieldFlagsTests(test.SimpleTestCase): def test_cardinality_o2m(self): o2m_type_fields = [ - f for f in self.fields_and_reverse_objects + f + for f in self.fields_and_reverse_objects if f.is_relation and f.one_to_many ] # Test classes are what we expect @@ -171,7 +175,8 @@ class FieldFlagsTests(test.SimpleTestCase): def test_cardinality_m2o(self): m2o_type_fields = [ - f for f in self.fields_and_reverse_objects + f + for f in self.fields_and_reverse_objects if f.is_relation and f.many_to_one ] # Test classes are what we expect @@ -179,28 +184,25 @@ class FieldFlagsTests(test.SimpleTestCase): # Ensure all m2o reverses are o2m for obj in m2o_type_fields: - if hasattr(obj, 'field'): + if hasattr(obj, "field"): reverse_field = obj.field self.assertTrue(reverse_field.is_relation and reverse_field.one_to_many) def test_cardinality_o2o(self): - o2o_type_fields = [ - f for f in self.all_fields - if f.is_relation and f.one_to_one - ] + o2o_type_fields = [f for f in self.all_fields if f.is_relation and f.one_to_one] # Test classes are what we expect self.assertEqual(ONE_TO_ONE_CLASSES, {f.__class__ for f in o2o_type_fields}) # Ensure all o2o reverses are o2o for obj in o2o_type_fields: - if hasattr(obj, 'field'): + if hasattr(obj, "field"): reverse_field = obj.field self.assertTrue(reverse_field.is_relation and reverse_field.one_to_one) def test_hidden_flag(self): incl_hidden = set(AllFieldsModel._meta.get_fields(include_hidden=True)) no_hidden = set(AllFieldsModel._meta.get_fields()) - fields_that_should_be_hidden = (incl_hidden - no_hidden) + fields_that_should_be_hidden = incl_hidden - no_hidden for f in incl_hidden: self.assertEqual(f in fields_that_should_be_hidden, f.hidden) @@ -215,5 +217,5 @@ class FieldFlagsTests(test.SimpleTestCase): def test_null(self): # null isn't well defined for a ManyToManyField, but changing it to # True causes backwards compatibility problems (#25320). - self.assertFalse(AllFieldsModel._meta.get_field('m2m').null) - self.assertTrue(AllFieldsModel._meta.get_field('reverse2').null) + self.assertFalse(AllFieldsModel._meta.get_field("m2m").null) + self.assertTrue(AllFieldsModel._meta.get_field("reverse2").null) diff --git a/tests/model_fields/test_filefield.py b/tests/model_fields/test_filefield.py index fb9426e2d1..e7c906112d 100644 --- a/tests/model_fields/test_filefield.py +++ b/tests/model_fields/test_filefield.py @@ -17,39 +17,38 @@ from .models import Document class FileFieldTests(TestCase): - def test_clearable(self): """ FileField.save_form_data() will clear its instance attribute value if passed False. """ - d = Document(myfile='something.txt') - self.assertEqual(d.myfile, 'something.txt') - field = d._meta.get_field('myfile') + d = Document(myfile="something.txt") + self.assertEqual(d.myfile, "something.txt") + field = d._meta.get_field("myfile") field.save_form_data(d, False) - self.assertEqual(d.myfile, '') + self.assertEqual(d.myfile, "") def test_unchanged(self): """ FileField.save_form_data() considers None to mean "no change" rather than "clear". """ - d = Document(myfile='something.txt') - self.assertEqual(d.myfile, 'something.txt') - field = d._meta.get_field('myfile') + d = Document(myfile="something.txt") + self.assertEqual(d.myfile, "something.txt") + field = d._meta.get_field("myfile") field.save_form_data(d, None) - self.assertEqual(d.myfile, 'something.txt') + self.assertEqual(d.myfile, "something.txt") def test_changed(self): """ FileField.save_form_data(), if passed a truthy value, updates its instance attribute. """ - d = Document(myfile='something.txt') - self.assertEqual(d.myfile, 'something.txt') - field = d._meta.get_field('myfile') - field.save_form_data(d, 'else.txt') - self.assertEqual(d.myfile, 'else.txt') + d = Document(myfile="something.txt") + self.assertEqual(d.myfile, "something.txt") + field = d._meta.get_field("myfile") + field.save_form_data(d, "else.txt") + self.assertEqual(d.myfile, "else.txt") def test_delete_when_file_unset(self): """ @@ -60,33 +59,35 @@ class FileFieldTests(TestCase): d.myfile.delete() def test_refresh_from_db(self): - d = Document.objects.create(myfile='something.txt') + d = Document.objects.create(myfile="something.txt") d.refresh_from_db() self.assertIs(d.myfile.instance, d) - @unittest.skipIf(sys.platform == 'win32', "Crashes with OSError on Windows.") + @unittest.skipIf(sys.platform == "win32", "Crashes with OSError on Windows.") def test_save_without_name(self): - with tempfile.NamedTemporaryFile(suffix='.txt') as tmp: - document = Document.objects.create(myfile='something.txt') + with tempfile.NamedTemporaryFile(suffix=".txt") as tmp: + document = Document.objects.create(myfile="something.txt") document.myfile = File(tmp) msg = f"Detected path traversal attempt in '{tmp.name}'" with self.assertRaisesMessage(SuspiciousFileOperation, msg): document.save() def test_defer(self): - Document.objects.create(myfile='something.txt') - self.assertEqual(Document.objects.defer('myfile')[0].myfile, 'something.txt') + Document.objects.create(myfile="something.txt") + self.assertEqual(Document.objects.defer("myfile")[0].myfile, "something.txt") def test_unique_when_same_filename(self): """ A FileField with unique=True shouldn't allow two instances with the same name to be saved. """ - Document.objects.create(myfile='something.txt') + Document.objects.create(myfile="something.txt") with self.assertRaises(IntegrityError): - Document.objects.create(myfile='something.txt') + Document.objects.create(myfile="something.txt") - @unittest.skipIf(sys.platform == 'win32', "Windows doesn't support moving open files.") + @unittest.skipIf( + sys.platform == "win32", "Windows doesn't support moving open files." + ) # The file's source and destination must be on the same filesystem. @override_settings(MEDIA_ROOT=temp.gettempdir()) def test_move_temporary_file(self): @@ -94,35 +95,43 @@ class FileFieldTests(TestCase): The temporary uploaded file is moved rather than copied to the destination. """ - with TemporaryUploadedFile('something.txt', 'text/plain', 0, 'UTF-8') as tmp_file: + with TemporaryUploadedFile( + "something.txt", "text/plain", 0, "UTF-8" + ) as tmp_file: tmp_file_path = tmp_file.temporary_file_path() Document.objects.create(myfile=tmp_file) - self.assertFalse(os.path.exists(tmp_file_path), 'Temporary file still exists') + self.assertFalse( + os.path.exists(tmp_file_path), "Temporary file still exists" + ) def test_open_returns_self(self): """ FieldField.open() returns self so it can be used as a context manager. """ - d = Document.objects.create(myfile='something.txt') + d = Document.objects.create(myfile="something.txt") # Replace the FileField's file with an in-memory ContentFile, so that # open() doesn't write to disk. - d.myfile.file = ContentFile(b'', name='bla') + d.myfile.file = ContentFile(b"", name="bla") self.assertEqual(d.myfile, d.myfile.open()) def test_media_root_pathlib(self): with tempfile.TemporaryDirectory() as tmp_dir: with override_settings(MEDIA_ROOT=Path(tmp_dir)): - with TemporaryUploadedFile('foo.txt', 'text/plain', 1, 'utf-8') as tmp_file: + with TemporaryUploadedFile( + "foo.txt", "text/plain", 1, "utf-8" + ) as tmp_file: Document.objects.create(myfile=tmp_file) - self.assertTrue(os.path.exists(os.path.join(tmp_dir, 'unused', 'foo.txt'))) + self.assertTrue( + os.path.exists(os.path.join(tmp_dir, "unused", "foo.txt")) + ) def test_pickle(self): with tempfile.TemporaryDirectory() as tmp_dir: with override_settings(MEDIA_ROOT=Path(tmp_dir)): - with open(__file__, 'rb') as fp: - file1 = File(fp, name='test_file.py') - document = Document(myfile='test_file.py') - document.myfile.save('test_file.py', file1) + with open(__file__, "rb") as fp: + file1 = File(fp, name="test_file.py") + document = Document(myfile="test_file.py") + document.myfile.save("test_file.py", file1) try: dump = pickle.dumps(document) loaded_document = pickle.loads(dump) @@ -159,14 +168,15 @@ class FileFieldTests(TestCase): finally: document.myfile.delete() - @isolate_apps('model_fields') + @isolate_apps("model_fields") def test_abstract_filefield_model(self): """ FileField.model returns the concrete model for fields defined in an abstract model. """ + class AbstractMyDocument(models.Model): - myfile = models.FileField(upload_to='unused') + myfile = models.FileField(upload_to="unused") class Meta: abstract = True @@ -174,5 +184,5 @@ class FileFieldTests(TestCase): class MyDocument(AbstractMyDocument): pass - document = MyDocument(myfile='test_file.py') + document = MyDocument(myfile="test_file.py") self.assertEqual(document.myfile.field.model, MyDocument) diff --git a/tests/model_fields/test_floatfield.py b/tests/model_fields/test_floatfield.py index 856197cd6e..264b5677e9 100644 --- a/tests/model_fields/test_floatfield.py +++ b/tests/model_fields/test_floatfield.py @@ -5,7 +5,6 @@ from .models import FloatModel class TestFloatField(TestCase): - def test_float_validates_object(self): instance = FloatModel(size=2.5) # Try setting float field to unsaved object @@ -20,8 +19,8 @@ class TestFloatField(TestCase): # Set field to object on saved instance instance.size = instance msg = ( - 'Tried to update field model_fields.FloatModel.size with a model ' - 'instance, %r. Use a value compatible with FloatField.' + "Tried to update field model_fields.FloatModel.size with a model " + "instance, %r. Use a value compatible with FloatField." ) % instance with transaction.atomic(): with self.assertRaisesMessage(TypeError, msg): @@ -40,8 +39,8 @@ class TestFloatField(TestCase): (TypeError, set()), (TypeError, object()), (TypeError, complex()), - (ValueError, 'non-numeric string'), - (ValueError, b'non-numeric byte-string'), + (ValueError, "non-numeric string"), + (ValueError, b"non-numeric byte-string"), ] for exception, value in tests: with self.subTest(value): diff --git a/tests/model_fields/test_foreignkey.py b/tests/model_fields/test_foreignkey.py index 0cd6d62a55..2c15dea720 100644 --- a/tests/model_fields/test_foreignkey.py +++ b/tests/model_fields/test_foreignkey.py @@ -11,24 +11,25 @@ from .models import Bar, FkToChar, Foo, PrimaryKeyCharModel class ForeignKeyTests(TestCase): - def test_callable_default(self): """A lazy callable may be used for ForeignKey.default.""" - a = Foo.objects.create(id=1, a='abc', d=Decimal('12.34')) - b = Bar.objects.create(b='bcd') + a = Foo.objects.create(id=1, a="abc", d=Decimal("12.34")) + b = Bar.objects.create(b="bcd") self.assertEqual(b.a, a) - @skipIfDBFeature('interprets_empty_strings_as_nulls') + @skipIfDBFeature("interprets_empty_strings_as_nulls") def test_empty_string_fk(self): """ Empty strings foreign key values don't get converted to None (#19299). """ - char_model_empty = PrimaryKeyCharModel.objects.create(string='') + char_model_empty = PrimaryKeyCharModel.objects.create(string="") fk_model_empty = FkToChar.objects.create(out=char_model_empty) - fk_model_empty = FkToChar.objects.select_related('out').get(id=fk_model_empty.pk) + fk_model_empty = FkToChar.objects.select_related("out").get( + id=fk_model_empty.pk + ) self.assertEqual(fk_model_empty.out, char_model_empty) - @isolate_apps('model_fields') + @isolate_apps("model_fields") def test_warning_when_unique_true_on_fk(self): class Foo(models.Model): pass @@ -39,17 +40,17 @@ class ForeignKeyTests(TestCase): model = FKUniqueTrue() expected_warnings = [ checks.Warning( - 'Setting unique=True on a ForeignKey has the same effect as using a OneToOneField.', - hint='ForeignKey(unique=True) is usually better served by a OneToOneField.', + "Setting unique=True on a ForeignKey has the same effect as using a OneToOneField.", + hint="ForeignKey(unique=True) is usually better served by a OneToOneField.", obj=FKUniqueTrue.fk_field.field, - id='fields.W342', + id="fields.W342", ) ] warnings = model.check() self.assertEqual(warnings, expected_warnings) def test_related_name_converted_to_text(self): - rel_name = Bar._meta.get_field('a').remote_field.related_name + rel_name = Bar._meta.get_field("a").remote_field.related_name self.assertIsInstance(rel_name, str) def test_abstract_model_pending_operations(self): @@ -60,7 +61,7 @@ class ForeignKeyTests(TestCase): pending_ops_before = list(apps._pending_operations.items()) class AbstractForeignKeyModel(models.Model): - fk = models.ForeignKey('missing.FK', models.CASCADE) + fk = models.ForeignKey("missing.FK", models.CASCADE) class Meta: abstract = True @@ -69,16 +70,16 @@ class ForeignKeyTests(TestCase): self.assertEqual( pending_ops_before, list(apps._pending_operations.items()), - 'Pending lookup added for a foreign key on an abstract model' + "Pending lookup added for a foreign key on an abstract model", ) - @isolate_apps('model_fields', 'model_fields.tests') + @isolate_apps("model_fields", "model_fields.tests") def test_abstract_model_app_relative_foreign_key(self): class AbstractReferent(models.Model): - reference = models.ForeignKey('Referred', on_delete=models.CASCADE) + reference = models.ForeignKey("Referred", on_delete=models.CASCADE) class Meta: - app_label = 'model_fields' + app_label = "model_fields" abstract = True def assert_app_model_resolved(label): @@ -90,12 +91,14 @@ class ForeignKeyTests(TestCase): class Meta: app_label = label - self.assertEqual(ConcreteReferent._meta.get_field('reference').related_model, Referred) + self.assertEqual( + ConcreteReferent._meta.get_field("reference").related_model, Referred + ) - assert_app_model_resolved('model_fields') - assert_app_model_resolved('tests') + assert_app_model_resolved("model_fields") + assert_app_model_resolved("tests") - @isolate_apps('model_fields') + @isolate_apps("model_fields") def test_to_python(self): class Foo(models.Model): pass @@ -103,9 +106,9 @@ class ForeignKeyTests(TestCase): class Bar(models.Model): fk = models.ForeignKey(Foo, models.CASCADE) - self.assertEqual(Bar._meta.get_field('fk').to_python('1'), 1) + self.assertEqual(Bar._meta.get_field("fk").to_python("1"), 1) - @isolate_apps('model_fields') + @isolate_apps("model_fields") def test_fk_to_fk_get_col_output_field(self): class Foo(models.Model): pass @@ -116,21 +119,21 @@ class ForeignKeyTests(TestCase): class Baz(models.Model): bar = models.ForeignKey(Bar, models.CASCADE, primary_key=True) - col = Baz._meta.get_field('bar').get_col('alias') + col = Baz._meta.get_field("bar").get_col("alias") self.assertIs(col.output_field, Foo._meta.pk) - @isolate_apps('model_fields') + @isolate_apps("model_fields") def test_recursive_fks_get_col(self): class Foo(models.Model): - bar = models.ForeignKey('Bar', models.CASCADE, primary_key=True) + bar = models.ForeignKey("Bar", models.CASCADE, primary_key=True) class Bar(models.Model): foo = models.ForeignKey(Foo, models.CASCADE, primary_key=True) - with self.assertRaisesMessage(ValueError, 'Cannot resolve output_field'): - Foo._meta.get_field('bar').get_col('alias') + with self.assertRaisesMessage(ValueError, "Cannot resolve output_field"): + Foo._meta.get_field("bar").get_col("alias") - @isolate_apps('model_fields') + @isolate_apps("model_fields") def test_non_local_to_field(self): class Parent(models.Model): key = models.IntegerField(unique=True) @@ -139,14 +142,14 @@ class ForeignKeyTests(TestCase): pass class Related(models.Model): - child = models.ForeignKey(Child, on_delete=models.CASCADE, to_field='key') + child = models.ForeignKey(Child, on_delete=models.CASCADE, to_field="key") msg = ( "'model_fields.Related.child' refers to field 'key' which is not " "local to model 'model_fields.Child'." ) with self.assertRaisesMessage(FieldError, msg): - Related._meta.get_field('child').related_fields + Related._meta.get_field("child").related_fields def test_invalid_to_parameter(self): msg = ( @@ -154,5 +157,6 @@ class ForeignKeyTests(TestCase): "either a model, a model name, or the string 'self'" ) with self.assertRaisesMessage(TypeError, msg): + class MyModel(models.Model): child = models.ForeignKey(1, models.CASCADE) diff --git a/tests/model_fields/test_genericipaddressfield.py b/tests/model_fields/test_genericipaddressfield.py index c65fe805cb..76845238e5 100644 --- a/tests/model_fields/test_genericipaddressfield.py +++ b/tests/model_fields/test_genericipaddressfield.py @@ -6,20 +6,19 @@ from .models import GenericIPAddress class GenericIPAddressFieldTests(TestCase): - def test_genericipaddressfield_formfield_protocol(self): """ GenericIPAddressField with a specified protocol does not generate a formfield without a protocol. """ - model_field = models.GenericIPAddressField(protocol='IPv4') + model_field = models.GenericIPAddressField(protocol="IPv4") form_field = model_field.formfield() with self.assertRaises(ValidationError): - form_field.clean('::1') - model_field = models.GenericIPAddressField(protocol='IPv6') + form_field.clean("::1") + model_field = models.GenericIPAddressField(protocol="IPv6") form_field = model_field.formfield() with self.assertRaises(ValidationError): - form_field.clean('127.0.0.1') + form_field.clean("127.0.0.1") def test_null_value(self): """ @@ -30,14 +29,14 @@ class GenericIPAddressFieldTests(TestCase): self.assertIsNone(o.ip) def test_blank_string_saved_as_null(self): - o = GenericIPAddress.objects.create(ip='') + o = GenericIPAddress.objects.create(ip="") o.refresh_from_db() self.assertIsNone(o.ip) - GenericIPAddress.objects.update(ip='') + GenericIPAddress.objects.update(ip="") o.refresh_from_db() self.assertIsNone(o.ip) def test_save_load(self): - instance = GenericIPAddress.objects.create(ip='::1') + instance = GenericIPAddress.objects.create(ip="::1") loaded = GenericIPAddress.objects.get() self.assertEqual(loaded.ip, instance.ip) diff --git a/tests/model_fields/test_imagefield.py b/tests/model_fields/test_imagefield.py index cbb58a0bbd..6ef46ef200 100644 --- a/tests/model_fields/test_imagefield.py +++ b/tests/model_fields/test_imagefield.py @@ -15,13 +15,19 @@ except ImproperlyConfigured: if Image: from .models import ( - Person, PersonDimensionsFirst, PersonTwoImages, PersonWithHeight, - PersonWithHeightAndWidth, TestImageFieldFile, temp_storage_dir, + Person, + PersonDimensionsFirst, + PersonTwoImages, + PersonWithHeight, + PersonWithHeightAndWidth, + TestImageFieldFile, + temp_storage_dir, ) else: # Pillow not available, create dummy classes (tests will be skipped anyway) class Person: pass + PersonWithHeight = PersonWithHeightAndWidth = PersonDimensionsFirst = Person PersonTwoImages = Person @@ -49,11 +55,11 @@ class ImageFieldTestMixin(SerializeMixin): 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'), name='4x8.png') + file_path1 = os.path.join(os.path.dirname(__file__), "4x8.png") + self.file1 = self.File(open(file_path1, "rb"), name="4x8.png") - file_path2 = os.path.join(os.path.dirname(__file__), '8x4.png') - self.file2 = self.File(open(file_path2, 'rb'), name='8x4.png') + file_path2 = os.path.join(os.path.dirname(__file__), "8x4.png") + self.file2 = self.File(open(file_path2, "rb"), name="8x4.png") def tearDown(self): """ @@ -63,7 +69,7 @@ class ImageFieldTestMixin(SerializeMixin): self.file2.close() shutil.rmtree(temp_storage_dir) - def check_dimensions(self, instance, width, height, field_name='mugshot'): + 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 @@ -81,18 +87,18 @@ class ImageFieldTestMixin(SerializeMixin): # Check height/width attributes of field. if width is None and height is None: with self.assertRaises(ValueError): - getattr(field, 'width') + getattr(field, "width") with self.assertRaises(ValueError): - getattr(field, 'height') + 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' + 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' + height_field_name = field_name + "_height" if hasattr(instance, height_field_name): self.assertEqual(getattr(instance, height_field_name), height) @@ -137,7 +143,7 @@ class ImageFieldTests(ImageFieldTestMixin, TestCase): p.mugshot.save("shot", self.file1) p = self.PersonModel.objects.get(name="Joan") path = p.mugshot.path - shutil.move(path, path + '.moved') + shutil.move(path, path + ".moved") self.PersonModel.objects.get(name="Joan") def test_delete_when_missing(self): @@ -193,11 +199,11 @@ class ImageFieldTests(ImageFieldTestMixin, TestCase): self.assertEqual(p.mugshot.field, loaded_mugshot.field) def test_defer(self): - self.PersonModel.objects.create(name='Joe', mugshot=self.file1) + self.PersonModel.objects.create(name="Joe", mugshot=self.file1) with self.assertNumQueries(1): - qs = list(self.PersonModel.objects.defer('mugshot')) + qs = list(self.PersonModel.objects.defer("mugshot")) with self.assertNumQueries(0): - self.assertEqual(qs[0].name, 'Joe') + self.assertEqual(qs[0].name, "Joe") @skipIf(Image is None, "Pillow is required to test ImageField") @@ -210,7 +216,7 @@ class ImageFieldTwoDimensionsTests(ImageFieldTestMixin, TestCase): """ Tests assigning an image field through the model's constructor. """ - p = self.PersonModel(name='Joe', mugshot=self.file1) + p = self.PersonModel(name="Joe", mugshot=self.file1) self.check_dimensions(p, 4, 8) p.save() self.check_dimensions(p, 4, 8) @@ -219,7 +225,7 @@ class ImageFieldTwoDimensionsTests(ImageFieldTestMixin, TestCase): """ Tests behavior when image is not passed in constructor. """ - p = self.PersonModel(name='Joe') + 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. @@ -227,7 +233,7 @@ class ImageFieldTwoDimensionsTests(ImageFieldTestMixin, TestCase): self.assertFalse(p.mugshot) # Test setting a fresh created model instance. - p = self.PersonModel(name='Joe') + p = self.PersonModel(name="Joe") p.mugshot = self.file1 self.check_dimensions(p, 4, 8) @@ -235,7 +241,7 @@ class ImageFieldTwoDimensionsTests(ImageFieldTestMixin, TestCase): """ Tests assigning an image in Manager.create(). """ - p = self.PersonModel.objects.create(name='Joe', mugshot=self.file1) + p = self.PersonModel.objects.create(name="Joe", mugshot=self.file1) self.check_dimensions(p, 4, 8) def test_default_value(self): @@ -252,7 +258,7 @@ class ImageFieldTwoDimensionsTests(ImageFieldTestMixin, TestCase): """ Assigning ImageField to None clears dimensions. """ - p = self.PersonModel(name='Joe', mugshot=self.file1) + p = self.PersonModel(name="Joe", mugshot=self.file1) self.check_dimensions(p, 4, 8) # If image assigned to None, dimension fields should be cleared. @@ -267,7 +273,7 @@ class ImageFieldTwoDimensionsTests(ImageFieldTestMixin, TestCase): Tests assignment using the field's save method and deletion using the field's delete method. """ - p = self.PersonModel(name='Joe') + p = self.PersonModel(name="Joe") p.mugshot.save("mug", self.file1) self.check_dimensions(p, 4, 8) @@ -284,14 +290,14 @@ class ImageFieldTwoDimensionsTests(ImageFieldTestMixin, TestCase): """ Dimensions are updated correctly in various situations. """ - p = self.PersonModel(name='Joe') + 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) # Test dimensions after fetching from database. - p = self.PersonModel.objects.get(name='Joe') + 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. @@ -363,76 +369,76 @@ class TwoImageFieldTests(ImageFieldTestMixin, TestCase): 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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 = self.PersonModel(name="Joe") p.mugshot.save("mug", self.file1) - self.check_dimensions(p, 4, 8, 'mugshot') - self.check_dimensions(p, None, None, 'headshot') + 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') + 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') + 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') + self.check_dimensions(p, None, None, "mugshot") + self.check_dimensions(p, None, None, "headshot") def test_dimensions(self): """ Dimensions are updated correctly in various situations. """ - p = self.PersonModel(name='Joe') + 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') + 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') + 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.assertIs(p.mugshot.was_opened, False) self.assertIs(p.headshot.was_opened, False) - self.check_dimensions(p, 4, 8, 'mugshot') - self.check_dimensions(p, 8, 4, 'headshot') + 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.assertIs(p.mugshot.was_opened, True) @@ -441,8 +447,8 @@ class TwoImageFieldTests(ImageFieldTestMixin, TestCase): # 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.check_dimensions(p, 4, 8, "mugshot") + self.check_dimensions(p, 8, 4, "headshot") self.assertIs(p.mugshot.was_opened, False) self.assertIs(p.headshot.was_opened, False) @@ -450,8 +456,8 @@ class TwoImageFieldTests(ImageFieldTestMixin, TestCase): # update. p.mugshot = self.file2 p.headshot = self.file1 - self.check_dimensions(p, 8, 4, 'mugshot') - self.check_dimensions(p, 4, 8, 'headshot') + self.check_dimensions(p, 8, 4, "mugshot") + self.check_dimensions(p, 4, 8, "headshot") # Dimensions were recalculated, and hence file should have opened. self.assertIs(p.mugshot.was_opened, True) self.assertIs(p.headshot.was_opened, True) diff --git a/tests/model_fields/test_integerfield.py b/tests/model_fields/test_integerfield.py index af5a9f2e35..3ee6ac16d8 100644 --- a/tests/model_fields/test_integerfield.py +++ b/tests/model_fields/test_integerfield.py @@ -4,8 +4,12 @@ from django.db import IntegrityError, connection, models from django.test import SimpleTestCase, TestCase from .models import ( - BigIntegerModel, IntegerModel, PositiveBigIntegerModel, - PositiveIntegerModel, PositiveSmallIntegerModel, SmallIntegerModel, + BigIntegerModel, + IntegerModel, + PositiveBigIntegerModel, + PositiveIntegerModel, + PositiveSmallIntegerModel, + SmallIntegerModel, ) @@ -16,7 +20,7 @@ class IntegerFieldTests(TestCase): @property def backend_range(self): - field = self.model._meta.get_field('value') + field = self.model._meta.get_field("value") internal_type = field.get_internal_type() return connection.ops.integer_field_range(internal_type) @@ -73,7 +77,7 @@ class IntegerFieldTests(TestCase): if min_value is not None: instance = self.model(value=min_value - 1) expected_message = validators.MinValueValidator.message % { - 'limit_value': min_value, + "limit_value": min_value, } with self.assertRaisesMessage(ValidationError, expected_message): instance.full_clean() @@ -83,7 +87,7 @@ class IntegerFieldTests(TestCase): if max_value is not None: instance = self.model(value=max_value + 1) expected_message = validators.MaxValueValidator.message % { - 'limit_value': max_value, + "limit_value": max_value, } with self.assertRaisesMessage(ValidationError, expected_message): instance.full_clean() @@ -101,26 +105,38 @@ class IntegerFieldTests(TestCase): with self.subTest(callable_limit=callable_limit): if min_backend_value is not None: min_custom_value = min_backend_value + 1 - limit_value = (lambda: min_custom_value) if callable_limit else min_custom_value - ranged_value_field = self.model._meta.get_field('value').__class__( + limit_value = ( + (lambda: min_custom_value) + if callable_limit + else min_custom_value + ) + ranged_value_field = self.model._meta.get_field("value").__class__( validators=[validators.MinValueValidator(limit_value)] ) field_range_message = validators.MinValueValidator.message % { - 'limit_value': min_custom_value, + "limit_value": min_custom_value, } - with self.assertRaisesMessage(ValidationError, '[%r]' % field_range_message): + with self.assertRaisesMessage( + ValidationError, "[%r]" % field_range_message + ): ranged_value_field.run_validators(min_backend_value - 1) if max_backend_value is not None: max_custom_value = max_backend_value - 1 - limit_value = (lambda: max_custom_value) if callable_limit else max_custom_value - ranged_value_field = self.model._meta.get_field('value').__class__( + limit_value = ( + (lambda: max_custom_value) + if callable_limit + else max_custom_value + ) + ranged_value_field = self.model._meta.get_field("value").__class__( validators=[validators.MaxValueValidator(limit_value)] ) field_range_message = validators.MaxValueValidator.message % { - 'limit_value': max_custom_value, + "limit_value": max_custom_value, } - with self.assertRaisesMessage(ValidationError, '[%r]' % field_range_message): + with self.assertRaisesMessage( + ValidationError, "[%r]" % field_range_message + ): ranged_value_field.run_validators(max_backend_value + 1) def test_types(self): @@ -132,8 +148,8 @@ class IntegerFieldTests(TestCase): self.assertIsInstance(instance.value, int) def test_coercing(self): - self.model.objects.create(value='10') - instance = self.model.objects.get(value='10') + self.model.objects.create(value="10") + instance = self.model.objects.get(value="10") self.assertEqual(instance.value, 10) def test_invalid_value(self): @@ -144,8 +160,8 @@ class IntegerFieldTests(TestCase): (TypeError, set()), (TypeError, object()), (TypeError, complex()), - (ValueError, 'non-numeric string'), - (ValueError, b'non-numeric byte-string'), + (ValueError, "non-numeric string"), + (ValueError, b"non-numeric byte-string"), ] for exception, value in tests: with self.subTest(value): @@ -154,7 +170,7 @@ class IntegerFieldTests(TestCase): self.model.objects.create(value=value) def test_rel_db_type(self): - field = self.model._meta.get_field('value') + field = self.model._meta.get_field("value") rel_db_type = field.rel_db_type(connection) self.assertEqual(rel_db_type, self.rel_db_type_class().db_type(connection)) @@ -192,7 +208,7 @@ class PositiveIntegerFieldTests(IntegerFieldTests): def test_negative_values(self): p = PositiveIntegerModel.objects.create(value=0) - p.value = models.F('value') - 1 + p.value = models.F("value") - 1 with self.assertRaises(IntegrityError): p.save() @@ -208,21 +224,20 @@ class PositiveBigIntegerFieldTests(IntegerFieldTests): class ValidationTests(SimpleTestCase): - class Choices(models.IntegerChoices): A = 1 def test_integerfield_cleans_valid_string(self): f = models.IntegerField() - self.assertEqual(f.clean('2', None), 2) + self.assertEqual(f.clean("2", None), 2) def test_integerfield_raises_error_on_invalid_intput(self): f = models.IntegerField() with self.assertRaises(ValidationError): - f.clean('a', None) + f.clean("a", None) def test_choices_validation_supports_named_groups(self): - f = models.IntegerField(choices=(('group', ((10, 'A'), (20, 'B'))), (30, 'C'))) + f = models.IntegerField(choices=(("group", ((10, "A"), (20, "B"))), (30, "C"))) self.assertEqual(10, f.clean(10, None)) def test_nullable_integerfield_raises_error_with_blank_false(self): @@ -239,20 +254,20 @@ class ValidationTests(SimpleTestCase): with self.assertRaises(ValidationError): f.clean(None, None) with self.assertRaises(ValidationError): - f.clean('', None) + f.clean("", None) def test_integerfield_validates_zero_against_choices(self): f = models.IntegerField(choices=((1, 1),)) with self.assertRaises(ValidationError): - f.clean('0', None) + f.clean("0", None) def test_enum_choices_cleans_valid_string(self): f = models.IntegerField(choices=self.Choices.choices) - self.assertEqual(f.clean('1', None), 1) + self.assertEqual(f.clean("1", None), 1) def test_enum_choices_invalid_input(self): f = models.IntegerField(choices=self.Choices.choices) with self.assertRaises(ValidationError): - f.clean('A', None) + f.clean("A", None) with self.assertRaises(ValidationError): - f.clean('3', None) + f.clean("3", None) diff --git a/tests/model_fields/test_jsonfield.py b/tests/model_fields/test_jsonfield.py index faedd451cb..dfd00f4745 100644 --- a/tests/model_fields/test_jsonfield.py +++ b/tests/model_fields/test_jsonfield.py @@ -7,40 +7,51 @@ from django.core import serializers from django.core.exceptions import ValidationError from django.core.serializers.json import DjangoJSONEncoder from django.db import ( - DataError, IntegrityError, NotSupportedError, OperationalError, connection, + DataError, + IntegrityError, + NotSupportedError, + OperationalError, + connection, models, ) from django.db.models import ( - Count, ExpressionWrapper, F, IntegerField, OuterRef, Q, Subquery, - Transform, Value, + Count, + ExpressionWrapper, + F, + IntegerField, + OuterRef, + Q, + Subquery, + Transform, + Value, ) from django.db.models.expressions import RawSQL from django.db.models.fields.json import ( - KeyTextTransform, KeyTransform, KeyTransformFactory, + KeyTextTransform, + KeyTransform, + KeyTransformFactory, KeyTransformTextLookupMixin, ) from django.db.models.functions import Cast -from django.test import ( - SimpleTestCase, TestCase, skipIfDBFeature, skipUnlessDBFeature, -) +from django.test import SimpleTestCase, TestCase, skipIfDBFeature, skipUnlessDBFeature from django.test.utils import CaptureQueriesContext -from .models import ( - CustomJSONDecoder, JSONModel, NullableJSONModel, RelatedJSONModel, -) +from .models import CustomJSONDecoder, JSONModel, NullableJSONModel, RelatedJSONModel -@skipUnlessDBFeature('supports_json_field') +@skipUnlessDBFeature("supports_json_field") class JSONFieldTests(TestCase): def test_invalid_value(self): - msg = 'is not JSON serializable' + msg = "is not JSON serializable" with self.assertRaisesMessage(TypeError, msg): - NullableJSONModel.objects.create(value={ - 'uuid': uuid.UUID('d85e2076-b67c-4ee7-8c3a-2bf5a2cc2475'), - }) + NullableJSONModel.objects.create( + value={ + "uuid": uuid.UUID("d85e2076-b67c-4ee7-8c3a-2bf5a2cc2475"), + } + ) def test_custom_encoder_decoder(self): - value = {'uuid': uuid.UUID('{d85e2076-b67c-4ee7-8c3a-2bf5a2cc2475}')} + value = {"uuid": uuid.UUID("{d85e2076-b67c-4ee7-8c3a-2bf5a2cc2475}")} obj = NullableJSONModel(value_custom=value) obj.clean_fields() obj.save() @@ -48,8 +59,8 @@ class JSONFieldTests(TestCase): self.assertEqual(obj.value_custom, value) def test_db_check_constraints(self): - value = '{@!invalid json value 123 $!@#' - with mock.patch.object(DjangoJSONEncoder, 'encode', return_value=value): + value = "{@!invalid json value 123 $!@#" + with mock.patch.object(DjangoJSONEncoder, "encode", return_value=value): with self.assertRaises((IntegrityError, DataError, OperationalError)): NullableJSONModel.objects.create(value_custom=value) @@ -58,33 +69,34 @@ class TestMethods(SimpleTestCase): def test_deconstruct(self): field = models.JSONField() name, path, args, kwargs = field.deconstruct() - self.assertEqual(path, 'django.db.models.JSONField') + self.assertEqual(path, "django.db.models.JSONField") self.assertEqual(args, []) self.assertEqual(kwargs, {}) def test_deconstruct_custom_encoder_decoder(self): field = models.JSONField(encoder=DjangoJSONEncoder, decoder=CustomJSONDecoder) name, path, args, kwargs = field.deconstruct() - self.assertEqual(kwargs['encoder'], DjangoJSONEncoder) - self.assertEqual(kwargs['decoder'], CustomJSONDecoder) + self.assertEqual(kwargs["encoder"], DjangoJSONEncoder) + self.assertEqual(kwargs["decoder"], CustomJSONDecoder) def test_get_transforms(self): @models.JSONField.register_lookup class MyTransform(Transform): - lookup_name = 'my_transform' + lookup_name = "my_transform" + field = models.JSONField() - transform = field.get_transform('my_transform') + transform = field.get_transform("my_transform") self.assertIs(transform, MyTransform) models.JSONField._unregister_lookup(MyTransform) models.JSONField._clear_cached_lookups() - transform = field.get_transform('my_transform') + transform = field.get_transform("my_transform") self.assertIsInstance(transform, KeyTransformFactory) def test_key_transform_text_lookup_mixin_non_key_transform(self): - transform = Transform('test') + transform = Transform("test") msg = ( - 'Transform should be an instance of KeyTransform in order to use ' - 'this lookup.' + "Transform should be an instance of KeyTransform in order to use " + "this lookup." ) with self.assertRaisesMessage(TypeError, msg): KeyTransformTextLookupMixin(transform) @@ -92,26 +104,26 @@ class TestMethods(SimpleTestCase): class TestValidation(SimpleTestCase): def test_invalid_encoder(self): - msg = 'The encoder parameter must be a callable object.' + msg = "The encoder parameter must be a callable object." with self.assertRaisesMessage(ValueError, msg): models.JSONField(encoder=DjangoJSONEncoder()) def test_invalid_decoder(self): - msg = 'The decoder parameter must be a callable object.' + msg = "The decoder parameter must be a callable object." with self.assertRaisesMessage(ValueError, msg): models.JSONField(decoder=CustomJSONDecoder()) def test_validation_error(self): field = models.JSONField() - msg = 'Value must be valid JSON.' - value = uuid.UUID('{d85e2076-b67c-4ee7-8c3a-2bf5a2cc2475}') + msg = "Value must be valid JSON." + value = uuid.UUID("{d85e2076-b67c-4ee7-8c3a-2bf5a2cc2475}") with self.assertRaisesMessage(ValidationError, msg): - field.clean({'uuid': value}, None) + field.clean({"uuid": value}, None) def test_custom_encoder(self): field = models.JSONField(encoder=DjangoJSONEncoder) - value = uuid.UUID('{d85e2076-b67c-4ee7-8c3a-2bf5a2cc2475}') - field.clean({'uuid': value}, None) + value = uuid.UUID("{d85e2076-b67c-4ee7-8c3a-2bf5a2cc2475}") + field.clean({"uuid": value}, None) class TestFormField(SimpleTestCase): @@ -121,7 +133,9 @@ class TestFormField(SimpleTestCase): self.assertIsInstance(form_field, forms.JSONField) def test_formfield_custom_encoder_decoder(self): - model_field = models.JSONField(encoder=DjangoJSONEncoder, decoder=CustomJSONDecoder) + model_field = models.JSONField( + encoder=DjangoJSONEncoder, decoder=CustomJSONDecoder + ) form_field = model_field.formfield() self.assertIs(form_field.encoder, DjangoJSONEncoder) self.assertIs(form_field.decoder, CustomJSONDecoder) @@ -133,8 +147,8 @@ class TestSerialization(SimpleTestCase): ) test_values = ( # (Python value, serialized value), - ({'a': 'b', 'c': None}, '{"a": "b", "c": null}'), - ('abc', '"abc"'), + ({"a": "b", "c": None}, '{"a": "b", "c": null}'), + ("abc", '"abc"'), ('{"a": "a"}', '"{\\"a\\": \\"a\\"}"'), ) @@ -142,14 +156,14 @@ class TestSerialization(SimpleTestCase): for value, serialized in self.test_values: with self.subTest(value=value): instance = JSONModel(value=value) - data = serializers.serialize('json', [instance]) + data = serializers.serialize("json", [instance]) self.assertJSONEqual(data, self.test_data % serialized) def test_loading(self): for value, serialized in self.test_values: with self.subTest(value=value): instance = list( - serializers.deserialize('json', self.test_data % serialized) + serializers.deserialize("json", self.test_data % serialized) )[0].object self.assertEqual(instance.value, value) @@ -158,18 +172,18 @@ class TestSerialization(SimpleTestCase): '<django-objects version="1.0">' '<object model="model_fields.nullablejsonmodel">' '<field name="value" type="JSONField">%s' - '</field></object></django-objects>' + "</field></object></django-objects>" ) for value, serialized in self.test_values: with self.subTest(value=value): instance = NullableJSONModel(value=value) - data = serializers.serialize('xml', [instance], fields=['value']) + data = serializers.serialize("xml", [instance], fields=["value"]) self.assertXMLEqual(data, test_xml_data % serialized) - new_instance = list(serializers.deserialize('xml', data))[0].object + new_instance = list(serializers.deserialize("xml", data))[0].object self.assertEqual(new_instance.value, instance.value) -@skipUnlessDBFeature('supports_json_field') +@skipUnlessDBFeature("supports_json_field") class TestSaveLoad(TestCase): def test_null(self): obj = NullableJSONModel(value=None) @@ -177,15 +191,15 @@ class TestSaveLoad(TestCase): obj.refresh_from_db() self.assertIsNone(obj.value) - @skipUnlessDBFeature('supports_primitives_in_json_field') + @skipUnlessDBFeature("supports_primitives_in_json_field") def test_json_null_different_from_sql_null(self): - json_null = NullableJSONModel.objects.create(value=Value('null')) + json_null = NullableJSONModel.objects.create(value=Value("null")) json_null.refresh_from_db() sql_null = NullableJSONModel.objects.create(value=None) sql_null.refresh_from_db() # 'null' is not equal to NULL in the database. self.assertSequenceEqual( - NullableJSONModel.objects.filter(value=Value('null')), + NullableJSONModel.objects.filter(value=Value("null")), [json_null], ) self.assertSequenceEqual( @@ -199,14 +213,14 @@ class TestSaveLoad(TestCase): # 'null' is equal to NULL in Python (None). self.assertEqual(json_null.value, sql_null.value) - @skipUnlessDBFeature('supports_primitives_in_json_field') + @skipUnlessDBFeature("supports_primitives_in_json_field") def test_primitives(self): values = [ True, 1, 1.45, - 'String', - '', + "String", + "", ] for value in values: with self.subTest(value=value): @@ -218,8 +232,8 @@ class TestSaveLoad(TestCase): def test_dict(self): values = [ {}, - {'name': 'John', 'age': 20, 'height': 180.3}, - {'a': True, 'b': {'b1': False, 'b2': None}}, + {"name": "John", "age": 20, "height": 180.3}, + {"a": True, "b": {"b1": False, "b2": None}}, ] for value in values: with self.subTest(value=value): @@ -230,7 +244,7 @@ class TestSaveLoad(TestCase): def test_list(self): values = [ [], - ['John', 20, 180.3], + ["John", 20, 180.3], [True, [False, None]], ] for value in values: @@ -241,16 +255,16 @@ class TestSaveLoad(TestCase): def test_realistic_object(self): value = { - 'name': 'John', - 'age': 20, - 'pets': [ - {'name': 'Kit', 'type': 'cat', 'age': 2}, - {'name': 'Max', 'type': 'dog', 'age': 1}, + "name": "John", + "age": 20, + "pets": [ + {"name": "Kit", "type": "cat", "age": 2}, + {"name": "Max", "type": "dog", "age": 1}, ], - 'courses': [ - ['A1', 'A2', 'A3'], - ['B1', 'B2'], - ['C1'], + "courses": [ + ["A1", "A2", "A3"], + ["B1", "B2"], + ["C1"], ], } obj = JSONModel.objects.create(value=value) @@ -258,48 +272,47 @@ class TestSaveLoad(TestCase): self.assertEqual(obj.value, value) -@skipUnlessDBFeature('supports_json_field') +@skipUnlessDBFeature("supports_json_field") class TestQuerying(TestCase): @classmethod def setUpTestData(cls): - cls.primitives = [True, False, 'yes', 7, 9.6] + cls.primitives = [True, False, "yes", 7, 9.6] values = [ None, [], {}, - {'a': 'b', 'c': 14}, + {"a": "b", "c": 14}, { - 'a': 'b', - 'c': 14, - 'd': ['e', {'f': 'g'}], - 'h': True, - 'i': False, - 'j': None, - 'k': {'l': 'm'}, - 'n': [None, True, False], - 'o': '"quoted"', - 'p': 4.2, - 'r': {'s': True, 't': False}, + "a": "b", + "c": 14, + "d": ["e", {"f": "g"}], + "h": True, + "i": False, + "j": None, + "k": {"l": "m"}, + "n": [None, True, False], + "o": '"quoted"', + "p": 4.2, + "r": {"s": True, "t": False}, }, [1, [2]], - {'k': True, 'l': False, 'foo': 'bax'}, + {"k": True, "l": False, "foo": "bax"}, { - 'foo': 'bar', - 'baz': {'a': 'b', 'c': 'd'}, - 'bar': ['foo', 'bar'], - 'bax': {'foo': 'bar'}, + "foo": "bar", + "baz": {"a": "b", "c": "d"}, + "bar": ["foo", "bar"], + "bax": {"foo": "bar"}, }, ] - cls.objs = [ - NullableJSONModel.objects.create(value=value) - for value in values - ] + cls.objs = [NullableJSONModel.objects.create(value=value) for value in values] if connection.features.supports_primitives_in_json_field: - cls.objs.extend([ - NullableJSONModel.objects.create(value=value) - for value in cls.primitives - ]) - cls.raw_sql = '%s::jsonb' if connection.vendor == 'postgresql' else '%s' + cls.objs.extend( + [ + NullableJSONModel.objects.create(value=value) + for value in cls.primitives + ] + ) + cls.raw_sql = "%s::jsonb" if connection.vendor == "postgresql" else "%s" def test_exact(self): self.assertSequenceEqual( @@ -309,13 +322,13 @@ class TestQuerying(TestCase): def test_exact_complex(self): self.assertSequenceEqual( - NullableJSONModel.objects.filter(value__exact={'a': 'b', 'c': 14}), + NullableJSONModel.objects.filter(value__exact={"a": "b", "c": 14}), [self.objs[3]], ) def test_icontains(self): self.assertSequenceEqual( - NullableJSONModel.objects.filter(value__icontains='BaX'), + NullableJSONModel.objects.filter(value__icontains="BaX"), self.objs[6:8], ) @@ -326,25 +339,25 @@ class TestQuerying(TestCase): ) def test_ordering_by_transform(self): - mariadb = connection.vendor == 'mysql' and connection.mysql_is_mariadb + mariadb = connection.vendor == "mysql" and connection.mysql_is_mariadb values = [ - {'ord': 93, 'name': 'bar'}, - {'ord': 22.1, 'name': 'foo'}, - {'ord': -1, 'name': 'baz'}, - {'ord': 21.931902, 'name': 'spam'}, - {'ord': -100291029, 'name': 'eggs'}, + {"ord": 93, "name": "bar"}, + {"ord": 22.1, "name": "foo"}, + {"ord": -1, "name": "baz"}, + {"ord": 21.931902, "name": "spam"}, + {"ord": -100291029, "name": "eggs"}, ] - for field_name in ['value', 'value_custom']: + for field_name in ["value", "value_custom"]: with self.subTest(field=field_name): objs = [ NullableJSONModel.objects.create(**{field_name: value}) for value in values ] query = NullableJSONModel.objects.filter( - **{'%s__name__isnull' % field_name: False}, - ).order_by('%s__ord' % field_name) + **{"%s__name__isnull" % field_name: False}, + ).order_by("%s__ord" % field_name) expected = [objs[4], objs[2], objs[3], objs[1], objs[0]] - if mariadb or connection.vendor == 'oracle': + if mariadb or connection.vendor == "oracle": # MariaDB and Oracle return JSON values as strings. expected = [objs[2], objs[4], objs[3], objs[1], objs[0]] self.assertSequenceEqual(query, expected) @@ -352,104 +365,133 @@ class TestQuerying(TestCase): def test_ordering_grouping_by_key_transform(self): base_qs = NullableJSONModel.objects.filter(value__d__0__isnull=False) for qs in ( - base_qs.order_by('value__d__0'), - base_qs.annotate(key=KeyTransform('0', KeyTransform('d', 'value'))).order_by('key'), + base_qs.order_by("value__d__0"), + base_qs.annotate( + key=KeyTransform("0", KeyTransform("d", "value")) + ).order_by("key"), ): self.assertSequenceEqual(qs, [self.objs[4]]) qs = NullableJSONModel.objects.filter(value__isnull=False) self.assertQuerysetEqual( - qs.filter(value__isnull=False).annotate( - key=KeyTextTransform('f', KeyTransform('1', KeyTransform('d', 'value'))), - ).values('key').annotate(count=Count('key')).order_by('count'), - [(None, 0), ('g', 1)], - operator.itemgetter('key', 'count'), + qs.filter(value__isnull=False) + .annotate( + key=KeyTextTransform( + "f", KeyTransform("1", KeyTransform("d", "value")) + ), + ) + .values("key") + .annotate(count=Count("key")) + .order_by("count"), + [(None, 0), ("g", 1)], + operator.itemgetter("key", "count"), ) def test_ordering_grouping_by_count(self): - qs = NullableJSONModel.objects.filter( - value__isnull=False, - ).values('value__d__0').annotate(count=Count('value__d__0')).order_by('count') - self.assertQuerysetEqual(qs, [0, 1], operator.itemgetter('count')) + qs = ( + NullableJSONModel.objects.filter( + value__isnull=False, + ) + .values("value__d__0") + .annotate(count=Count("value__d__0")) + .order_by("count") + ) + self.assertQuerysetEqual(qs, [0, 1], operator.itemgetter("count")) def test_order_grouping_custom_decoder(self): - NullableJSONModel.objects.create(value_custom={'a': 'b'}) + NullableJSONModel.objects.create(value_custom={"a": "b"}) qs = NullableJSONModel.objects.filter(value_custom__isnull=False) self.assertSequenceEqual( qs.values( - 'value_custom__a', - ).annotate( - count=Count('id'), - ).order_by('value_custom__a'), - [{'value_custom__a': 'b', 'count': 1}], + "value_custom__a", + ) + .annotate( + count=Count("id"), + ) + .order_by("value_custom__a"), + [{"value_custom__a": "b", "count": 1}], ) def test_key_transform_raw_expression(self): expr = RawSQL(self.raw_sql, ['{"x": "bar"}']) self.assertSequenceEqual( - NullableJSONModel.objects.filter(value__foo=KeyTransform('x', expr)), + NullableJSONModel.objects.filter(value__foo=KeyTransform("x", expr)), [self.objs[7]], ) def test_nested_key_transform_raw_expression(self): expr = RawSQL(self.raw_sql, ['{"x": {"y": "bar"}}']) self.assertSequenceEqual( - NullableJSONModel.objects.filter(value__foo=KeyTransform('y', KeyTransform('x', expr))), + NullableJSONModel.objects.filter( + value__foo=KeyTransform("y", KeyTransform("x", expr)) + ), [self.objs[7]], ) def test_key_transform_expression(self): self.assertSequenceEqual( - NullableJSONModel.objects.filter(value__d__0__isnull=False).annotate( - key=KeyTransform('d', 'value'), - chain=KeyTransform('0', 'key'), - expr=KeyTransform('0', Cast('key', models.JSONField())), - ).filter(chain=F('expr')), + NullableJSONModel.objects.filter(value__d__0__isnull=False) + .annotate( + key=KeyTransform("d", "value"), + chain=KeyTransform("0", "key"), + expr=KeyTransform("0", Cast("key", models.JSONField())), + ) + .filter(chain=F("expr")), [self.objs[4]], ) def test_key_transform_annotation_expression(self): - obj = NullableJSONModel.objects.create(value={'d': ['e', 'e']}) + obj = NullableJSONModel.objects.create(value={"d": ["e", "e"]}) self.assertSequenceEqual( - NullableJSONModel.objects.filter(value__d__0__isnull=False).annotate( - key=F('value__d'), - chain=F('key__0'), - expr=Cast('key', models.JSONField()), - ).filter(chain=F('expr__1')), + NullableJSONModel.objects.filter(value__d__0__isnull=False) + .annotate( + key=F("value__d"), + chain=F("key__0"), + expr=Cast("key", models.JSONField()), + ) + .filter(chain=F("expr__1")), [obj], ) def test_nested_key_transform_expression(self): self.assertSequenceEqual( - NullableJSONModel.objects.filter(value__d__0__isnull=False).annotate( - key=KeyTransform('d', 'value'), - chain=KeyTransform('f', KeyTransform('1', 'key')), - expr=KeyTransform('f', KeyTransform('1', Cast('key', models.JSONField()))), - ).filter(chain=F('expr')), + NullableJSONModel.objects.filter(value__d__0__isnull=False) + .annotate( + key=KeyTransform("d", "value"), + chain=KeyTransform("f", KeyTransform("1", "key")), + expr=KeyTransform( + "f", KeyTransform("1", Cast("key", models.JSONField())) + ), + ) + .filter(chain=F("expr")), [self.objs[4]], ) def test_nested_key_transform_annotation_expression(self): obj = NullableJSONModel.objects.create( - value={'d': ['e', {'f': 'g'}, {'f': 'g'}]}, + value={"d": ["e", {"f": "g"}, {"f": "g"}]}, ) self.assertSequenceEqual( - NullableJSONModel.objects.filter(value__d__0__isnull=False).annotate( - key=F('value__d'), - chain=F('key__1__f'), - expr=Cast('key', models.JSONField()), - ).filter(chain=F('expr__2__f')), + NullableJSONModel.objects.filter(value__d__0__isnull=False) + .annotate( + key=F("value__d"), + chain=F("key__1__f"), + expr=Cast("key", models.JSONField()), + ) + .filter(chain=F("expr__2__f")), [obj], ) def test_nested_key_transform_on_subquery(self): self.assertSequenceEqual( - NullableJSONModel.objects.filter(value__d__0__isnull=False).annotate( + NullableJSONModel.objects.filter(value__d__0__isnull=False) + .annotate( subquery_value=Subquery( - NullableJSONModel.objects.filter(pk=OuterRef('pk')).values('value') + NullableJSONModel.objects.filter(pk=OuterRef("pk")).values("value") ), - key=KeyTransform('d', 'subquery_value'), - chain=KeyTransform('f', KeyTransform('1', 'key')), - ).filter(chain='g'), + key=KeyTransform("d", "subquery_value"), + chain=KeyTransform("f", KeyTransform("1", "key")), + ) + .filter(chain="g"), [self.objs[4]], ) @@ -457,7 +499,7 @@ class TestQuerying(TestCase): self.assertSequenceEqual( NullableJSONModel.objects.annotate( expr=ExpressionWrapper( - KeyTransform('c', 'value'), + KeyTransform("c", "value"), output_field=IntegerField(), ), ).filter(expr__isnull=False), @@ -466,29 +508,39 @@ class TestQuerying(TestCase): def test_has_key(self): self.assertSequenceEqual( - NullableJSONModel.objects.filter(value__has_key='a'), + NullableJSONModel.objects.filter(value__has_key="a"), [self.objs[3], self.objs[4]], ) def test_has_key_null_value(self): self.assertSequenceEqual( - NullableJSONModel.objects.filter(value__has_key='j'), + NullableJSONModel.objects.filter(value__has_key="j"), [self.objs[4]], ) def test_has_key_deep(self): tests = [ - (Q(value__baz__has_key='a'), self.objs[7]), - (Q(value__has_key=KeyTransform('a', KeyTransform('baz', 'value'))), self.objs[7]), - (Q(value__has_key=F('value__baz__a')), self.objs[7]), - (Q(value__has_key=KeyTransform('c', KeyTransform('baz', 'value'))), self.objs[7]), - (Q(value__has_key=F('value__baz__c')), self.objs[7]), - (Q(value__d__1__has_key='f'), self.objs[4]), + (Q(value__baz__has_key="a"), self.objs[7]), + ( + Q(value__has_key=KeyTransform("a", KeyTransform("baz", "value"))), + self.objs[7], + ), + (Q(value__has_key=F("value__baz__a")), self.objs[7]), + ( + Q(value__has_key=KeyTransform("c", KeyTransform("baz", "value"))), + self.objs[7], + ), + (Q(value__has_key=F("value__baz__c")), self.objs[7]), + (Q(value__d__1__has_key="f"), self.objs[4]), ( - Q(value__has_key=KeyTransform('f', KeyTransform('1', KeyTransform('d', 'value')))), + Q( + value__has_key=KeyTransform( + "f", KeyTransform("1", KeyTransform("d", "value")) + ) + ), self.objs[4], ), - (Q(value__has_key=F('value__d__1__f')), self.objs[4]), + (Q(value__has_key=F("value__d__1__f")), self.objs[4]), ] for condition, expected in tests: with self.subTest(condition=condition): @@ -498,12 +550,12 @@ class TestQuerying(TestCase): ) def test_has_key_list(self): - obj = NullableJSONModel.objects.create(value=[{'a': 1}, {'b': 'x'}]) + obj = NullableJSONModel.objects.create(value=[{"a": 1}, {"b": "x"}]) tests = [ - Q(value__1__has_key='b'), - Q(value__has_key=KeyTransform('b', KeyTransform(1, 'value'))), - Q(value__has_key=KeyTransform('b', KeyTransform('1', 'value'))), - Q(value__has_key=F('value__1__b')), + Q(value__1__has_key="b"), + Q(value__has_key=KeyTransform("b", KeyTransform(1, "value"))), + Q(value__has_key=KeyTransform("b", KeyTransform("1", "value"))), + Q(value__has_key=F("value__1__b")), ] for condition in tests: with self.subTest(condition=condition): @@ -514,49 +566,49 @@ class TestQuerying(TestCase): def test_has_keys(self): self.assertSequenceEqual( - NullableJSONModel.objects.filter(value__has_keys=['a', 'c', 'h']), + NullableJSONModel.objects.filter(value__has_keys=["a", "c", "h"]), [self.objs[4]], ) def test_has_any_keys(self): self.assertSequenceEqual( - NullableJSONModel.objects.filter(value__has_any_keys=['c', 'l']), + NullableJSONModel.objects.filter(value__has_any_keys=["c", "l"]), [self.objs[3], self.objs[4], self.objs[6]], ) - @skipUnlessDBFeature('supports_json_field_contains') + @skipUnlessDBFeature("supports_json_field_contains") def test_contains(self): tests = [ ({}, self.objs[2:5] + self.objs[6:8]), - ({'baz': {'a': 'b', 'c': 'd'}}, [self.objs[7]]), - ({'baz': {'a': 'b'}}, [self.objs[7]]), - ({'baz': {'c': 'd'}}, [self.objs[7]]), - ({'k': True, 'l': False}, [self.objs[6]]), - ({'d': ['e', {'f': 'g'}]}, [self.objs[4]]), - ({'d': ['e']}, [self.objs[4]]), - ({'d': [{'f': 'g'}]}, [self.objs[4]]), + ({"baz": {"a": "b", "c": "d"}}, [self.objs[7]]), + ({"baz": {"a": "b"}}, [self.objs[7]]), + ({"baz": {"c": "d"}}, [self.objs[7]]), + ({"k": True, "l": False}, [self.objs[6]]), + ({"d": ["e", {"f": "g"}]}, [self.objs[4]]), + ({"d": ["e"]}, [self.objs[4]]), + ({"d": [{"f": "g"}]}, [self.objs[4]]), ([1, [2]], [self.objs[5]]), ([1], [self.objs[5]]), ([[2]], [self.objs[5]]), - ({'n': [None, True, False]}, [self.objs[4]]), - ({'j': None}, [self.objs[4]]), + ({"n": [None, True, False]}, [self.objs[4]]), + ({"j": None}, [self.objs[4]]), ] for value, expected in tests: with self.subTest(value=value): qs = NullableJSONModel.objects.filter(value__contains=value) self.assertSequenceEqual(qs, expected) - @skipIfDBFeature('supports_json_field_contains') + @skipIfDBFeature("supports_json_field_contains") def test_contains_unsupported(self): - msg = 'contains lookup is not supported on this database backend.' + msg = "contains lookup is not supported on this database backend." with self.assertRaisesMessage(NotSupportedError, msg): NullableJSONModel.objects.filter( - value__contains={'baz': {'a': 'b', 'c': 'd'}}, + value__contains={"baz": {"a": "b", "c": "d"}}, ).get() @skipUnlessDBFeature( - 'supports_primitives_in_json_field', - 'supports_json_field_contains', + "supports_primitives_in_json_field", + "supports_json_field_contains", ) def test_contains_primitives(self): for value in self.primitives: @@ -564,27 +616,31 @@ class TestQuerying(TestCase): qs = NullableJSONModel.objects.filter(value__contains=value) self.assertIs(qs.exists(), True) - @skipUnlessDBFeature('supports_json_field_contains') + @skipUnlessDBFeature("supports_json_field_contains") def test_contained_by(self): - qs = NullableJSONModel.objects.filter(value__contained_by={'a': 'b', 'c': 14, 'h': True}) + qs = NullableJSONModel.objects.filter( + value__contained_by={"a": "b", "c": 14, "h": True} + ) self.assertSequenceEqual(qs, self.objs[2:4]) - @skipIfDBFeature('supports_json_field_contains') + @skipIfDBFeature("supports_json_field_contains") def test_contained_by_unsupported(self): - msg = 'contained_by lookup is not supported on this database backend.' + msg = "contained_by lookup is not supported on this database backend." with self.assertRaisesMessage(NotSupportedError, msg): - NullableJSONModel.objects.filter(value__contained_by={'a': 'b'}).get() + NullableJSONModel.objects.filter(value__contained_by={"a": "b"}).get() def test_deep_values(self): - qs = NullableJSONModel.objects.values_list('value__k__l') + qs = NullableJSONModel.objects.values_list("value__k__l") expected_objs = [(None,)] * len(self.objs) - expected_objs[4] = ('m',) + expected_objs[4] = ("m",) self.assertSequenceEqual(qs, expected_objs) - @skipUnlessDBFeature('can_distinct_on_fields') + @skipUnlessDBFeature("can_distinct_on_fields") def test_deep_distinct(self): - query = NullableJSONModel.objects.distinct('value__k__l').values_list('value__k__l') - self.assertSequenceEqual(query, [('m',), (None,)]) + query = NullableJSONModel.objects.distinct("value__k__l").values_list( + "value__k__l" + ) + self.assertSequenceEqual(query, [("m",), (None,)]) def test_isnull_key(self): # key__isnull=False works the same as has_key='key'. @@ -606,9 +662,11 @@ class TestQuerying(TestCase): ) def test_isnull_key_or_none(self): - obj = NullableJSONModel.objects.create(value={'a': None}) + obj = NullableJSONModel.objects.create(value={"a": None}) self.assertSequenceEqual( - NullableJSONModel.objects.filter(Q(value__a__isnull=True) | Q(value__a=None)), + NullableJSONModel.objects.filter( + Q(value__a__isnull=True) | Q(value__a=None) + ), self.objs[:3] + self.objs[5:] + [obj], ) @@ -619,8 +677,8 @@ class TestQuerying(TestCase): ) def test_none_key_exclude(self): - obj = NullableJSONModel.objects.create(value={'j': 1}) - if connection.vendor == 'oracle': + obj = NullableJSONModel.objects.create(value={"j": 1}) + if connection.vendor == "oracle": # Oracle supports filtering JSON objects with NULL keys, but the # current implementation doesn't support it. self.assertSequenceEqual( @@ -628,7 +686,9 @@ class TestQuerying(TestCase): self.objs[1:4] + self.objs[5:] + [obj], ) else: - self.assertSequenceEqual(NullableJSONModel.objects.exclude(value__j=None), [obj]) + self.assertSequenceEqual( + NullableJSONModel.objects.exclude(value__j=None), [obj] + ) def test_shallow_list_lookup(self): self.assertSequenceEqual( @@ -638,25 +698,27 @@ class TestQuerying(TestCase): def test_shallow_obj_lookup(self): self.assertSequenceEqual( - NullableJSONModel.objects.filter(value__a='b'), + NullableJSONModel.objects.filter(value__a="b"), [self.objs[3], self.objs[4]], ) def test_obj_subquery_lookup(self): qs = NullableJSONModel.objects.annotate( - field=Subquery(NullableJSONModel.objects.filter(pk=OuterRef('pk')).values('value')), - ).filter(field__a='b') + field=Subquery( + NullableJSONModel.objects.filter(pk=OuterRef("pk")).values("value") + ), + ).filter(field__a="b") self.assertSequenceEqual(qs, [self.objs[3], self.objs[4]]) def test_deep_lookup_objs(self): self.assertSequenceEqual( - NullableJSONModel.objects.filter(value__k__l='m'), + NullableJSONModel.objects.filter(value__k__l="m"), [self.objs[4]], ) def test_shallow_lookup_obj_target(self): self.assertSequenceEqual( - NullableJSONModel.objects.filter(value__k={'l': 'm'}), + NullableJSONModel.objects.filter(value__k={"l": "m"}), [self.objs[4]], ) @@ -668,7 +730,7 @@ class TestQuerying(TestCase): def test_deep_lookup_mixed(self): self.assertSequenceEqual( - NullableJSONModel.objects.filter(value__d__1__f='g'), + NullableJSONModel.objects.filter(value__d__1__f="g"), [self.objs[4]], ) @@ -685,8 +747,8 @@ class TestQuerying(TestCase): def test_lookup_exclude(self): tests = [ - (Q(value__a='b'), [self.objs[0]]), - (Q(value__foo='bax'), [self.objs[0], self.objs[7]]), + (Q(value__a="b"), [self.objs[0]]), + (Q(value__foo="bax"), [self.objs[0], self.objs[7]]), ] for condition, expected in tests: self.assertSequenceEqual( @@ -700,7 +762,7 @@ class TestQuerying(TestCase): def test_lookup_exclude_nonexistent_key(self): # Values without the key are ignored. - condition = Q(value__foo='bax') + condition = Q(value__foo="bax") objs_with_value = [self.objs[6]] objs_with_different_value = [self.objs[0], self.objs[7]] self.assertSequenceEqual( @@ -737,13 +799,13 @@ class TestQuerying(TestCase): self.objs[3:5], ) - @skipUnlessDBFeature('supports_json_field_contains') + @skipUnlessDBFeature("supports_json_field_contains") def test_array_key_contains(self): tests = [ ([], [self.objs[7]]), - ('bar', [self.objs[7]]), - (['bar'], [self.objs[7]]), - ('ar', []), + ("bar", [self.objs[7]]), + (["bar"], [self.objs[7]]), + ("ar", []), ] for value, expected in tests: with self.subTest(value=value): @@ -753,34 +815,38 @@ class TestQuerying(TestCase): ) def test_key_iexact(self): - self.assertIs(NullableJSONModel.objects.filter(value__foo__iexact='BaR').exists(), True) - self.assertIs(NullableJSONModel.objects.filter(value__foo__iexact='"BaR"').exists(), False) + self.assertIs( + NullableJSONModel.objects.filter(value__foo__iexact="BaR").exists(), True + ) + self.assertIs( + NullableJSONModel.objects.filter(value__foo__iexact='"BaR"').exists(), False + ) def test_key_in(self): tests = [ - ('value__c__in', [14], self.objs[3:5]), - ('value__c__in', [14, 15], self.objs[3:5]), - ('value__0__in', [1], [self.objs[5]]), - ('value__0__in', [1, 3], [self.objs[5]]), - ('value__foo__in', ['bar'], [self.objs[7]]), + ("value__c__in", [14], self.objs[3:5]), + ("value__c__in", [14, 15], self.objs[3:5]), + ("value__0__in", [1], [self.objs[5]]), + ("value__0__in", [1, 3], [self.objs[5]]), + ("value__foo__in", ["bar"], [self.objs[7]]), ( - 'value__foo__in', - [KeyTransform('foo', KeyTransform('bax', 'value'))], + "value__foo__in", + [KeyTransform("foo", KeyTransform("bax", "value"))], [self.objs[7]], ), - ('value__foo__in', [F('value__bax__foo')], [self.objs[7]]), + ("value__foo__in", [F("value__bax__foo")], [self.objs[7]]), ( - 'value__foo__in', - [KeyTransform('foo', KeyTransform('bax', 'value')), 'baz'], + "value__foo__in", + [KeyTransform("foo", KeyTransform("bax", "value")), "baz"], [self.objs[7]], ), - ('value__foo__in', [F('value__bax__foo'), 'baz'], [self.objs[7]]), - ('value__foo__in', ['bar', 'baz'], [self.objs[7]]), - ('value__bar__in', [['foo', 'bar']], [self.objs[7]]), - ('value__bar__in', [['foo', 'bar'], ['a']], [self.objs[7]]), - ('value__bax__in', [{'foo': 'bar'}, {'a': 'b'}], [self.objs[7]]), - ('value__h__in', [True, 'foo'], [self.objs[4]]), - ('value__i__in', [False, 'foo'], [self.objs[4]]), + ("value__foo__in", [F("value__bax__foo"), "baz"], [self.objs[7]]), + ("value__foo__in", ["bar", "baz"], [self.objs[7]]), + ("value__bar__in", [["foo", "bar"]], [self.objs[7]]), + ("value__bar__in", [["foo", "bar"], ["a"]], [self.objs[7]]), + ("value__bax__in", [{"foo": "bar"}, {"a": "b"}], [self.objs[7]]), + ("value__h__in", [True, "foo"], [self.objs[4]]), + ("value__i__in", [False, "foo"], [self.objs[4]]), ] for lookup, value, expected in tests: with self.subTest(lookup=lookup, value=value): @@ -792,16 +858,16 @@ class TestQuerying(TestCase): def test_key_values(self): qs = NullableJSONModel.objects.filter(value__h=True) tests = [ - ('value__a', 'b'), - ('value__c', 14), - ('value__d', ['e', {'f': 'g'}]), - ('value__h', True), - ('value__i', False), - ('value__j', None), - ('value__k', {'l': 'm'}), - ('value__n', [None, True, False]), - ('value__p', 4.2), - ('value__r', {'s': True, 't': False}), + ("value__a", "b"), + ("value__c", 14), + ("value__d", ["e", {"f": "g"}]), + ("value__h", True), + ("value__i", False), + ("value__j", None), + ("value__k", {"l": "m"}), + ("value__n", [None, True, False]), + ("value__p", 4.2), + ("value__r", {"s": True, "t": False}), ] for lookup, expected in tests: with self.subTest(lookup=lookup): @@ -810,38 +876,56 @@ class TestQuerying(TestCase): def test_key_values_boolean(self): qs = NullableJSONModel.objects.filter(value__h=True, value__i=False) tests = [ - ('value__h', True), - ('value__i', False), + ("value__h", True), + ("value__i", False), ] for lookup, expected in tests: with self.subTest(lookup=lookup): self.assertIs(qs.values_list(lookup, flat=True).get(), expected) - @skipUnlessDBFeature('supports_json_field_contains') + @skipUnlessDBFeature("supports_json_field_contains") def test_key_contains(self): - self.assertIs(NullableJSONModel.objects.filter(value__foo__contains='ar').exists(), False) - self.assertIs(NullableJSONModel.objects.filter(value__foo__contains='bar').exists(), True) + self.assertIs( + NullableJSONModel.objects.filter(value__foo__contains="ar").exists(), False + ) + self.assertIs( + NullableJSONModel.objects.filter(value__foo__contains="bar").exists(), True + ) def test_key_icontains(self): - self.assertIs(NullableJSONModel.objects.filter(value__foo__icontains='Ar').exists(), True) + self.assertIs( + NullableJSONModel.objects.filter(value__foo__icontains="Ar").exists(), True + ) def test_key_startswith(self): - self.assertIs(NullableJSONModel.objects.filter(value__foo__startswith='b').exists(), True) + self.assertIs( + NullableJSONModel.objects.filter(value__foo__startswith="b").exists(), True + ) def test_key_istartswith(self): - self.assertIs(NullableJSONModel.objects.filter(value__foo__istartswith='B').exists(), True) + self.assertIs( + NullableJSONModel.objects.filter(value__foo__istartswith="B").exists(), True + ) def test_key_endswith(self): - self.assertIs(NullableJSONModel.objects.filter(value__foo__endswith='r').exists(), True) + self.assertIs( + NullableJSONModel.objects.filter(value__foo__endswith="r").exists(), True + ) def test_key_iendswith(self): - self.assertIs(NullableJSONModel.objects.filter(value__foo__iendswith='R').exists(), True) + self.assertIs( + NullableJSONModel.objects.filter(value__foo__iendswith="R").exists(), True + ) def test_key_regex(self): - self.assertIs(NullableJSONModel.objects.filter(value__foo__regex=r'^bar$').exists(), True) + self.assertIs( + NullableJSONModel.objects.filter(value__foo__regex=r"^bar$").exists(), True + ) def test_key_iregex(self): - self.assertIs(NullableJSONModel.objects.filter(value__foo__iregex=r'^bAr$').exists(), True) + self.assertIs( + NullableJSONModel.objects.filter(value__foo__iregex=r"^bAr$").exists(), True + ) def test_key_quoted_string(self): self.assertEqual( @@ -849,93 +933,110 @@ class TestQuerying(TestCase): self.objs[4], ) - @skipUnlessDBFeature('has_json_operators') + @skipUnlessDBFeature("has_json_operators") def test_key_sql_injection(self): with CaptureQueriesContext(connection) as queries: self.assertIs( - NullableJSONModel.objects.filter(**{ - """value__test' = '"a"') OR 1 = 1 OR ('d""": 'x', - }).exists(), + NullableJSONModel.objects.filter( + **{ + """value__test' = '"a"') OR 1 = 1 OR ('d""": "x", + } + ).exists(), False, ) self.assertIn( """."value" -> 'test'' = ''"a"'') OR 1 = 1 OR (''d') = '"x"' """, - queries[0]['sql'], + queries[0]["sql"], ) - @skipIfDBFeature('has_json_operators') + @skipIfDBFeature("has_json_operators") def test_key_sql_injection_escape(self): - query = str(JSONModel.objects.filter(**{ - """value__test") = '"a"' OR 1 = 1 OR ("d""": 'x', - }).query) + query = str( + JSONModel.objects.filter( + **{ + """value__test") = '"a"' OR 1 = 1 OR ("d""": "x", + } + ).query + ) self.assertIn('"test\\"', query) self.assertIn('\\"d', query) def test_key_escape(self): - obj = NullableJSONModel.objects.create(value={'%total': 10}) - self.assertEqual(NullableJSONModel.objects.filter(**{'value__%total': 10}).get(), obj) + obj = NullableJSONModel.objects.create(value={"%total": 10}) + self.assertEqual( + NullableJSONModel.objects.filter(**{"value__%total": 10}).get(), obj + ) def test_none_key_and_exact_lookup(self): self.assertSequenceEqual( - NullableJSONModel.objects.filter(value__a='b', value__j=None), + NullableJSONModel.objects.filter(value__a="b", value__j=None), [self.objs[4]], ) def test_lookups_with_key_transform(self): tests = ( - ('value__baz__has_key', 'c'), - ('value__baz__has_keys', ['a', 'c']), - ('value__baz__has_any_keys', ['a', 'x']), - ('value__has_key', KeyTextTransform('foo', 'value')), + ("value__baz__has_key", "c"), + ("value__baz__has_keys", ["a", "c"]), + ("value__baz__has_any_keys", ["a", "x"]), + ("value__has_key", KeyTextTransform("foo", "value")), ) for lookup, value in tests: with self.subTest(lookup=lookup): - self.assertIs(NullableJSONModel.objects.filter( - **{lookup: value}, - ).exists(), True) + self.assertIs( + NullableJSONModel.objects.filter( + **{lookup: value}, + ).exists(), + True, + ) - @skipUnlessDBFeature('supports_json_field_contains') + @skipUnlessDBFeature("supports_json_field_contains") def test_contains_contained_by_with_key_transform(self): tests = [ - ('value__d__contains', 'e'), - ('value__d__contains', [{'f': 'g'}]), - ('value__contains', KeyTransform('bax', 'value')), - ('value__contains', F('value__bax')), - ('value__baz__contains', {'a': 'b'}), - ('value__baz__contained_by', {'a': 'b', 'c': 'd', 'e': 'f'}), + ("value__d__contains", "e"), + ("value__d__contains", [{"f": "g"}]), + ("value__contains", KeyTransform("bax", "value")), + ("value__contains", F("value__bax")), + ("value__baz__contains", {"a": "b"}), + ("value__baz__contained_by", {"a": "b", "c": "d", "e": "f"}), ( - 'value__contained_by', - KeyTransform('x', RawSQL( - self.raw_sql, - ['{"x": {"a": "b", "c": 1, "d": "e"}}'], - )), + "value__contained_by", + KeyTransform( + "x", + RawSQL( + self.raw_sql, + ['{"x": {"a": "b", "c": 1, "d": "e"}}'], + ), + ), ), ] # For databases where {'f': 'g'} (without surrounding []) matches # [{'f': 'g'}]. if not connection.features.json_key_contains_list_matching_requires_list: - tests.append(('value__d__contains', {'f': 'g'})) + tests.append(("value__d__contains", {"f": "g"})) for lookup, value in tests: with self.subTest(lookup=lookup, value=value): - self.assertIs(NullableJSONModel.objects.filter( - **{lookup: value}, - ).exists(), True) + self.assertIs( + NullableJSONModel.objects.filter( + **{lookup: value}, + ).exists(), + True, + ) def test_join_key_transform_annotation_expression(self): related_obj = RelatedJSONModel.objects.create( - value={'d': ['f', 'e']}, + value={"d": ["f", "e"]}, json_model=self.objs[4], ) RelatedJSONModel.objects.create( - value={'d': ['e', 'f']}, + value={"d": ["e", "f"]}, json_model=self.objs[4], ) self.assertSequenceEqual( RelatedJSONModel.objects.annotate( - key=F('value__d'), - related_key=F('json_model__value__d'), - chain=F('key__1'), - expr=Cast('key', models.JSONField()), - ).filter(chain=F('related_key__0')), + key=F("value__d"), + related_key=F("json_model__value__d"), + chain=F("key__1"), + expr=Cast("key", models.JSONField()), + ).filter(chain=F("related_key__0")), [related_obj], ) diff --git a/tests/model_fields/test_manytomanyfield.py b/tests/model_fields/test_manytomanyfield.py index 0ddf57ceaf..3dbc267634 100644 --- a/tests/model_fields/test_manytomanyfield.py +++ b/tests/model_fields/test_manytomanyfield.py @@ -7,7 +7,6 @@ from .models import ManyToMany class ManyToManyFieldTests(SimpleTestCase): - def test_abstract_model_pending_operations(self): """ Many-to-many fields declared on abstract models should not add lazy @@ -16,7 +15,7 @@ class ManyToManyFieldTests(SimpleTestCase): pending_ops_before = list(apps._pending_operations.items()) class AbstractManyToManyModel(models.Model): - fk = models.ForeignKey('missing.FK', models.CASCADE) + fk = models.ForeignKey("missing.FK", models.CASCADE) class Meta: abstract = True @@ -25,16 +24,16 @@ class ManyToManyFieldTests(SimpleTestCase): self.assertEqual( pending_ops_before, list(apps._pending_operations.items()), - 'Pending lookup added for a many-to-many field on an abstract model' + "Pending lookup added for a many-to-many field on an abstract model", ) - @isolate_apps('model_fields', 'model_fields.tests') + @isolate_apps("model_fields", "model_fields.tests") def test_abstract_model_app_relative_foreign_key(self): class AbstractReferent(models.Model): - reference = models.ManyToManyField('Referred', through='Through') + reference = models.ManyToManyField("Referred", through="Through") class Meta: - app_label = 'model_fields' + app_label = "model_fields" abstract = True def assert_app_model_resolved(label): @@ -43,8 +42,10 @@ class ManyToManyFieldTests(SimpleTestCase): app_label = label class Through(models.Model): - referred = models.ForeignKey('Referred', on_delete=models.CASCADE) - referent = models.ForeignKey('ConcreteReferent', on_delete=models.CASCADE) + referred = models.ForeignKey("Referred", on_delete=models.CASCADE) + referent = models.ForeignKey( + "ConcreteReferent", on_delete=models.CASCADE + ) class Meta: app_label = label @@ -53,11 +54,13 @@ class ManyToManyFieldTests(SimpleTestCase): class Meta: app_label = label - self.assertEqual(ConcreteReferent._meta.get_field('reference').related_model, Referred) + self.assertEqual( + ConcreteReferent._meta.get_field("reference").related_model, Referred + ) self.assertEqual(ConcreteReferent.reference.through, Through) - assert_app_model_resolved('model_fields') - assert_app_model_resolved('tests') + assert_app_model_resolved("model_fields") + assert_app_model_resolved("tests") def test_invalid_to_parameter(self): msg = ( @@ -66,10 +69,11 @@ class ManyToManyFieldTests(SimpleTestCase): "string 'self'" ) with self.assertRaisesMessage(TypeError, msg): + class MyModel(models.Model): m2m = models.ManyToManyField(1) - @isolate_apps('model_fields') + @isolate_apps("model_fields") def test_through_db_table_mutually_exclusive(self): class Child(models.Model): pass @@ -78,24 +82,26 @@ class ManyToManyFieldTests(SimpleTestCase): referred = models.ForeignKey(Child, on_delete=models.CASCADE) referent = models.ForeignKey(Child, on_delete=models.CASCADE) - msg = 'Cannot specify a db_table if an intermediary model is used.' + msg = "Cannot specify a db_table if an intermediary model is used." with self.assertRaisesMessage(ValueError, msg): + class MyModel(models.Model): m2m = models.ManyToManyField( Child, - through='Through', - db_table='custom_name', + through="Through", + db_table="custom_name", ) class ManyToManyFieldDBTests(TestCase): - def test_value_from_object_instance_without_pk(self): obj = ManyToMany() - self.assertEqual(obj._meta.get_field('m2m').value_from_object(obj), []) + self.assertEqual(obj._meta.get_field("m2m").value_from_object(obj), []) def test_value_from_object_instance_with_pk(self): obj = ManyToMany.objects.create() related_obj = ManyToMany.objects.create() obj.m2m.add(related_obj) - self.assertEqual(obj._meta.get_field('m2m').value_from_object(obj), [related_obj]) + self.assertEqual( + obj._meta.get_field("m2m").value_from_object(obj), [related_obj] + ) diff --git a/tests/model_fields/test_promises.py b/tests/model_fields/test_promises.py index f48a4cc34a..bfc09f590d 100644 --- a/tests/model_fields/test_promises.py +++ b/tests/model_fields/test_promises.py @@ -2,24 +2,43 @@ import datetime from decimal import Decimal from django.db.models import ( - AutoField, BinaryField, BooleanField, CharField, DateField, DateTimeField, - DecimalField, EmailField, FileField, FilePathField, FloatField, - GenericIPAddressField, ImageField, IntegerField, IPAddressField, - PositiveBigIntegerField, PositiveIntegerField, PositiveSmallIntegerField, - SlugField, SmallIntegerField, TextField, TimeField, URLField, + AutoField, + BinaryField, + BooleanField, + CharField, + DateField, + DateTimeField, + DecimalField, + EmailField, + FileField, + FilePathField, + FloatField, + GenericIPAddressField, + ImageField, + IntegerField, + IPAddressField, + PositiveBigIntegerField, + PositiveIntegerField, + PositiveSmallIntegerField, + SlugField, + SmallIntegerField, + TextField, + TimeField, + URLField, ) from django.test import SimpleTestCase from django.utils.functional import lazy class PromiseTest(SimpleTestCase): - def test_AutoField(self): lazy_func = lazy(lambda: 1, int) - self.assertIsInstance(AutoField(primary_key=True).get_prep_value(lazy_func()), int) + self.assertIsInstance( + AutoField(primary_key=True).get_prep_value(lazy_func()), int + ) def test_BinaryField(self): - lazy_func = lazy(lambda: b'', bytes) + lazy_func = lazy(lambda: b"", bytes) self.assertIsInstance(BinaryField().get_prep_value(lazy_func()), bytes) def test_BooleanField(self): @@ -27,7 +46,7 @@ class PromiseTest(SimpleTestCase): self.assertIsInstance(BooleanField().get_prep_value(lazy_func()), bool) def test_CharField(self): - lazy_func = lazy(lambda: '', str) + lazy_func = lazy(lambda: "", str) self.assertIsInstance(CharField().get_prep_value(lazy_func()), str) lazy_func = lazy(lambda: 0, int) self.assertIsInstance(CharField().get_prep_value(lazy_func()), str) @@ -38,24 +57,26 @@ class PromiseTest(SimpleTestCase): def test_DateTimeField(self): lazy_func = lazy(lambda: datetime.datetime.now(), datetime.datetime) - self.assertIsInstance(DateTimeField().get_prep_value(lazy_func()), datetime.datetime) + self.assertIsInstance( + DateTimeField().get_prep_value(lazy_func()), datetime.datetime + ) def test_DecimalField(self): - lazy_func = lazy(lambda: Decimal('1.2'), Decimal) + lazy_func = lazy(lambda: Decimal("1.2"), Decimal) self.assertIsInstance(DecimalField().get_prep_value(lazy_func()), Decimal) def test_EmailField(self): - lazy_func = lazy(lambda: 'mailbox@domain.com', str) + lazy_func = lazy(lambda: "mailbox@domain.com", str) self.assertIsInstance(EmailField().get_prep_value(lazy_func()), str) def test_FileField(self): - lazy_func = lazy(lambda: 'filename.ext', str) + lazy_func = lazy(lambda: "filename.ext", str) self.assertIsInstance(FileField().get_prep_value(lazy_func()), str) lazy_func = lazy(lambda: 0, int) self.assertIsInstance(FileField().get_prep_value(lazy_func()), str) def test_FilePathField(self): - lazy_func = lazy(lambda: 'tests.py', str) + lazy_func = lazy(lambda: "tests.py", str) self.assertIsInstance(FilePathField().get_prep_value(lazy_func()), str) lazy_func = lazy(lambda: 0, int) self.assertIsInstance(FilePathField().get_prep_value(lazy_func()), str) @@ -65,7 +86,7 @@ class PromiseTest(SimpleTestCase): self.assertIsInstance(FloatField().get_prep_value(lazy_func()), float) def test_ImageField(self): - lazy_func = lazy(lambda: 'filename.ext', str) + lazy_func = lazy(lambda: "filename.ext", str) self.assertIsInstance(ImageField().get_prep_value(lazy_func()), str) def test_IntegerField(self): @@ -73,13 +94,13 @@ class PromiseTest(SimpleTestCase): self.assertIsInstance(IntegerField().get_prep_value(lazy_func()), int) def test_IPAddressField(self): - lazy_func = lazy(lambda: '127.0.0.1', str) + lazy_func = lazy(lambda: "127.0.0.1", str) self.assertIsInstance(IPAddressField().get_prep_value(lazy_func()), str) lazy_func = lazy(lambda: 0, int) self.assertIsInstance(IPAddressField().get_prep_value(lazy_func()), str) def test_GenericIPAddressField(self): - lazy_func = lazy(lambda: '127.0.0.1', str) + lazy_func = lazy(lambda: "127.0.0.1", str) self.assertIsInstance(GenericIPAddressField().get_prep_value(lazy_func()), str) lazy_func = lazy(lambda: 0, int) self.assertIsInstance(GenericIPAddressField().get_prep_value(lazy_func()), str) @@ -90,14 +111,18 @@ class PromiseTest(SimpleTestCase): def test_PositiveSmallIntegerField(self): lazy_func = lazy(lambda: 1, int) - self.assertIsInstance(PositiveSmallIntegerField().get_prep_value(lazy_func()), int) + self.assertIsInstance( + PositiveSmallIntegerField().get_prep_value(lazy_func()), int + ) def test_PositiveBigIntegerField(self): lazy_func = lazy(lambda: 1, int) - self.assertIsInstance(PositiveBigIntegerField().get_prep_value(lazy_func()), int) + self.assertIsInstance( + PositiveBigIntegerField().get_prep_value(lazy_func()), int + ) def test_SlugField(self): - lazy_func = lazy(lambda: 'slug', str) + lazy_func = lazy(lambda: "slug", str) self.assertIsInstance(SlugField().get_prep_value(lazy_func()), str) lazy_func = lazy(lambda: 0, int) self.assertIsInstance(SlugField().get_prep_value(lazy_func()), str) @@ -107,7 +132,7 @@ class PromiseTest(SimpleTestCase): self.assertIsInstance(SmallIntegerField().get_prep_value(lazy_func()), int) def test_TextField(self): - lazy_func = lazy(lambda: 'Abc', str) + lazy_func = lazy(lambda: "Abc", str) self.assertIsInstance(TextField().get_prep_value(lazy_func()), str) lazy_func = lazy(lambda: 0, int) self.assertIsInstance(TextField().get_prep_value(lazy_func()), str) @@ -117,5 +142,5 @@ class PromiseTest(SimpleTestCase): self.assertIsInstance(TimeField().get_prep_value(lazy_func()), datetime.time) def test_URLField(self): - lazy_func = lazy(lambda: 'http://domain.com', str) + lazy_func = lazy(lambda: "http://domain.com", str) self.assertIsInstance(URLField().get_prep_value(lazy_func()), str) diff --git a/tests/model_fields/test_slugfield.py b/tests/model_fields/test_slugfield.py index 3dc955d3ad..4d000c9276 100644 --- a/tests/model_fields/test_slugfield.py +++ b/tests/model_fields/test_slugfield.py @@ -4,19 +4,18 @@ from .models import BigS, UnicodeSlugField class SlugFieldTests(TestCase): - def test_slugfield_max_length(self): """ SlugField honors max_length. """ - bs = BigS.objects.create(s='slug' * 50) + bs = BigS.objects.create(s="slug" * 50) bs = BigS.objects.get(pk=bs.pk) - self.assertEqual(bs.s, 'slug' * 50) + self.assertEqual(bs.s, "slug" * 50) def test_slugfield_unicode_max_length(self): """ SlugField with allow_unicode=True honors max_length. """ - bs = UnicodeSlugField.objects.create(s='你好你好' * 50) + bs = UnicodeSlugField.objects.create(s="你好你好" * 50) bs = UnicodeSlugField.objects.get(pk=bs.pk) - self.assertEqual(bs.s, '你好你好' * 50) + self.assertEqual(bs.s, "你好你好" * 50) diff --git a/tests/model_fields/test_textfield.py b/tests/model_fields/test_textfield.py index dd5f5a5280..63d6f1cda2 100644 --- a/tests/model_fields/test_textfield.py +++ b/tests/model_fields/test_textfield.py @@ -6,7 +6,6 @@ from .models import Post class TextFieldTests(TestCase): - def test_max_length_passed_to_formfield(self): """ TextField passes its max_length attribute to form fields created using @@ -19,21 +18,21 @@ class TextFieldTests(TestCase): def test_choices_generates_select_widget(self): """A TextField with choices uses a Select widget.""" - f = models.TextField(choices=[('A', 'A'), ('B', 'B')]) + f = models.TextField(choices=[("A", "A"), ("B", "B")]) self.assertIsInstance(f.formfield().widget, forms.Select) def test_to_python(self): """TextField.to_python() should return a string.""" f = models.TextField() - self.assertEqual(f.to_python(1), '1') + self.assertEqual(f.to_python(1), "1") def test_lookup_integer_in_textfield(self): self.assertEqual(Post.objects.filter(body=24).count(), 0) def test_emoji(self): - p = Post.objects.create(title='Whatever', body='Smile 😀.') + p = Post.objects.create(title="Whatever", body="Smile 😀.") p.refresh_from_db() - self.assertEqual(p.body, 'Smile 😀.') + self.assertEqual(p.body, "Smile 😀.") class TestMethods(SimpleTestCase): @@ -41,6 +40,6 @@ class TestMethods(SimpleTestCase): field = models.TextField() *_, kwargs = field.deconstruct() self.assertEqual(kwargs, {}) - field = models.TextField(db_collation='utf8_esperanto_ci') + field = models.TextField(db_collation="utf8_esperanto_ci") *_, kwargs = field.deconstruct() - self.assertEqual(kwargs, {'db_collation': 'utf8_esperanto_ci'}) + self.assertEqual(kwargs, {"db_collation": "utf8_esperanto_ci"}) diff --git a/tests/model_fields/test_uuid.py b/tests/model_fields/test_uuid.py index c53df2c7af..c7776cf6b5 100644 --- a/tests/model_fields/test_uuid.py +++ b/tests/model_fields/test_uuid.py @@ -6,11 +6,17 @@ from django.db import IntegrityError, connection, models from django.db.models import CharField, F, Value from django.db.models.functions import Concat, Repeat from django.test import ( - SimpleTestCase, TestCase, TransactionTestCase, skipUnlessDBFeature, + SimpleTestCase, + TestCase, + TransactionTestCase, + skipUnlessDBFeature, ) from .models import ( - NullableUUIDModel, PrimaryKeyUUIDModel, RelatedToUUIDModel, UUIDGrandchild, + NullableUUIDModel, + PrimaryKeyUUIDModel, + RelatedToUUIDModel, + UUIDGrandchild, UUIDModel, ) @@ -22,19 +28,19 @@ class TestSaveLoad(TestCase): self.assertEqual(loaded.field, instance.field) def test_str_instance_no_hyphens(self): - UUIDModel.objects.create(field='550e8400e29b41d4a716446655440000') + UUIDModel.objects.create(field="550e8400e29b41d4a716446655440000") loaded = UUIDModel.objects.get() - self.assertEqual(loaded.field, uuid.UUID('550e8400e29b41d4a716446655440000')) + self.assertEqual(loaded.field, uuid.UUID("550e8400e29b41d4a716446655440000")) def test_str_instance_hyphens(self): - UUIDModel.objects.create(field='550e8400-e29b-41d4-a716-446655440000') + UUIDModel.objects.create(field="550e8400-e29b-41d4-a716-446655440000") loaded = UUIDModel.objects.get() - self.assertEqual(loaded.field, uuid.UUID('550e8400e29b41d4a716446655440000')) + self.assertEqual(loaded.field, uuid.UUID("550e8400e29b41d4a716446655440000")) def test_str_instance_bad_hyphens(self): - UUIDModel.objects.create(field='550e84-00-e29b-41d4-a716-4-466-55440000') + UUIDModel.objects.create(field="550e84-00-e29b-41d4-a716-4-466-55440000") loaded = UUIDModel.objects.get() - self.assertEqual(loaded.field, uuid.UUID('550e8400e29b41d4a716446655440000')) + self.assertEqual(loaded.field, uuid.UUID("550e8400e29b41d4a716446655440000")) def test_null_handling(self): NullableUUIDModel.objects.create(field=None) @@ -42,22 +48,29 @@ class TestSaveLoad(TestCase): self.assertIsNone(loaded.field) def test_pk_validated(self): - with self.assertRaisesMessage(exceptions.ValidationError, 'is not a valid UUID'): + with self.assertRaisesMessage( + exceptions.ValidationError, "is not a valid UUID" + ): PrimaryKeyUUIDModel.objects.get(pk={}) - with self.assertRaisesMessage(exceptions.ValidationError, 'is not a valid UUID'): + with self.assertRaisesMessage( + exceptions.ValidationError, "is not a valid UUID" + ): PrimaryKeyUUIDModel.objects.get(pk=[]) def test_wrong_value(self): - with self.assertRaisesMessage(exceptions.ValidationError, 'is not a valid UUID'): - UUIDModel.objects.get(field='not-a-uuid') + with self.assertRaisesMessage( + exceptions.ValidationError, "is not a valid UUID" + ): + UUIDModel.objects.get(field="not-a-uuid") - with self.assertRaisesMessage(exceptions.ValidationError, 'is not a valid UUID'): - UUIDModel.objects.create(field='not-a-uuid') + with self.assertRaisesMessage( + exceptions.ValidationError, "is not a valid UUID" + ): + UUIDModel.objects.create(field="not-a-uuid") class TestMethods(SimpleTestCase): - def test_deconstruct(self): field = models.UUIDField() name, path, args, kwargs = field.deconstruct() @@ -69,18 +82,18 @@ class TestMethods(SimpleTestCase): def test_to_python_int_values(self): self.assertEqual( models.UUIDField().to_python(0), - uuid.UUID('00000000-0000-0000-0000-000000000000') + uuid.UUID("00000000-0000-0000-0000-000000000000"), ) # Works for integers less than 128 bits. self.assertEqual( - models.UUIDField().to_python((2 ** 128) - 1), - uuid.UUID('ffffffff-ffff-ffff-ffff-ffffffffffff') + models.UUIDField().to_python((2**128) - 1), + uuid.UUID("ffffffff-ffff-ffff-ffff-ffffffffffff"), ) def test_to_python_int_too_large(self): # Fails for integers larger than 128 bits. with self.assertRaises(exceptions.ValidationError): - models.UUIDField().to_python(2 ** 128) + models.UUIDField().to_python(2**128) class TestQuerying(TestCase): @@ -88,9 +101,9 @@ class TestQuerying(TestCase): def setUpTestData(cls): cls.objs = [ NullableUUIDModel.objects.create( - field=uuid.UUID('25d405be-4895-4d50-9b2e-d6695359ce47'), + field=uuid.UUID("25d405be-4895-4d50-9b2e-d6695359ce47"), ), - NullableUUIDModel.objects.create(field='550e8400e29b41d4a716446655440000'), + NullableUUIDModel.objects.create(field="550e8400e29b41d4a716446655440000"), NullableUUIDModel.objects.create(field=None), ] @@ -106,12 +119,14 @@ class TestQuerying(TestCase): def test_exact(self): self.assertSequenceEqual( - NullableUUIDModel.objects.filter(field__exact='550e8400e29b41d4a716446655440000'), - [self.objs[1]] + NullableUUIDModel.objects.filter( + field__exact="550e8400e29b41d4a716446655440000" + ), + [self.objs[1]], ) self.assertSequenceEqual( NullableUUIDModel.objects.filter( - field__exact='550e8400-e29b-41d4-a716-446655440000' + field__exact="550e8400-e29b-41d4-a716-446655440000" ), [self.objs[1]], ) @@ -119,100 +134,101 @@ class TestQuerying(TestCase): def test_iexact(self): self.assertSequenceEqualWithoutHyphens( NullableUUIDModel.objects.filter( - field__iexact='550E8400E29B41D4A716446655440000' + field__iexact="550E8400E29B41D4A716446655440000" ), [self.objs[1]], ) self.assertSequenceEqual( NullableUUIDModel.objects.filter( - field__iexact='550E8400-E29B-41D4-A716-446655440000' + field__iexact="550E8400-E29B-41D4-A716-446655440000" ), [self.objs[1]], ) def test_isnull(self): self.assertSequenceEqual( - NullableUUIDModel.objects.filter(field__isnull=True), - [self.objs[2]] + NullableUUIDModel.objects.filter(field__isnull=True), [self.objs[2]] ) def test_contains(self): self.assertSequenceEqualWithoutHyphens( - NullableUUIDModel.objects.filter(field__contains='8400e29b'), + NullableUUIDModel.objects.filter(field__contains="8400e29b"), [self.objs[1]], ) self.assertSequenceEqual( - NullableUUIDModel.objects.filter(field__contains='8400-e29b'), + NullableUUIDModel.objects.filter(field__contains="8400-e29b"), [self.objs[1]], ) def test_icontains(self): self.assertSequenceEqualWithoutHyphens( - NullableUUIDModel.objects.filter(field__icontains='8400E29B'), + NullableUUIDModel.objects.filter(field__icontains="8400E29B"), [self.objs[1]], ) self.assertSequenceEqual( - NullableUUIDModel.objects.filter(field__icontains='8400-E29B'), + NullableUUIDModel.objects.filter(field__icontains="8400-E29B"), [self.objs[1]], ) def test_startswith(self): self.assertSequenceEqualWithoutHyphens( - NullableUUIDModel.objects.filter(field__startswith='550e8400e29b4'), + NullableUUIDModel.objects.filter(field__startswith="550e8400e29b4"), [self.objs[1]], ) self.assertSequenceEqual( - NullableUUIDModel.objects.filter(field__startswith='550e8400-e29b-4'), + NullableUUIDModel.objects.filter(field__startswith="550e8400-e29b-4"), [self.objs[1]], ) def test_istartswith(self): self.assertSequenceEqualWithoutHyphens( - NullableUUIDModel.objects.filter(field__istartswith='550E8400E29B4'), + NullableUUIDModel.objects.filter(field__istartswith="550E8400E29B4"), [self.objs[1]], ) self.assertSequenceEqual( - NullableUUIDModel.objects.filter(field__istartswith='550E8400-E29B-4'), + NullableUUIDModel.objects.filter(field__istartswith="550E8400-E29B-4"), [self.objs[1]], ) def test_endswith(self): self.assertSequenceEqualWithoutHyphens( - NullableUUIDModel.objects.filter(field__endswith='a716446655440000'), + NullableUUIDModel.objects.filter(field__endswith="a716446655440000"), [self.objs[1]], ) self.assertSequenceEqual( - NullableUUIDModel.objects.filter(field__endswith='a716-446655440000'), + NullableUUIDModel.objects.filter(field__endswith="a716-446655440000"), [self.objs[1]], ) def test_iendswith(self): self.assertSequenceEqualWithoutHyphens( - NullableUUIDModel.objects.filter(field__iendswith='A716446655440000'), + NullableUUIDModel.objects.filter(field__iendswith="A716446655440000"), [self.objs[1]], ) self.assertSequenceEqual( - NullableUUIDModel.objects.filter(field__iendswith='A716-446655440000'), + NullableUUIDModel.objects.filter(field__iendswith="A716-446655440000"), [self.objs[1]], ) def test_filter_with_expr(self): self.assertSequenceEqualWithoutHyphens( NullableUUIDModel.objects.annotate( - value=Concat(Value('8400'), Value('e29b'), output_field=CharField()), - ).filter(field__contains=F('value')), + value=Concat(Value("8400"), Value("e29b"), output_field=CharField()), + ).filter(field__contains=F("value")), [self.objs[1]], ) self.assertSequenceEqual( NullableUUIDModel.objects.annotate( - value=Concat(Value('8400'), Value('-'), Value('e29b'), output_field=CharField()), - ).filter(field__contains=F('value')), + value=Concat( + Value("8400"), Value("-"), Value("e29b"), output_field=CharField() + ), + ).filter(field__contains=F("value")), [self.objs[1]], ) self.assertSequenceEqual( NullableUUIDModel.objects.annotate( - value=Repeat(Value('0'), 4, output_field=CharField()), - ).filter(field__contains=F('value')), + value=Repeat(Value("0"), 4, output_field=CharField()), + ).filter(field__contains=F("value")), [self.objs[1]], ) @@ -228,16 +244,20 @@ class TestSerialization(SimpleTestCase): ) def test_dumping(self): - instance = UUIDModel(field=uuid.UUID('550e8400e29b41d4a716446655440000')) - data = serializers.serialize('json', [instance]) + instance = UUIDModel(field=uuid.UUID("550e8400e29b41d4a716446655440000")) + data = serializers.serialize("json", [instance]) self.assertEqual(json.loads(data), json.loads(self.test_data)) def test_loading(self): - instance = list(serializers.deserialize('json', self.test_data))[0].object - self.assertEqual(instance.field, uuid.UUID('550e8400-e29b-41d4-a716-446655440000')) + instance = list(serializers.deserialize("json", self.test_data))[0].object + self.assertEqual( + instance.field, uuid.UUID("550e8400-e29b-41d4-a716-446655440000") + ) def test_nullable_loading(self): - instance = list(serializers.deserialize('json', self.nullable_test_data))[0].object + instance = list(serializers.deserialize("json", self.nullable_test_data))[ + 0 + ].object self.assertIsNone(instance.field) @@ -245,9 +265,12 @@ class TestValidation(SimpleTestCase): def test_invalid_uuid(self): field = models.UUIDField() with self.assertRaises(exceptions.ValidationError) as cm: - field.clean('550e8400', None) - self.assertEqual(cm.exception.code, 'invalid') - self.assertEqual(cm.exception.message % cm.exception.params, '“550e8400” is not a valid UUID.') + field.clean("550e8400", None) + self.assertEqual(cm.exception.code, "invalid") + self.assertEqual( + cm.exception.message % cm.exception.params, + "“550e8400” is not a valid UUID.", + ) def test_uuid_instance_ok(self): field = models.UUIDField() @@ -311,9 +334,9 @@ class TestAsPrimaryKey(TestCase): class TestAsPrimaryKeyTransactionTests(TransactionTestCase): # Need a TransactionTestCase to avoid deferring FK constraint checking. - available_apps = ['model_fields'] + available_apps = ["model_fields"] - @skipUnlessDBFeature('supports_foreign_keys') + @skipUnlessDBFeature("supports_foreign_keys") def test_unsaved_fk(self): u1 = PrimaryKeyUUIDModel() with self.assertRaises(IntegrityError): diff --git a/tests/model_fields/tests.py b/tests/model_fields/tests.py index 86365989f0..eb21d436d8 100644 --- a/tests/model_fields/tests.py +++ b/tests/model_fields/tests.py @@ -7,8 +7,15 @@ from django.test import SimpleTestCase, TestCase from django.utils.functional import lazy from .models import ( - Bar, Choiceful, Foo, RenamedField, VerboseNameField, Whiz, WhizDelayed, - WhizIter, WhizIterEmpty, + Bar, + Choiceful, + Foo, + RenamedField, + VerboseNameField, + Whiz, + WhizDelayed, + WhizIter, + WhizIterEmpty, ) @@ -18,7 +25,6 @@ class Nested: class BasicFieldTests(SimpleTestCase): - def test_show_hidden_initial(self): """ Fields with choices respect show_hidden_initial as a kwarg to @@ -36,14 +42,14 @@ class BasicFieldTests(SimpleTestCase): """ __repr__() of a field displays its name. """ - f = Foo._meta.get_field('a') - self.assertEqual(repr(f), '<django.db.models.fields.CharField: a>') + f = Foo._meta.get_field("a") + self.assertEqual(repr(f), "<django.db.models.fields.CharField: a>") f = models.fields.CharField() - self.assertEqual(repr(f), '<django.db.models.fields.CharField>') + self.assertEqual(repr(f), "<django.db.models.fields.CharField>") def test_field_repr_nested(self): """__repr__() uses __qualname__ for nested class support.""" - self.assertEqual(repr(Nested.Field()), '<model_fields.tests.Nested.Field>') + self.assertEqual(repr(Nested.Field()), "<model_fields.tests.Nested.Field>") def test_field_name(self): """ @@ -51,34 +57,36 @@ class BasicFieldTests(SimpleTestCase): model's attribute name (modelname). """ instance = RenamedField() - self.assertTrue(hasattr(instance, 'get_fieldname_display')) - self.assertFalse(hasattr(instance, 'get_modelname_display')) + self.assertTrue(hasattr(instance, "get_fieldname_display")) + self.assertFalse(hasattr(instance, "get_modelname_display")) def test_field_verbose_name(self): m = VerboseNameField for i in range(1, 22): - self.assertEqual(m._meta.get_field('field%d' % i).verbose_name, 'verbose field%d' % i) + self.assertEqual( + m._meta.get_field("field%d" % i).verbose_name, "verbose field%d" % i + ) - self.assertEqual(m._meta.get_field('id').verbose_name, 'verbose pk') + self.assertEqual(m._meta.get_field("id").verbose_name, "verbose pk") def test_choices_form_class(self): """Can supply a custom choices form class to Field.formfield()""" - choices = [('a', 'a')] + choices = [("a", "a")] field = models.CharField(choices=choices) klass = forms.TypedMultipleChoiceField self.assertIsInstance(field.formfield(choices_form_class=klass), klass) def test_formfield_disabled(self): """Field.formfield() sets disabled for fields with choices.""" - field = models.CharField(choices=[('a', 'b')]) + field = models.CharField(choices=[("a", "b")]) form_field = field.formfield(disabled=True) self.assertIs(form_field.disabled, True) def test_field_str(self): f = models.Field() - self.assertEqual(str(f), '<django.db.models.fields.Field>') - f = Foo._meta.get_field('a') - self.assertEqual(str(f), 'model_fields.Foo.a') + self.assertEqual(str(f), "<django.db.models.fields.Field>") + f = Foo._meta.get_field("a") + self.assertEqual(str(f), "model_fields.Foo.a") def test_field_ordering(self): """Fields are ordered based on their creation.""" @@ -88,11 +96,11 @@ class BasicFieldTests(SimpleTestCase): self.assertLess(f2, f1) self.assertGreater(f3, f1) self.assertIsNotNone(f1) - self.assertNotIn(f2, (None, 1, '')) + self.assertNotIn(f2, (None, 1, "")) def test_field_instance_is_picklable(self): """Field instances can be pickled.""" - field = models.Field(max_length=100, default='a string') + field = models.Field(max_length=100, default="a string") # Must be picklable with this cached property populated (#28188). field._get_default pickle.dumps(field) @@ -100,10 +108,11 @@ class BasicFieldTests(SimpleTestCase): def test_deconstruct_nested_field(self): """deconstruct() uses __qualname__ for nested class support.""" name, path, args, kwargs = Nested.Field().deconstruct() - self.assertEqual(path, 'model_fields.tests.Nested.Field') + self.assertEqual(path, "model_fields.tests.Nested.Field") def test_abstract_inherited_fields(self): """Field instances from abstract models are not equal.""" + class AbstractModel(models.Model): field = models.IntegerField() @@ -116,9 +125,9 @@ class BasicFieldTests(SimpleTestCase): class InheritAbstractModel2(AbstractModel): pass - abstract_model_field = AbstractModel._meta.get_field('field') - inherit1_model_field = InheritAbstractModel1._meta.get_field('field') - inherit2_model_field = InheritAbstractModel2._meta.get_field('field') + abstract_model_field = AbstractModel._meta.get_field("field") + inherit1_model_field = InheritAbstractModel1._meta.get_field("field") + inherit2_model_field = InheritAbstractModel2._meta.get_field("field") self.assertNotEqual(abstract_model_field, inherit1_model_field) self.assertNotEqual(abstract_model_field, inherit2_model_field) @@ -139,25 +148,24 @@ class BasicFieldTests(SimpleTestCase): class ChoicesTests(SimpleTestCase): - @classmethod def setUpClass(cls): super().setUpClass() - cls.no_choices = Choiceful._meta.get_field('no_choices') - cls.empty_choices = Choiceful._meta.get_field('empty_choices') - cls.empty_choices_bool = Choiceful._meta.get_field('empty_choices_bool') - cls.empty_choices_text = Choiceful._meta.get_field('empty_choices_text') - cls.with_choices = Choiceful._meta.get_field('with_choices') + cls.no_choices = Choiceful._meta.get_field("no_choices") + cls.empty_choices = Choiceful._meta.get_field("empty_choices") + cls.empty_choices_bool = Choiceful._meta.get_field("empty_choices_bool") + cls.empty_choices_text = Choiceful._meta.get_field("empty_choices_text") + cls.with_choices = Choiceful._meta.get_field("with_choices") def test_choices(self): self.assertIsNone(self.no_choices.choices) self.assertEqual(self.empty_choices.choices, ()) - self.assertEqual(self.with_choices.choices, [(1, 'A')]) + self.assertEqual(self.with_choices.choices, [(1, "A")]) def test_flatchoices(self): self.assertEqual(self.no_choices.flatchoices, []) self.assertEqual(self.empty_choices.flatchoices, []) - self.assertEqual(self.with_choices.flatchoices, [(1, 'A')]) + self.assertEqual(self.with_choices.flatchoices, [(1, "A")]) def test_check(self): self.assertEqual(Choiceful.check(), []) @@ -175,7 +183,9 @@ class ChoicesTests(SimpleTestCase): no_choices_formfield = self.no_choices.formfield() self.assertIsInstance(no_choices_formfield, forms.IntegerField) fields = ( - self.empty_choices, self.with_choices, self.empty_choices_bool, + self.empty_choices, + self.with_choices, + self.empty_choices_bool, self.empty_choices_text, ) for field in fields: @@ -184,163 +194,164 @@ class ChoicesTests(SimpleTestCase): class GetFieldDisplayTests(SimpleTestCase): - def test_choices_and_field_display(self): """ get_choices() interacts with get_FIELD_display() to return the expected values. """ - self.assertEqual(Whiz(c=1).get_c_display(), 'First') # A nested value - self.assertEqual(Whiz(c=0).get_c_display(), 'Other') # A top level value - self.assertEqual(Whiz(c=9).get_c_display(), 9) # Invalid value - self.assertIsNone(Whiz(c=None).get_c_display()) # Blank value - self.assertEqual(Whiz(c='').get_c_display(), '') # Empty value - self.assertEqual(WhizDelayed(c=0).get_c_display(), 'Other') # Delayed choices + self.assertEqual(Whiz(c=1).get_c_display(), "First") # A nested value + self.assertEqual(Whiz(c=0).get_c_display(), "Other") # A top level value + self.assertEqual(Whiz(c=9).get_c_display(), 9) # Invalid value + self.assertIsNone(Whiz(c=None).get_c_display()) # Blank value + self.assertEqual(Whiz(c="").get_c_display(), "") # Empty value + self.assertEqual(WhizDelayed(c=0).get_c_display(), "Other") # Delayed choices def test_get_FIELD_display_translated(self): """A translated display value is coerced to str.""" val = Whiz(c=5).get_c_display() self.assertIsInstance(val, str) - self.assertEqual(val, 'translated') + self.assertEqual(val, "translated") def test_overriding_FIELD_display(self): class FooBar(models.Model): - foo_bar = models.IntegerField(choices=[(1, 'foo'), (2, 'bar')]) + foo_bar = models.IntegerField(choices=[(1, "foo"), (2, "bar")]) def get_foo_bar_display(self): - return 'something' + return "something" f = FooBar(foo_bar=1) - self.assertEqual(f.get_foo_bar_display(), 'something') + self.assertEqual(f.get_foo_bar_display(), "something") def test_overriding_inherited_FIELD_display(self): class Base(models.Model): - foo = models.CharField(max_length=254, choices=[('A', 'Base A')]) + foo = models.CharField(max_length=254, choices=[("A", "Base A")]) class Meta: abstract = True class Child(Base): - foo = models.CharField(max_length=254, choices=[('A', 'Child A'), ('B', 'Child B')]) + foo = models.CharField( + max_length=254, choices=[("A", "Child A"), ("B", "Child B")] + ) - self.assertEqual(Child(foo='A').get_foo_display(), 'Child A') - self.assertEqual(Child(foo='B').get_foo_display(), 'Child B') + self.assertEqual(Child(foo="A").get_foo_display(), "Child A") + self.assertEqual(Child(foo="B").get_foo_display(), "Child B") def test_iterator_choices(self): """ get_choices() works with Iterators. """ - self.assertEqual(WhizIter(c=1).c, 1) # A nested value - self.assertEqual(WhizIter(c=9).c, 9) # Invalid value - self.assertIsNone(WhizIter(c=None).c) # Blank value - self.assertEqual(WhizIter(c='').c, '') # Empty value + self.assertEqual(WhizIter(c=1).c, 1) # A nested value + self.assertEqual(WhizIter(c=9).c, 9) # Invalid value + self.assertIsNone(WhizIter(c=None).c) # Blank value + self.assertEqual(WhizIter(c="").c, "") # Empty value def test_empty_iterator_choices(self): """ get_choices() works with empty iterators. """ - self.assertEqual(WhizIterEmpty(c="a").c, "a") # A nested value - self.assertEqual(WhizIterEmpty(c="b").c, "b") # Invalid value - self.assertIsNone(WhizIterEmpty(c=None).c) # Blank value - self.assertEqual(WhizIterEmpty(c='').c, '') # Empty value + self.assertEqual(WhizIterEmpty(c="a").c, "a") # A nested value + self.assertEqual(WhizIterEmpty(c="b").c, "b") # Invalid value + self.assertIsNone(WhizIterEmpty(c=None).c) # Blank value + self.assertEqual(WhizIterEmpty(c="").c, "") # Empty value class GetChoicesTests(SimpleTestCase): - def test_empty_choices(self): choices = [] f = models.CharField(choices=choices) self.assertEqual(f.get_choices(include_blank=False), choices) def test_blank_in_choices(self): - choices = [('', '<><>'), ('a', 'A')] + choices = [("", "<><>"), ("a", "A")] f = models.CharField(choices=choices) self.assertEqual(f.get_choices(include_blank=True), choices) def test_blank_in_grouped_choices(self): choices = [ - ('f', 'Foo'), - ('b', 'Bar'), - ('Group', ( - ('', 'No Preference'), - ('fg', 'Foo'), - ('bg', 'Bar'), - )), + ("f", "Foo"), + ("b", "Bar"), + ( + "Group", + ( + ("", "No Preference"), + ("fg", "Foo"), + ("bg", "Bar"), + ), + ), ] f = models.CharField(choices=choices) self.assertEqual(f.get_choices(include_blank=True), choices) def test_lazy_strings_not_evaluated(self): lazy_func = lazy(lambda x: 0 / 0, int) # raises ZeroDivisionError if evaluated. - f = models.CharField(choices=[(lazy_func('group'), (('a', 'A'), ('b', 'B')))]) - self.assertEqual(f.get_choices(include_blank=True)[0], ('', '---------')) + f = models.CharField(choices=[(lazy_func("group"), (("a", "A"), ("b", "B")))]) + self.assertEqual(f.get_choices(include_blank=True)[0], ("", "---------")) class GetChoicesOrderingTests(TestCase): - @classmethod def setUpTestData(cls): - cls.foo1 = Foo.objects.create(a='a', d='12.35') - cls.foo2 = Foo.objects.create(a='b', d='12.34') - cls.bar1 = Bar.objects.create(a=cls.foo1, b='b') - cls.bar2 = Bar.objects.create(a=cls.foo2, b='a') - cls.field = Bar._meta.get_field('a') + cls.foo1 = Foo.objects.create(a="a", d="12.35") + cls.foo2 = Foo.objects.create(a="b", d="12.34") + cls.bar1 = Bar.objects.create(a=cls.foo1, b="b") + cls.bar2 = Bar.objects.create(a=cls.foo2, b="a") + cls.field = Bar._meta.get_field("a") def assertChoicesEqual(self, choices, objs): self.assertEqual(choices, [(obj.pk, str(obj)) for obj in objs]) def test_get_choices(self): self.assertChoicesEqual( - self.field.get_choices(include_blank=False, ordering=('a',)), - [self.foo1, self.foo2] + self.field.get_choices(include_blank=False, ordering=("a",)), + [self.foo1, self.foo2], ) self.assertChoicesEqual( - self.field.get_choices(include_blank=False, ordering=('-a',)), - [self.foo2, self.foo1] + self.field.get_choices(include_blank=False, ordering=("-a",)), + [self.foo2, self.foo1], ) def test_get_choices_default_ordering(self): - self.addCleanup(setattr, Foo._meta, 'ordering', Foo._meta.ordering) - Foo._meta.ordering = ('d',) + self.addCleanup(setattr, Foo._meta, "ordering", Foo._meta.ordering) + Foo._meta.ordering = ("d",) self.assertChoicesEqual( - self.field.get_choices(include_blank=False), - [self.foo2, self.foo1] + self.field.get_choices(include_blank=False), [self.foo2, self.foo1] ) def test_get_choices_reverse_related_field(self): self.assertChoicesEqual( - self.field.remote_field.get_choices(include_blank=False, ordering=('a',)), - [self.bar1, self.bar2] + self.field.remote_field.get_choices(include_blank=False, ordering=("a",)), + [self.bar1, self.bar2], ) self.assertChoicesEqual( - self.field.remote_field.get_choices(include_blank=False, ordering=('-a',)), - [self.bar2, self.bar1] + self.field.remote_field.get_choices(include_blank=False, ordering=("-a",)), + [self.bar2, self.bar1], ) def test_get_choices_reverse_related_field_default_ordering(self): - self.addCleanup(setattr, Bar._meta, 'ordering', Bar._meta.ordering) - Bar._meta.ordering = ('b',) + self.addCleanup(setattr, Bar._meta, "ordering", Bar._meta.ordering) + Bar._meta.ordering = ("b",) self.assertChoicesEqual( self.field.remote_field.get_choices(include_blank=False), - [self.bar2, self.bar1] + [self.bar2, self.bar1], ) class GetChoicesLimitChoicesToTests(TestCase): @classmethod def setUpTestData(cls): - cls.foo1 = Foo.objects.create(a='a', d='12.34') - cls.foo2 = Foo.objects.create(a='b', d='12.34') - cls.bar1 = Bar.objects.create(a=cls.foo1, b='b') - cls.bar2 = Bar.objects.create(a=cls.foo2, b='a') - cls.field = Bar._meta.get_field('a') + cls.foo1 = Foo.objects.create(a="a", d="12.34") + cls.foo2 = Foo.objects.create(a="b", d="12.34") + cls.bar1 = Bar.objects.create(a=cls.foo1, b="b") + cls.bar2 = Bar.objects.create(a=cls.foo2, b="a") + cls.field = Bar._meta.get_field("a") def assertChoicesEqual(self, choices, objs): self.assertEqual(choices, [(obj.pk, str(obj)) for obj in objs]) def test_get_choices(self): self.assertChoicesEqual( - self.field.get_choices(include_blank=False, limit_choices_to={'a': 'a'}), + self.field.get_choices(include_blank=False, limit_choices_to={"a": "a"}), [self.foo1], ) self.assertChoicesEqual( @@ -351,7 +362,7 @@ class GetChoicesLimitChoicesToTests(TestCase): def test_get_choices_reverse_related_field(self): field = self.field.remote_field self.assertChoicesEqual( - field.get_choices(include_blank=False, limit_choices_to={'b': 'b'}), + field.get_choices(include_blank=False, limit_choices_to={"b": "b"}), [self.bar1], ) self.assertChoicesEqual( |