diff options
Diffstat (limited to 'tests/migrations')
112 files changed, 9345 insertions, 5267 deletions
diff --git a/tests/migrations/deprecated_field_migrations/0001_initial.py b/tests/migrations/deprecated_field_migrations/0001_initial.py index 8665d5b2ff..b5d606c8ad 100644 --- a/tests/migrations/deprecated_field_migrations/0001_initial.py +++ b/tests/migrations/deprecated_field_migrations/0001_initial.py @@ -3,15 +3,22 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='IPAddressField', + name="IPAddressField", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('ip', models.IPAddressField(null=True, blank=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("ip", models.IPAddressField(null=True, blank=True)), ], ), ] diff --git a/tests/migrations/deprecated_field_migrations/0002_remove_ipaddressfield_ip.py b/tests/migrations/deprecated_field_migrations/0002_remove_ipaddressfield_ip.py index 1b27bf536d..019b80fddf 100644 --- a/tests/migrations/deprecated_field_migrations/0002_remove_ipaddressfield_ip.py +++ b/tests/migrations/deprecated_field_migrations/0002_remove_ipaddressfield_ip.py @@ -4,12 +4,12 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('migrations', '0001_initial'), + ("migrations", "0001_initial"), ] operations = [ migrations.RemoveField( - model_name='ipaddressfield', - name='ip', + model_name="ipaddressfield", + name="ip", ), ] diff --git a/tests/migrations/migrations_test_apps/alter_fk/author_app/migrations/0001_initial.py b/tests/migrations/migrations_test_apps/alter_fk/author_app/migrations/0001_initial.py index 48664b2a04..c7cf43a233 100644 --- a/tests/migrations/migrations_test_apps/alter_fk/author_app/migrations/0001_initial.py +++ b/tests/migrations/migrations_test_apps/alter_fk/author_app/migrations/0001_initial.py @@ -3,15 +3,19 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='Author', + name="Author", fields=[ - ('id', models.AutoField(serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(max_length=50)), + ( + "id", + models.AutoField( + serialize=False, auto_created=True, primary_key=True + ), + ), + ("name", models.CharField(max_length=50)), ], ), ] diff --git a/tests/migrations/migrations_test_apps/alter_fk/author_app/migrations/0002_alter_id.py b/tests/migrations/migrations_test_apps/alter_fk/author_app/migrations/0002_alter_id.py index 18bc91ad72..cd18df17f3 100644 --- a/tests/migrations/migrations_test_apps/alter_fk/author_app/migrations/0002_alter_id.py +++ b/tests/migrations/migrations_test_apps/alter_fk/author_app/migrations/0002_alter_id.py @@ -4,14 +4,14 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('author_app', '0001_initial'), - ('book_app', '0001_initial'), # Forces the book table to alter the FK + ("author_app", "0001_initial"), + ("book_app", "0001_initial"), # Forces the book table to alter the FK ] operations = [ migrations.AlterField( - model_name='author', - name='id', + model_name="author", + name="id", field=models.CharField(max_length=10, primary_key=True), ), ] diff --git a/tests/migrations/migrations_test_apps/alter_fk/book_app/migrations/0001_initial.py b/tests/migrations/migrations_test_apps/alter_fk/book_app/migrations/0001_initial.py index 46543caeee..72c11285d6 100644 --- a/tests/migrations/migrations_test_apps/alter_fk/book_app/migrations/0001_initial.py +++ b/tests/migrations/migrations_test_apps/alter_fk/book_app/migrations/0001_initial.py @@ -4,16 +4,21 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('author_app', '0001_initial'), + ("author_app", "0001_initial"), ] operations = [ migrations.CreateModel( - name='Book', + name="Book", fields=[ - ('id', models.AutoField(serialize=False, auto_created=True, primary_key=True)), - ('title', models.CharField(max_length=50)), - ('author', models.ForeignKey('author_app.Author', models.CASCADE)), + ( + "id", + models.AutoField( + serialize=False, auto_created=True, primary_key=True + ), + ), + ("title", models.CharField(max_length=50)), + ("author", models.ForeignKey("author_app.Author", models.CASCADE)), ], ), ] diff --git a/tests/migrations/migrations_test_apps/conflicting_app_with_dependencies/migrations/0001_initial.py b/tests/migrations/migrations_test_apps/conflicting_app_with_dependencies/migrations/0001_initial.py index ddf070a8cd..59ad944f67 100644 --- a/tests/migrations/migrations_test_apps/conflicting_app_with_dependencies/migrations/0001_initial.py +++ b/tests/migrations/migrations_test_apps/conflicting_app_with_dependencies/migrations/0001_initial.py @@ -20,5 +20,5 @@ class Migration(migrations.Migration): ("id", models.AutoField(primary_key=True)), ("fluffy", models.BooleanField(default=True)), ], - ) + ), ] diff --git a/tests/migrations/migrations_test_apps/conflicting_app_with_dependencies/migrations/0002_second.py b/tests/migrations/migrations_test_apps/conflicting_app_with_dependencies/migrations/0002_second.py index d612af5726..7c581f158f 100644 --- a/tests/migrations/migrations_test_apps/conflicting_app_with_dependencies/migrations/0002_second.py +++ b/tests/migrations/migrations_test_apps/conflicting_app_with_dependencies/migrations/0002_second.py @@ -17,5 +17,5 @@ class Migration(migrations.Migration): [ ("id", models.AutoField(primary_key=True)), ], - ) + ), ] diff --git a/tests/migrations/migrations_test_apps/lookuperror_a/migrations/0001_initial.py b/tests/migrations/migrations_test_apps/lookuperror_a/migrations/0001_initial.py index 6351b0d212..eef91811cb 100644 --- a/tests/migrations/migrations_test_apps/lookuperror_a/migrations/0001_initial.py +++ b/tests/migrations/migrations_test_apps/lookuperror_a/migrations/0001_initial.py @@ -3,14 +3,21 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='A1', + name="A1", fields=[ - ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)), + ( + "id", + models.AutoField( + serialize=False, + verbose_name="ID", + auto_created=True, + primary_key=True, + ), + ), ], ), ] diff --git a/tests/migrations/migrations_test_apps/lookuperror_a/migrations/0002_a2.py b/tests/migrations/migrations_test_apps/lookuperror_a/migrations/0002_a2.py index ab943b9c77..573909f9a7 100644 --- a/tests/migrations/migrations_test_apps/lookuperror_a/migrations/0002_a2.py +++ b/tests/migrations/migrations_test_apps/lookuperror_a/migrations/0002_a2.py @@ -4,14 +4,22 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('lookuperror_a', '0001_initial'), + ("lookuperror_a", "0001_initial"), ] operations = [ migrations.CreateModel( - name='A2', + name="A2", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + serialize=False, + auto_created=True, + ), + ), ], ), ] diff --git a/tests/migrations/migrations_test_apps/lookuperror_a/migrations/0003_a3.py b/tests/migrations/migrations_test_apps/lookuperror_a/migrations/0003_a3.py index 42b5853d3c..d1caeb2284 100644 --- a/tests/migrations/migrations_test_apps/lookuperror_a/migrations/0003_a3.py +++ b/tests/migrations/migrations_test_apps/lookuperror_a/migrations/0003_a3.py @@ -4,18 +4,26 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('lookuperror_c', '0002_c2'), - ('lookuperror_b', '0002_b2'), - ('lookuperror_a', '0002_a2'), + ("lookuperror_c", "0002_c2"), + ("lookuperror_b", "0002_b2"), + ("lookuperror_a", "0002_a2"), ] operations = [ migrations.CreateModel( - name='A3', + name="A3", fields=[ - ('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')), - ('b2', models.ForeignKey('lookuperror_b.B2', models.CASCADE)), - ('c2', models.ForeignKey('lookuperror_c.C2', models.CASCADE)), + ( + "id", + models.AutoField( + serialize=False, + auto_created=True, + primary_key=True, + verbose_name="ID", + ), + ), + ("b2", models.ForeignKey("lookuperror_b.B2", models.CASCADE)), + ("c2", models.ForeignKey("lookuperror_c.C2", models.CASCADE)), ], ), ] diff --git a/tests/migrations/migrations_test_apps/lookuperror_a/migrations/0004_a4.py b/tests/migrations/migrations_test_apps/lookuperror_a/migrations/0004_a4.py index b7a0bcb8a7..060bc499f5 100644 --- a/tests/migrations/migrations_test_apps/lookuperror_a/migrations/0004_a4.py +++ b/tests/migrations/migrations_test_apps/lookuperror_a/migrations/0004_a4.py @@ -4,14 +4,22 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('lookuperror_a', '0003_a3'), + ("lookuperror_a", "0003_a3"), ] operations = [ migrations.CreateModel( - name='A4', + name="A4", fields=[ - ('id', models.AutoField(auto_created=True, serialize=False, verbose_name='ID', primary_key=True)), + ( + "id", + models.AutoField( + auto_created=True, + serialize=False, + verbose_name="ID", + primary_key=True, + ), + ), ], ), ] diff --git a/tests/migrations/migrations_test_apps/lookuperror_a/models.py b/tests/migrations/migrations_test_apps/lookuperror_a/models.py index 9428f952eb..fbc4cb6809 100644 --- a/tests/migrations/migrations_test_apps/lookuperror_a/models.py +++ b/tests/migrations/migrations_test_apps/lookuperror_a/models.py @@ -10,8 +10,8 @@ class A2(models.Model): class A3(models.Model): - b2 = models.ForeignKey('lookuperror_b.B2', models.CASCADE) - c2 = models.ForeignKey('lookuperror_c.C2', models.CASCADE) + b2 = models.ForeignKey("lookuperror_b.B2", models.CASCADE) + c2 = models.ForeignKey("lookuperror_c.C2", models.CASCADE) class A4(models.Model): diff --git a/tests/migrations/migrations_test_apps/lookuperror_b/migrations/0001_initial.py b/tests/migrations/migrations_test_apps/lookuperror_b/migrations/0001_initial.py index def52ae789..af48c80d3c 100644 --- a/tests/migrations/migrations_test_apps/lookuperror_b/migrations/0001_initial.py +++ b/tests/migrations/migrations_test_apps/lookuperror_b/migrations/0001_initial.py @@ -3,14 +3,21 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='B1', + name="B1", fields=[ - ('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')), + ( + "id", + models.AutoField( + serialize=False, + auto_created=True, + primary_key=True, + verbose_name="ID", + ), + ), ], ), ] diff --git a/tests/migrations/migrations_test_apps/lookuperror_b/migrations/0002_b2.py b/tests/migrations/migrations_test_apps/lookuperror_b/migrations/0002_b2.py index a2ac5e1ba7..87ab4c3194 100644 --- a/tests/migrations/migrations_test_apps/lookuperror_b/migrations/0002_b2.py +++ b/tests/migrations/migrations_test_apps/lookuperror_b/migrations/0002_b2.py @@ -4,16 +4,24 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('lookuperror_a', '0002_a2'), - ('lookuperror_b', '0001_initial'), + ("lookuperror_a", "0002_a2"), + ("lookuperror_b", "0001_initial"), ] operations = [ migrations.CreateModel( - name='B2', + name="B2", fields=[ - ('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)), - ('a1', models.ForeignKey('lookuperror_a.A1', models.CASCADE)), + ( + "id", + models.AutoField( + primary_key=True, + verbose_name="ID", + auto_created=True, + serialize=False, + ), + ), + ("a1", models.ForeignKey("lookuperror_a.A1", models.CASCADE)), ], ), ] diff --git a/tests/migrations/migrations_test_apps/lookuperror_b/migrations/0003_b3.py b/tests/migrations/migrations_test_apps/lookuperror_b/migrations/0003_b3.py index 1c76e73ec1..e068563dd1 100644 --- a/tests/migrations/migrations_test_apps/lookuperror_b/migrations/0003_b3.py +++ b/tests/migrations/migrations_test_apps/lookuperror_b/migrations/0003_b3.py @@ -4,14 +4,22 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('lookuperror_b', '0002_b2'), + ("lookuperror_b", "0002_b2"), ] operations = [ migrations.CreateModel( - name='B3', + name="B3", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, primary_key=True, auto_created=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + primary_key=True, + auto_created=True, + ), + ), ], ), ] diff --git a/tests/migrations/migrations_test_apps/lookuperror_b/models.py b/tests/migrations/migrations_test_apps/lookuperror_b/models.py index ed78c48e68..0bca4e68ec 100644 --- a/tests/migrations/migrations_test_apps/lookuperror_b/models.py +++ b/tests/migrations/migrations_test_apps/lookuperror_b/models.py @@ -6,7 +6,7 @@ class B1(models.Model): class B2(models.Model): - a1 = models.ForeignKey('lookuperror_a.A1', models.CASCADE) + a1 = models.ForeignKey("lookuperror_a.A1", models.CASCADE) class B3(models.Model): diff --git a/tests/migrations/migrations_test_apps/lookuperror_c/migrations/0001_initial.py b/tests/migrations/migrations_test_apps/lookuperror_c/migrations/0001_initial.py index 8453148b87..523259fd26 100644 --- a/tests/migrations/migrations_test_apps/lookuperror_c/migrations/0001_initial.py +++ b/tests/migrations/migrations_test_apps/lookuperror_c/migrations/0001_initial.py @@ -3,14 +3,21 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='C1', + name="C1", fields=[ - ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)), + ( + "id", + models.AutoField( + serialize=False, + verbose_name="ID", + auto_created=True, + primary_key=True, + ), + ), ], ), ] diff --git a/tests/migrations/migrations_test_apps/lookuperror_c/migrations/0002_c2.py b/tests/migrations/migrations_test_apps/lookuperror_c/migrations/0002_c2.py index a928da9ae0..3699db274b 100644 --- a/tests/migrations/migrations_test_apps/lookuperror_c/migrations/0002_c2.py +++ b/tests/migrations/migrations_test_apps/lookuperror_c/migrations/0002_c2.py @@ -4,16 +4,24 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('lookuperror_a', '0002_a2'), - ('lookuperror_c', '0001_initial'), + ("lookuperror_a", "0002_a2"), + ("lookuperror_c", "0001_initial"), ] operations = [ migrations.CreateModel( - name='C2', + name="C2", fields=[ - ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)), - ('a1', models.ForeignKey('lookuperror_a.A1', models.CASCADE)), + ( + "id", + models.AutoField( + auto_created=True, + verbose_name="ID", + primary_key=True, + serialize=False, + ), + ), + ("a1", models.ForeignKey("lookuperror_a.A1", models.CASCADE)), ], ), ] diff --git a/tests/migrations/migrations_test_apps/lookuperror_c/migrations/0003_c3.py b/tests/migrations/migrations_test_apps/lookuperror_c/migrations/0003_c3.py index 58119ac8ac..8be34afa6b 100644 --- a/tests/migrations/migrations_test_apps/lookuperror_c/migrations/0003_c3.py +++ b/tests/migrations/migrations_test_apps/lookuperror_c/migrations/0003_c3.py @@ -4,14 +4,22 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('lookuperror_c', '0002_c2'), + ("lookuperror_c", "0002_c2"), ] operations = [ migrations.CreateModel( - name='C3', + name="C3", fields=[ - ('id', models.AutoField(auto_created=True, serialize=False, verbose_name='ID', primary_key=True)), + ( + "id", + models.AutoField( + auto_created=True, + serialize=False, + verbose_name="ID", + primary_key=True, + ), + ), ], ), ] diff --git a/tests/migrations/migrations_test_apps/lookuperror_c/models.py b/tests/migrations/migrations_test_apps/lookuperror_c/models.py index 5dc28ae5ba..dbf5bca6b8 100644 --- a/tests/migrations/migrations_test_apps/lookuperror_c/models.py +++ b/tests/migrations/migrations_test_apps/lookuperror_c/models.py @@ -6,7 +6,7 @@ class C1(models.Model): class C2(models.Model): - a1 = models.ForeignKey('lookuperror_a.A1', models.CASCADE) + a1 = models.ForeignKey("lookuperror_a.A1", models.CASCADE) class C3(models.Model): diff --git a/tests/migrations/migrations_test_apps/migrated_app/migrations/0001_initial.py b/tests/migrations/migrations_test_apps/migrated_app/migrations/0001_initial.py index 344bebdfe3..59ad944f67 100644 --- a/tests/migrations/migrations_test_apps/migrated_app/migrations/0001_initial.py +++ b/tests/migrations/migrations_test_apps/migrated_app/migrations/0001_initial.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): operations = [ - migrations.CreateModel( "Author", [ @@ -15,13 +14,11 @@ class Migration(migrations.Migration): ("silly_field", models.BooleanField(default=False)), ], ), - migrations.CreateModel( "Tribble", [ ("id", models.AutoField(primary_key=True)), ("fluffy", models.BooleanField(default=True)), ], - ) - + ), ] diff --git a/tests/migrations/migrations_test_apps/migrated_unapplied_app/migrations/0001_initial.py b/tests/migrations/migrations_test_apps/migrated_unapplied_app/migrations/0001_initial.py index 800ceed7e4..551f597562 100644 --- a/tests/migrations/migrations_test_apps/migrated_unapplied_app/migrations/0001_initial.py +++ b/tests/migrations/migrations_test_apps/migrated_unapplied_app/migrations/0001_initial.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): operations = [ - migrations.CreateModel( "OtherAuthor", [ @@ -15,5 +14,4 @@ class Migration(migrations.Migration): ("silly_field", models.BooleanField(default=False)), ], ), - ] diff --git a/tests/migrations/migrations_test_apps/mutate_state_a/migrations/0001_initial.py b/tests/migrations/migrations_test_apps/mutate_state_a/migrations/0001_initial.py index 37c9bf7377..4da5347412 100644 --- a/tests/migrations/migrations_test_apps/mutate_state_a/migrations/0001_initial.py +++ b/tests/migrations/migrations_test_apps/mutate_state_a/migrations/0001_initial.py @@ -4,16 +4,27 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('mutate_state_b', '0001_initial'), + ("mutate_state_b", "0001_initial"), ] operations = [ - migrations.SeparateDatabaseAndState([], [ - migrations.CreateModel( - name='A', - fields=[ - ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)), - ], - ), - ]) + migrations.SeparateDatabaseAndState( + [], + [ + migrations.CreateModel( + name="A", + fields=[ + ( + "id", + models.AutoField( + serialize=False, + verbose_name="ID", + auto_created=True, + primary_key=True, + ), + ), + ], + ), + ], + ) ] diff --git a/tests/migrations/migrations_test_apps/mutate_state_b/migrations/0001_initial.py b/tests/migrations/migrations_test_apps/mutate_state_b/migrations/0001_initial.py index 51c022dd7f..4d5e712d66 100644 --- a/tests/migrations/migrations_test_apps/mutate_state_b/migrations/0001_initial.py +++ b/tests/migrations/migrations_test_apps/mutate_state_b/migrations/0001_initial.py @@ -3,16 +3,26 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ] + dependencies = [] operations = [ - migrations.SeparateDatabaseAndState([], [ - migrations.CreateModel( - name='B', - fields=[ - ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)), - ], - ), - ]) + migrations.SeparateDatabaseAndState( + [], + [ + migrations.CreateModel( + name="B", + fields=[ + ( + "id", + models.AutoField( + serialize=False, + verbose_name="ID", + auto_created=True, + primary_key=True, + ), + ), + ], + ), + ], + ) ] diff --git a/tests/migrations/migrations_test_apps/mutate_state_b/migrations/0002_add_field.py b/tests/migrations/migrations_test_apps/mutate_state_b/migrations/0002_add_field.py index ae968382eb..fcd8a9337a 100644 --- a/tests/migrations/migrations_test_apps/mutate_state_b/migrations/0002_add_field.py +++ b/tests/migrations/migrations_test_apps/mutate_state_b/migrations/0002_add_field.py @@ -4,15 +4,18 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('mutate_state_b', '0001_initial'), + ("mutate_state_b", "0001_initial"), ] operations = [ - migrations.SeparateDatabaseAndState([], [ - migrations.AddField( - model_name='B', - name='added', - field=models.TextField(), - ), - ]) + migrations.SeparateDatabaseAndState( + [], + [ + migrations.AddField( + model_name="B", + name="added", + field=models.TextField(), + ), + ], + ) ] diff --git a/tests/migrations/migrations_test_apps/unmigrated_app_simple/models.py b/tests/migrations/migrations_test_apps/unmigrated_app_simple/models.py index 785d040800..5119205b9a 100644 --- a/tests/migrations/migrations_test_apps/unmigrated_app_simple/models.py +++ b/tests/migrations/migrations_test_apps/unmigrated_app_simple/models.py @@ -6,4 +6,5 @@ class UnmigratedModel(models.Model): A model that is in a migration-less app (which this app is if its migrations directory has not been repointed) """ + pass diff --git a/tests/migrations/migrations_test_apps/unspecified_app_with_conflict/migrations/0001_initial.py b/tests/migrations/migrations_test_apps/unspecified_app_with_conflict/migrations/0001_initial.py index 344bebdfe3..59ad944f67 100644 --- a/tests/migrations/migrations_test_apps/unspecified_app_with_conflict/migrations/0001_initial.py +++ b/tests/migrations/migrations_test_apps/unspecified_app_with_conflict/migrations/0001_initial.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): operations = [ - migrations.CreateModel( "Author", [ @@ -15,13 +14,11 @@ class Migration(migrations.Migration): ("silly_field", models.BooleanField(default=False)), ], ), - migrations.CreateModel( "Tribble", [ ("id", models.AutoField(primary_key=True)), ("fluffy", models.BooleanField(default=True)), ], - ) - + ), ] diff --git a/tests/migrations/migrations_test_apps/unspecified_app_with_conflict/migrations/0002_conflicting_second.py b/tests/migrations/migrations_test_apps/unspecified_app_with_conflict/migrations/0002_conflicting_second.py index ad44031030..385420e98b 100644 --- a/tests/migrations/migrations_test_apps/unspecified_app_with_conflict/migrations/0002_conflicting_second.py +++ b/tests/migrations/migrations_test_apps/unspecified_app_with_conflict/migrations/0002_conflicting_second.py @@ -6,12 +6,10 @@ class Migration(migrations.Migration): dependencies = [("unspecified_app_with_conflict", "0001_initial")] operations = [ - migrations.CreateModel( "Something", [ ("id", models.AutoField(primary_key=True)), ], ) - ] diff --git a/tests/migrations/migrations_test_apps/unspecified_app_with_conflict/migrations/0002_second.py b/tests/migrations/migrations_test_apps/unspecified_app_with_conflict/migrations/0002_second.py index fbf5a9110c..8da324aaff 100644 --- a/tests/migrations/migrations_test_apps/unspecified_app_with_conflict/migrations/0002_second.py +++ b/tests/migrations/migrations_test_apps/unspecified_app_with_conflict/migrations/0002_second.py @@ -6,18 +6,13 @@ class Migration(migrations.Migration): dependencies = [("unspecified_app_with_conflict", "0001_initial")] operations = [ - migrations.DeleteModel("Tribble"), - migrations.RemoveField("Author", "silly_field"), - migrations.AddField("Author", "rating", models.IntegerField(default=0)), - migrations.CreateModel( "Book", [ ("id", models.AutoField(primary_key=True)), ], - ) - + ), ] diff --git a/tests/migrations/models.py b/tests/migrations/models.py index 440aa582d6..0d728561d0 100644 --- a/tests/migrations/models.py +++ b/tests/migrations/models.py @@ -11,13 +11,13 @@ class ModelWithCustomBase(models.Model, metaclass=CustomModelBase): class UnicodeModel(models.Model): - title = models.CharField('ÚÑÍ¢ÓÐÉ', max_length=20, default='“Ðjáñgó”') + title = models.CharField("ÚÑÍ¢ÓÐÉ", max_length=20, default="“Ðjáñgó”") class Meta: # Disable auto loading of this model as we load it on our own apps = Apps() - verbose_name = 'úñí©óðé µóðéø' - verbose_name_plural = 'úñí©óðé µóðéøß' + verbose_name = "úñí©óðé µóðéø" + verbose_name_plural = "úñí©óðé µóðéøß" def __str__(self): return self.title @@ -27,6 +27,7 @@ class Unserializable: """ An object that migration doesn't know how to serialize. """ + pass @@ -43,6 +44,7 @@ class UnmigratedModel(models.Model): A model that is in a migration-less app (which this app is if its migrations directory has not been repointed) """ + pass diff --git a/tests/migrations/routers.py b/tests/migrations/routers.py index bc036382a7..211c189772 100644 --- a/tests/migrations/routers.py +++ b/tests/migrations/routers.py @@ -1,6 +1,6 @@ class DefaultOtherRouter: def allow_migrate(self, db, app_label, model_name=None, **hints): - return db in {'default', 'other'} + return db in {"default", "other"} class TestRouter: @@ -8,7 +8,7 @@ class TestRouter: """ The Tribble model should be the only one to appear in the 'other' db. """ - if model_name == 'tribble': - return db == 'other' - elif db != 'default': + if model_name == "tribble": + return db == "other" + elif db != "default": return False diff --git a/tests/migrations/test_add_many_to_many_field_initial/0001_initial.py b/tests/migrations/test_add_many_to_many_field_initial/0001_initial.py index 50fd06a35f..e7e7d59633 100644 --- a/tests/migrations/test_add_many_to_many_field_initial/0001_initial.py +++ b/tests/migrations/test_add_many_to_many_field_initial/0001_initial.py @@ -5,25 +5,40 @@ class Migration(migrations.Migration): initial = True - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='Project', + name="Project", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ], ), migrations.CreateModel( - name='Task', + name="Task", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), ], ), migrations.AddField( - model_name='project', - name='tasks', - field=models.ManyToManyField(to='Task'), + model_name="project", + name="tasks", + field=models.ManyToManyField(to="Task"), ), ] diff --git a/tests/migrations/test_add_many_to_many_field_initial/0002_initial.py b/tests/migrations/test_add_many_to_many_field_initial/0002_initial.py index 1bc6c8aafa..928e4ea1c9 100644 --- a/tests/migrations/test_add_many_to_many_field_initial/0002_initial.py +++ b/tests/migrations/test_add_many_to_many_field_initial/0002_initial.py @@ -11,8 +11,8 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( - model_name='task', - name='projects', - field=models.ManyToManyField(to='Project'), + model_name="task", + name="projects", + field=models.ManyToManyField(to="Project"), ), ] diff --git a/tests/migrations/test_auto_now_add/0001_initial.py b/tests/migrations/test_auto_now_add/0001_initial.py index f1bfb44657..e7fafc96c6 100644 --- a/tests/migrations/test_auto_now_add/0001_initial.py +++ b/tests/migrations/test_auto_now_add/0001_initial.py @@ -7,10 +7,18 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name='Entry', + name="Entry", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('title', models.CharField(max_length=255)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("title", models.CharField(max_length=255)), ], ), ] diff --git a/tests/migrations/test_autodetector.py b/tests/migrations/test_autodetector.py index dddd4e0c94..cadc8cef30 100644 --- a/tests/migrations/test_autodetector.py +++ b/tests/migrations/test_autodetector.py @@ -28,11 +28,7 @@ class DeconstructibleObject: self.kwargs = kwargs def deconstruct(self): - return ( - self.__module__ + '.' + self.__class__.__name__, - self.args, - self.kwargs - ) + return (self.__module__ + "." + self.__class__.__name__, self.args, self.kwargs) class AutodetectorTests(TestCase): @@ -40,427 +36,911 @@ class AutodetectorTests(TestCase): Tests the migration autodetector. """ - author_empty = ModelState("testapp", "Author", [("id", models.AutoField(primary_key=True))]) - author_name = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200)), - ]) - author_name_null = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, null=True)), - ]) - author_name_longer = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=400)), - ]) - author_name_renamed = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("names", models.CharField(max_length=200)), - ]) - author_name_default = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, default='Ada Lovelace')), - ]) - author_name_check_constraint = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200)), - ], - {'constraints': [models.CheckConstraint(check=models.Q(name__contains='Bob'), name='name_contains_bob')]}, + author_empty = ModelState( + "testapp", "Author", [("id", models.AutoField(primary_key=True))] + ) + author_name = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200)), + ], + ) + author_name_null = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200, null=True)), + ], + ) + author_name_longer = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=400)), + ], + ) + author_name_renamed = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("names", models.CharField(max_length=200)), + ], + ) + author_name_default = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200, default="Ada Lovelace")), + ], + ) + author_name_check_constraint = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200)), + ], + { + "constraints": [ + models.CheckConstraint( + check=models.Q(name__contains="Bob"), name="name_contains_bob" + ) + ] + }, + ) + author_dates_of_birth_auto_now = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("date_of_birth", models.DateField(auto_now=True)), + ("date_time_of_birth", models.DateTimeField(auto_now=True)), + ("time_of_birth", models.TimeField(auto_now=True)), + ], + ) + author_dates_of_birth_auto_now_add = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("date_of_birth", models.DateField(auto_now_add=True)), + ("date_time_of_birth", models.DateTimeField(auto_now_add=True)), + ("time_of_birth", models.TimeField(auto_now_add=True)), + ], + ) + author_name_deconstructible_1 = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200, default=DeconstructibleObject())), + ], + ) + author_name_deconstructible_2 = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200, default=DeconstructibleObject())), + ], + ) + author_name_deconstructible_3 = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200, default=models.IntegerField())), + ], + ) + author_name_deconstructible_4 = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200, default=models.IntegerField())), + ], + ) + author_name_deconstructible_list_1 = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "name", + models.CharField( + max_length=200, default=[DeconstructibleObject(), 123] + ), + ), + ], + ) + author_name_deconstructible_list_2 = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "name", + models.CharField( + max_length=200, default=[DeconstructibleObject(), 123] + ), + ), + ], + ) + author_name_deconstructible_list_3 = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "name", + models.CharField( + max_length=200, default=[DeconstructibleObject(), 999] + ), + ), + ], + ) + author_name_deconstructible_tuple_1 = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "name", + models.CharField( + max_length=200, default=(DeconstructibleObject(), 123) + ), + ), + ], + ) + author_name_deconstructible_tuple_2 = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "name", + models.CharField( + max_length=200, default=(DeconstructibleObject(), 123) + ), + ), + ], + ) + author_name_deconstructible_tuple_3 = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "name", + models.CharField( + max_length=200, default=(DeconstructibleObject(), 999) + ), + ), + ], + ) + author_name_deconstructible_dict_1 = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "name", + models.CharField( + max_length=200, + default={"item": DeconstructibleObject(), "otheritem": 123}, + ), + ), + ], + ) + author_name_deconstructible_dict_2 = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "name", + models.CharField( + max_length=200, + default={"item": DeconstructibleObject(), "otheritem": 123}, + ), + ), + ], + ) + author_name_deconstructible_dict_3 = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "name", + models.CharField( + max_length=200, + default={"item": DeconstructibleObject(), "otheritem": 999}, + ), + ), + ], + ) + author_name_nested_deconstructible_1 = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "name", + models.CharField( + max_length=200, + default=DeconstructibleObject( + DeconstructibleObject(1), + ( + DeconstructibleObject("t1"), + DeconstructibleObject("t2"), + ), + a=DeconstructibleObject("A"), + b=DeconstructibleObject(B=DeconstructibleObject("c")), + ), + ), + ), + ], + ) + author_name_nested_deconstructible_2 = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "name", + models.CharField( + max_length=200, + default=DeconstructibleObject( + DeconstructibleObject(1), + ( + DeconstructibleObject("t1"), + DeconstructibleObject("t2"), + ), + a=DeconstructibleObject("A"), + b=DeconstructibleObject(B=DeconstructibleObject("c")), + ), + ), + ), + ], + ) + author_name_nested_deconstructible_changed_arg = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "name", + models.CharField( + max_length=200, + default=DeconstructibleObject( + DeconstructibleObject(1), + ( + DeconstructibleObject("t1"), + DeconstructibleObject("t2-changed"), + ), + a=DeconstructibleObject("A"), + b=DeconstructibleObject(B=DeconstructibleObject("c")), + ), + ), + ), + ], + ) + author_name_nested_deconstructible_extra_arg = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "name", + models.CharField( + max_length=200, + default=DeconstructibleObject( + DeconstructibleObject(1), + ( + DeconstructibleObject("t1"), + DeconstructibleObject("t2"), + ), + None, + a=DeconstructibleObject("A"), + b=DeconstructibleObject(B=DeconstructibleObject("c")), + ), + ), + ), + ], + ) + author_name_nested_deconstructible_changed_kwarg = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "name", + models.CharField( + max_length=200, + default=DeconstructibleObject( + DeconstructibleObject(1), + ( + DeconstructibleObject("t1"), + DeconstructibleObject("t2"), + ), + a=DeconstructibleObject("A"), + b=DeconstructibleObject(B=DeconstructibleObject("c-changed")), + ), + ), + ), + ], + ) + author_name_nested_deconstructible_extra_kwarg = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "name", + models.CharField( + max_length=200, + default=DeconstructibleObject( + DeconstructibleObject(1), + ( + DeconstructibleObject("t1"), + DeconstructibleObject("t2"), + ), + a=DeconstructibleObject("A"), + b=DeconstructibleObject(B=DeconstructibleObject("c")), + c=None, + ), + ), + ), + ], + ) + author_custom_pk = ModelState( + "testapp", "Author", [("pk_field", models.IntegerField(primary_key=True))] + ) + author_with_biography_non_blank = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField()), + ("biography", models.TextField()), + ], + ) + author_with_biography_blank = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(blank=True)), + ("biography", models.TextField(blank=True)), + ], + ) + author_with_book = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200)), + ("book", models.ForeignKey("otherapp.Book", models.CASCADE)), + ], + ) + author_with_book_order_wrt = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200)), + ("book", models.ForeignKey("otherapp.Book", models.CASCADE)), + ], + options={"order_with_respect_to": "book"}, + ) + author_renamed_with_book = ModelState( + "testapp", + "Writer", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200)), + ("book", models.ForeignKey("otherapp.Book", models.CASCADE)), + ], + ) + author_with_publisher_string = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200)), + ("publisher_name", models.CharField(max_length=200)), + ], + ) + author_with_publisher = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200)), + ("publisher", models.ForeignKey("testapp.Publisher", models.CASCADE)), + ], + ) + author_with_user = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200)), + ("user", models.ForeignKey("auth.User", models.CASCADE)), + ], + ) + author_with_custom_user = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200)), + ("user", models.ForeignKey("thirdapp.CustomUser", models.CASCADE)), + ], + ) + author_proxy = ModelState( + "testapp", "AuthorProxy", [], {"proxy": True}, ("testapp.author",) + ) + author_proxy_options = ModelState( + "testapp", + "AuthorProxy", + [], + { + "proxy": True, + "verbose_name": "Super Author", + }, + ("testapp.author",), + ) + author_proxy_notproxy = ModelState( + "testapp", "AuthorProxy", [], {}, ("testapp.author",) + ) + author_proxy_third = ModelState( + "thirdapp", "AuthorProxy", [], {"proxy": True}, ("testapp.author",) + ) + author_proxy_third_notproxy = ModelState( + "thirdapp", "AuthorProxy", [], {}, ("testapp.author",) + ) + author_proxy_proxy = ModelState( + "testapp", "AAuthorProxyProxy", [], {"proxy": True}, ("testapp.authorproxy",) + ) + author_unmanaged = ModelState( + "testapp", "AuthorUnmanaged", [], {"managed": False}, ("testapp.author",) + ) + author_unmanaged_managed = ModelState( + "testapp", "AuthorUnmanaged", [], {}, ("testapp.author",) + ) + author_unmanaged_default_pk = ModelState( + "testapp", "Author", [("id", models.AutoField(primary_key=True))] + ) + author_unmanaged_custom_pk = ModelState( + "testapp", + "Author", + [ + ("pk_field", models.IntegerField(primary_key=True)), + ], + ) + author_with_m2m = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("publishers", models.ManyToManyField("testapp.Publisher")), + ], + ) + author_with_m2m_blank = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("publishers", models.ManyToManyField("testapp.Publisher", blank=True)), + ], + ) + author_with_m2m_through = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "publishers", + models.ManyToManyField("testapp.Publisher", through="testapp.Contract"), + ), + ], + ) + author_with_renamed_m2m_through = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "publishers", + models.ManyToManyField("testapp.Publisher", through="testapp.Deal"), + ), + ], + ) + author_with_former_m2m = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("publishers", models.CharField(max_length=100)), + ], + ) + author_with_options = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ], + { + "permissions": [("can_hire", "Can hire")], + "verbose_name": "Authi", + }, + ) + author_with_db_table_options = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ], + {"db_table": "author_one"}, + ) + author_with_new_db_table_options = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ], + {"db_table": "author_two"}, + ) + author_renamed_with_db_table_options = ModelState( + "testapp", + "NewAuthor", + [ + ("id", models.AutoField(primary_key=True)), + ], + {"db_table": "author_one"}, + ) + author_renamed_with_new_db_table_options = ModelState( + "testapp", + "NewAuthor", + [ + ("id", models.AutoField(primary_key=True)), + ], + {"db_table": "author_three"}, + ) + contract = ModelState( + "testapp", + "Contract", + [ + ("id", models.AutoField(primary_key=True)), + ("author", models.ForeignKey("testapp.Author", models.CASCADE)), + ("publisher", models.ForeignKey("testapp.Publisher", models.CASCADE)), + ], + ) + contract_renamed = ModelState( + "testapp", + "Deal", + [ + ("id", models.AutoField(primary_key=True)), + ("author", models.ForeignKey("testapp.Author", models.CASCADE)), + ("publisher", models.ForeignKey("testapp.Publisher", models.CASCADE)), + ], + ) + publisher = ModelState( + "testapp", + "Publisher", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=100)), + ], + ) + publisher_with_author = ModelState( + "testapp", + "Publisher", + [ + ("id", models.AutoField(primary_key=True)), + ("author", models.ForeignKey("testapp.Author", models.CASCADE)), + ("name", models.CharField(max_length=100)), + ], + ) + publisher_with_aardvark_author = ModelState( + "testapp", + "Publisher", + [ + ("id", models.AutoField(primary_key=True)), + ("author", models.ForeignKey("testapp.Aardvark", models.CASCADE)), + ("name", models.CharField(max_length=100)), + ], + ) + publisher_with_book = ModelState( + "testapp", + "Publisher", + [ + ("id", models.AutoField(primary_key=True)), + ("author", models.ForeignKey("otherapp.Book", models.CASCADE)), + ("name", models.CharField(max_length=100)), + ], + ) + other_pony = ModelState( + "otherapp", + "Pony", + [ + ("id", models.AutoField(primary_key=True)), + ], + ) + other_pony_food = ModelState( + "otherapp", + "Pony", + [ + ("id", models.AutoField(primary_key=True)), + ], + managers=[ + ("food_qs", FoodQuerySet.as_manager()), + ("food_mgr", FoodManager("a", "b")), + ("food_mgr_kwargs", FoodManager("x", "y", 3, 4)), + ], + ) + other_stable = ModelState( + "otherapp", "Stable", [("id", models.AutoField(primary_key=True))] + ) + third_thing = ModelState( + "thirdapp", "Thing", [("id", models.AutoField(primary_key=True))] + ) + book = ModelState( + "otherapp", + "Book", + [ + ("id", models.AutoField(primary_key=True)), + ("author", models.ForeignKey("testapp.Author", models.CASCADE)), + ("title", models.CharField(max_length=200)), + ], + ) + book_proxy_fk = ModelState( + "otherapp", + "Book", + [ + ("id", models.AutoField(primary_key=True)), + ("author", models.ForeignKey("thirdapp.AuthorProxy", models.CASCADE)), + ("title", models.CharField(max_length=200)), + ], + ) + book_proxy_proxy_fk = ModelState( + "otherapp", + "Book", + [ + ("id", models.AutoField(primary_key=True)), + ("author", models.ForeignKey("testapp.AAuthorProxyProxy", models.CASCADE)), + ], + ) + book_migrations_fk = ModelState( + "otherapp", + "Book", + [ + ("id", models.AutoField(primary_key=True)), + ("author", models.ForeignKey("migrations.UnmigratedModel", models.CASCADE)), + ("title", models.CharField(max_length=200)), + ], + ) + book_with_no_author_fk = ModelState( + "otherapp", + "Book", + [ + ("id", models.AutoField(primary_key=True)), + ("author", models.IntegerField()), + ("title", models.CharField(max_length=200)), + ], + ) + book_with_no_author = ModelState( + "otherapp", + "Book", + [ + ("id", models.AutoField(primary_key=True)), + ("title", models.CharField(max_length=200)), + ], + ) + book_with_author_renamed = ModelState( + "otherapp", + "Book", + [ + ("id", models.AutoField(primary_key=True)), + ("author", models.ForeignKey("testapp.Writer", models.CASCADE)), + ("title", models.CharField(max_length=200)), + ], + ) + book_with_field_and_author_renamed = ModelState( + "otherapp", + "Book", + [ + ("id", models.AutoField(primary_key=True)), + ("writer", models.ForeignKey("testapp.Writer", models.CASCADE)), + ("title", models.CharField(max_length=200)), + ], + ) + book_with_multiple_authors = ModelState( + "otherapp", + "Book", + [ + ("id", models.AutoField(primary_key=True)), + ("authors", models.ManyToManyField("testapp.Author")), + ("title", models.CharField(max_length=200)), + ], + ) + book_with_multiple_authors_through_attribution = ModelState( + "otherapp", + "Book", + [ + ("id", models.AutoField(primary_key=True)), + ( + "authors", + models.ManyToManyField( + "testapp.Author", through="otherapp.Attribution" + ), + ), + ("title", models.CharField(max_length=200)), + ], + ) + book_indexes = ModelState( + "otherapp", + "Book", + [ + ("id", models.AutoField(primary_key=True)), + ("author", models.ForeignKey("testapp.Author", models.CASCADE)), + ("title", models.CharField(max_length=200)), + ], + { + "indexes": [ + models.Index(fields=["author", "title"], name="book_title_author_idx") + ], + }, + ) + book_unordered_indexes = ModelState( + "otherapp", + "Book", + [ + ("id", models.AutoField(primary_key=True)), + ("author", models.ForeignKey("testapp.Author", models.CASCADE)), + ("title", models.CharField(max_length=200)), + ], + { + "indexes": [ + models.Index(fields=["title", "author"], name="book_author_title_idx") + ], + }, + ) + book_foo_together = ModelState( + "otherapp", + "Book", + [ + ("id", models.AutoField(primary_key=True)), + ("author", models.ForeignKey("testapp.Author", models.CASCADE)), + ("title", models.CharField(max_length=200)), + ], + { + "index_together": {("author", "title")}, + "unique_together": {("author", "title")}, + }, + ) + book_foo_together_2 = ModelState( + "otherapp", + "Book", + [ + ("id", models.AutoField(primary_key=True)), + ("author", models.ForeignKey("testapp.Author", models.CASCADE)), + ("title", models.CharField(max_length=200)), + ], + { + "index_together": {("title", "author")}, + "unique_together": {("title", "author")}, + }, + ) + book_foo_together_3 = ModelState( + "otherapp", + "Book", + [ + ("id", models.AutoField(primary_key=True)), + ("newfield", models.IntegerField()), + ("author", models.ForeignKey("testapp.Author", models.CASCADE)), + ("title", models.CharField(max_length=200)), + ], + { + "index_together": {("title", "newfield")}, + "unique_together": {("title", "newfield")}, + }, + ) + book_foo_together_4 = ModelState( + "otherapp", + "Book", + [ + ("id", models.AutoField(primary_key=True)), + ("newfield2", models.IntegerField()), + ("author", models.ForeignKey("testapp.Author", models.CASCADE)), + ("title", models.CharField(max_length=200)), + ], + { + "index_together": {("title", "newfield2")}, + "unique_together": {("title", "newfield2")}, + }, + ) + attribution = ModelState( + "otherapp", + "Attribution", + [ + ("id", models.AutoField(primary_key=True)), + ("author", models.ForeignKey("testapp.Author", models.CASCADE)), + ("book", models.ForeignKey("otherapp.Book", models.CASCADE)), + ], + ) + edition = ModelState( + "thirdapp", + "Edition", + [ + ("id", models.AutoField(primary_key=True)), + ("book", models.ForeignKey("otherapp.Book", models.CASCADE)), + ], + ) + custom_user = ModelState( + "thirdapp", + "CustomUser", + [ + ("id", models.AutoField(primary_key=True)), + ("username", models.CharField(max_length=255)), + ], + bases=(AbstractBaseUser,), + ) + custom_user_no_inherit = ModelState( + "thirdapp", + "CustomUser", + [ + ("id", models.AutoField(primary_key=True)), + ("username", models.CharField(max_length=255)), + ], + ) + aardvark = ModelState( + "thirdapp", "Aardvark", [("id", models.AutoField(primary_key=True))] + ) + aardvark_testapp = ModelState( + "testapp", "Aardvark", [("id", models.AutoField(primary_key=True))] + ) + aardvark_based_on_author = ModelState( + "testapp", "Aardvark", [], bases=("testapp.Author",) + ) + aardvark_pk_fk_author = ModelState( + "testapp", + "Aardvark", + [ + ( + "id", + models.OneToOneField( + "testapp.Author", models.CASCADE, primary_key=True + ), + ), + ], ) - author_dates_of_birth_auto_now = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("date_of_birth", models.DateField(auto_now=True)), - ("date_time_of_birth", models.DateTimeField(auto_now=True)), - ("time_of_birth", models.TimeField(auto_now=True)), - ]) - author_dates_of_birth_auto_now_add = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("date_of_birth", models.DateField(auto_now_add=True)), - ("date_time_of_birth", models.DateTimeField(auto_now_add=True)), - ("time_of_birth", models.TimeField(auto_now_add=True)), - ]) - author_name_deconstructible_1 = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, default=DeconstructibleObject())), - ]) - author_name_deconstructible_2 = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, default=DeconstructibleObject())), - ]) - author_name_deconstructible_3 = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, default=models.IntegerField())), - ]) - author_name_deconstructible_4 = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, default=models.IntegerField())), - ]) - author_name_deconstructible_list_1 = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, default=[DeconstructibleObject(), 123])), - ]) - author_name_deconstructible_list_2 = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, default=[DeconstructibleObject(), 123])), - ]) - author_name_deconstructible_list_3 = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, default=[DeconstructibleObject(), 999])), - ]) - author_name_deconstructible_tuple_1 = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, default=(DeconstructibleObject(), 123))), - ]) - author_name_deconstructible_tuple_2 = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, default=(DeconstructibleObject(), 123))), - ]) - author_name_deconstructible_tuple_3 = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, default=(DeconstructibleObject(), 999))), - ]) - author_name_deconstructible_dict_1 = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, default={ - 'item': DeconstructibleObject(), 'otheritem': 123 - })), - ]) - author_name_deconstructible_dict_2 = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, default={ - 'item': DeconstructibleObject(), 'otheritem': 123 - })), - ]) - author_name_deconstructible_dict_3 = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, default={ - 'item': DeconstructibleObject(), 'otheritem': 999 - })), - ]) - author_name_nested_deconstructible_1 = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, default=DeconstructibleObject( - DeconstructibleObject(1), - (DeconstructibleObject('t1'), DeconstructibleObject('t2'),), - a=DeconstructibleObject('A'), - b=DeconstructibleObject(B=DeconstructibleObject('c')), - ))), - ]) - author_name_nested_deconstructible_2 = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, default=DeconstructibleObject( - DeconstructibleObject(1), - (DeconstructibleObject('t1'), DeconstructibleObject('t2'),), - a=DeconstructibleObject('A'), - b=DeconstructibleObject(B=DeconstructibleObject('c')), - ))), - ]) - author_name_nested_deconstructible_changed_arg = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, default=DeconstructibleObject( - DeconstructibleObject(1), - (DeconstructibleObject('t1'), DeconstructibleObject('t2-changed'),), - a=DeconstructibleObject('A'), - b=DeconstructibleObject(B=DeconstructibleObject('c')), - ))), - ]) - author_name_nested_deconstructible_extra_arg = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, default=DeconstructibleObject( - DeconstructibleObject(1), - (DeconstructibleObject('t1'), DeconstructibleObject('t2'),), - None, - a=DeconstructibleObject('A'), - b=DeconstructibleObject(B=DeconstructibleObject('c')), - ))), - ]) - author_name_nested_deconstructible_changed_kwarg = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, default=DeconstructibleObject( - DeconstructibleObject(1), - (DeconstructibleObject('t1'), DeconstructibleObject('t2'),), - a=DeconstructibleObject('A'), - b=DeconstructibleObject(B=DeconstructibleObject('c-changed')), - ))), - ]) - author_name_nested_deconstructible_extra_kwarg = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200, default=DeconstructibleObject( - DeconstructibleObject(1), - (DeconstructibleObject('t1'), DeconstructibleObject('t2'),), - a=DeconstructibleObject('A'), - b=DeconstructibleObject(B=DeconstructibleObject('c')), - c=None, - ))), - ]) - author_custom_pk = ModelState("testapp", "Author", [("pk_field", models.IntegerField(primary_key=True))]) - author_with_biography_non_blank = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField()), - ("biography", models.TextField()), - ]) - author_with_biography_blank = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(blank=True)), - ("biography", models.TextField(blank=True)), - ]) - author_with_book = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200)), - ("book", models.ForeignKey("otherapp.Book", models.CASCADE)), - ]) - author_with_book_order_wrt = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200)), - ("book", models.ForeignKey("otherapp.Book", models.CASCADE)), - ], options={"order_with_respect_to": "book"}) - author_renamed_with_book = ModelState("testapp", "Writer", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200)), - ("book", models.ForeignKey("otherapp.Book", models.CASCADE)), - ]) - author_with_publisher_string = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200)), - ("publisher_name", models.CharField(max_length=200)), - ]) - author_with_publisher = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200)), - ("publisher", models.ForeignKey("testapp.Publisher", models.CASCADE)), - ]) - author_with_user = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200)), - ("user", models.ForeignKey("auth.User", models.CASCADE)), - ]) - author_with_custom_user = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200)), - ("user", models.ForeignKey("thirdapp.CustomUser", models.CASCADE)), - ]) - author_proxy = ModelState("testapp", "AuthorProxy", [], {"proxy": True}, ("testapp.author",)) - author_proxy_options = ModelState("testapp", "AuthorProxy", [], { - "proxy": True, - "verbose_name": "Super Author", - }, ("testapp.author",)) - author_proxy_notproxy = ModelState("testapp", "AuthorProxy", [], {}, ("testapp.author",)) - author_proxy_third = ModelState("thirdapp", "AuthorProxy", [], {"proxy": True}, ("testapp.author",)) - author_proxy_third_notproxy = ModelState("thirdapp", "AuthorProxy", [], {}, ("testapp.author",)) - author_proxy_proxy = ModelState("testapp", "AAuthorProxyProxy", [], {"proxy": True}, ("testapp.authorproxy",)) - author_unmanaged = ModelState("testapp", "AuthorUnmanaged", [], {"managed": False}, ("testapp.author",)) - author_unmanaged_managed = ModelState("testapp", "AuthorUnmanaged", [], {}, ("testapp.author",)) - author_unmanaged_default_pk = ModelState("testapp", "Author", [("id", models.AutoField(primary_key=True))]) - author_unmanaged_custom_pk = ModelState("testapp", "Author", [ - ("pk_field", models.IntegerField(primary_key=True)), - ]) - author_with_m2m = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("publishers", models.ManyToManyField("testapp.Publisher")), - ]) - author_with_m2m_blank = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("publishers", models.ManyToManyField("testapp.Publisher", blank=True)), - ]) - author_with_m2m_through = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("publishers", models.ManyToManyField("testapp.Publisher", through="testapp.Contract")), - ]) - author_with_renamed_m2m_through = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("publishers", models.ManyToManyField("testapp.Publisher", through="testapp.Deal")), - ]) - author_with_former_m2m = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("publishers", models.CharField(max_length=100)), - ]) - author_with_options = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ], { - "permissions": [('can_hire', 'Can hire')], - "verbose_name": "Authi", - }) - author_with_db_table_options = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ], {"db_table": "author_one"}) - author_with_new_db_table_options = ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ], {"db_table": "author_two"}) - author_renamed_with_db_table_options = ModelState("testapp", "NewAuthor", [ - ("id", models.AutoField(primary_key=True)), - ], {"db_table": "author_one"}) - author_renamed_with_new_db_table_options = ModelState("testapp", "NewAuthor", [ - ("id", models.AutoField(primary_key=True)), - ], {"db_table": "author_three"}) - contract = ModelState("testapp", "Contract", [ - ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("testapp.Author", models.CASCADE)), - ("publisher", models.ForeignKey("testapp.Publisher", models.CASCADE)), - ]) - contract_renamed = ModelState("testapp", "Deal", [ - ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("testapp.Author", models.CASCADE)), - ("publisher", models.ForeignKey("testapp.Publisher", models.CASCADE)), - ]) - publisher = ModelState("testapp", "Publisher", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=100)), - ]) - publisher_with_author = ModelState("testapp", "Publisher", [ - ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("testapp.Author", models.CASCADE)), - ("name", models.CharField(max_length=100)), - ]) - publisher_with_aardvark_author = ModelState("testapp", "Publisher", [ - ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("testapp.Aardvark", models.CASCADE)), - ("name", models.CharField(max_length=100)), - ]) - publisher_with_book = ModelState("testapp", "Publisher", [ - ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("otherapp.Book", models.CASCADE)), - ("name", models.CharField(max_length=100)), - ]) - other_pony = ModelState("otherapp", "Pony", [ - ("id", models.AutoField(primary_key=True)), - ]) - other_pony_food = ModelState("otherapp", "Pony", [ - ("id", models.AutoField(primary_key=True)), - ], managers=[ - ('food_qs', FoodQuerySet.as_manager()), - ('food_mgr', FoodManager('a', 'b')), - ('food_mgr_kwargs', FoodManager('x', 'y', 3, 4)), - ]) - other_stable = ModelState("otherapp", "Stable", [("id", models.AutoField(primary_key=True))]) - third_thing = ModelState("thirdapp", "Thing", [("id", models.AutoField(primary_key=True))]) - book = ModelState("otherapp", "Book", [ - ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("testapp.Author", models.CASCADE)), - ("title", models.CharField(max_length=200)), - ]) - book_proxy_fk = ModelState("otherapp", "Book", [ - ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("thirdapp.AuthorProxy", models.CASCADE)), - ("title", models.CharField(max_length=200)), - ]) - book_proxy_proxy_fk = ModelState("otherapp", "Book", [ - ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("testapp.AAuthorProxyProxy", models.CASCADE)), - ]) - book_migrations_fk = ModelState("otherapp", "Book", [ - ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.UnmigratedModel", models.CASCADE)), - ("title", models.CharField(max_length=200)), - ]) - book_with_no_author_fk = ModelState("otherapp", "Book", [ - ("id", models.AutoField(primary_key=True)), - ("author", models.IntegerField()), - ("title", models.CharField(max_length=200)), - ]) - book_with_no_author = ModelState("otherapp", "Book", [ - ("id", models.AutoField(primary_key=True)), - ("title", models.CharField(max_length=200)), - ]) - book_with_author_renamed = ModelState("otherapp", "Book", [ - ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("testapp.Writer", models.CASCADE)), - ("title", models.CharField(max_length=200)), - ]) - book_with_field_and_author_renamed = ModelState("otherapp", "Book", [ - ("id", models.AutoField(primary_key=True)), - ("writer", models.ForeignKey("testapp.Writer", models.CASCADE)), - ("title", models.CharField(max_length=200)), - ]) - book_with_multiple_authors = ModelState("otherapp", "Book", [ - ("id", models.AutoField(primary_key=True)), - ("authors", models.ManyToManyField("testapp.Author")), - ("title", models.CharField(max_length=200)), - ]) - book_with_multiple_authors_through_attribution = ModelState("otherapp", "Book", [ - ("id", models.AutoField(primary_key=True)), - ("authors", models.ManyToManyField("testapp.Author", through="otherapp.Attribution")), - ("title", models.CharField(max_length=200)), - ]) - book_indexes = ModelState("otherapp", "Book", [ - ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("testapp.Author", models.CASCADE)), - ("title", models.CharField(max_length=200)), - ], { - "indexes": [models.Index(fields=["author", "title"], name="book_title_author_idx")], - }) - book_unordered_indexes = ModelState("otherapp", "Book", [ - ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("testapp.Author", models.CASCADE)), - ("title", models.CharField(max_length=200)), - ], { - "indexes": [models.Index(fields=["title", "author"], name="book_author_title_idx")], - }) - book_foo_together = ModelState("otherapp", "Book", [ - ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("testapp.Author", models.CASCADE)), - ("title", models.CharField(max_length=200)), - ], { - "index_together": {("author", "title")}, - "unique_together": {("author", "title")}, - }) - book_foo_together_2 = ModelState("otherapp", "Book", [ - ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("testapp.Author", models.CASCADE)), - ("title", models.CharField(max_length=200)), - ], { - "index_together": {("title", "author")}, - "unique_together": {("title", "author")}, - }) - book_foo_together_3 = ModelState("otherapp", "Book", [ - ("id", models.AutoField(primary_key=True)), - ("newfield", models.IntegerField()), - ("author", models.ForeignKey("testapp.Author", models.CASCADE)), - ("title", models.CharField(max_length=200)), - ], { - "index_together": {("title", "newfield")}, - "unique_together": {("title", "newfield")}, - }) - book_foo_together_4 = ModelState("otherapp", "Book", [ - ("id", models.AutoField(primary_key=True)), - ("newfield2", models.IntegerField()), - ("author", models.ForeignKey("testapp.Author", models.CASCADE)), - ("title", models.CharField(max_length=200)), - ], { - "index_together": {("title", "newfield2")}, - "unique_together": {("title", "newfield2")}, - }) - attribution = ModelState("otherapp", "Attribution", [ - ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("testapp.Author", models.CASCADE)), - ("book", models.ForeignKey("otherapp.Book", models.CASCADE)), - ]) - edition = ModelState("thirdapp", "Edition", [ - ("id", models.AutoField(primary_key=True)), - ("book", models.ForeignKey("otherapp.Book", models.CASCADE)), - ]) - custom_user = ModelState("thirdapp", "CustomUser", [ - ("id", models.AutoField(primary_key=True)), - ("username", models.CharField(max_length=255)), - ], bases=(AbstractBaseUser,)) - custom_user_no_inherit = ModelState("thirdapp", "CustomUser", [ - ("id", models.AutoField(primary_key=True)), - ("username", models.CharField(max_length=255)), - ]) - aardvark = ModelState("thirdapp", "Aardvark", [("id", models.AutoField(primary_key=True))]) - aardvark_testapp = ModelState("testapp", "Aardvark", [("id", models.AutoField(primary_key=True))]) - aardvark_based_on_author = ModelState("testapp", "Aardvark", [], bases=("testapp.Author",)) - aardvark_pk_fk_author = ModelState("testapp", "Aardvark", [ - ("id", models.OneToOneField("testapp.Author", models.CASCADE, primary_key=True)), - ]) knight = ModelState("eggs", "Knight", [("id", models.AutoField(primary_key=True))]) - rabbit = ModelState("eggs", "Rabbit", [ - ("id", models.AutoField(primary_key=True)), - ("knight", models.ForeignKey("eggs.Knight", models.CASCADE)), - ("parent", models.ForeignKey("eggs.Rabbit", models.CASCADE)), - ], { - "unique_together": {("parent", "knight")}, - "indexes": [models.Index(fields=["parent", "knight"], name='rabbit_circular_fk_index')], - }) + rabbit = ModelState( + "eggs", + "Rabbit", + [ + ("id", models.AutoField(primary_key=True)), + ("knight", models.ForeignKey("eggs.Knight", models.CASCADE)), + ("parent", models.ForeignKey("eggs.Rabbit", models.CASCADE)), + ], + { + "unique_together": {("parent", "knight")}, + "indexes": [ + models.Index( + fields=["parent", "knight"], name="rabbit_circular_fk_index" + ) + ], + }, + ) def repr_changes(self, changes, include_dependencies=False): output = "" @@ -481,100 +961,154 @@ class AutodetectorTests(TestCase): def assertNumberMigrations(self, changes, app_label, number): if len(changes.get(app_label, [])) != number: - self.fail("Incorrect number of migrations (%s) for %s (expected %s)\n%s" % ( - len(changes.get(app_label, [])), - app_label, - number, - self.repr_changes(changes), - )) + self.fail( + "Incorrect number of migrations (%s) for %s (expected %s)\n%s" + % ( + len(changes.get(app_label, [])), + app_label, + number, + self.repr_changes(changes), + ) + ) def assertMigrationDependencies(self, changes, app_label, position, dependencies): if not changes.get(app_label): - self.fail("No migrations found for %s\n%s" % (app_label, self.repr_changes(changes))) + self.fail( + "No migrations found for %s\n%s" + % (app_label, self.repr_changes(changes)) + ) if len(changes[app_label]) < position + 1: - self.fail("No migration at index %s for %s\n%s" % (position, app_label, self.repr_changes(changes))) + self.fail( + "No migration at index %s for %s\n%s" + % (position, app_label, self.repr_changes(changes)) + ) migration = changes[app_label][position] if set(migration.dependencies) != set(dependencies): - self.fail("Migration dependencies mismatch for %s.%s (expected %s):\n%s" % ( - app_label, - migration.name, - dependencies, - self.repr_changes(changes, include_dependencies=True), - )) + self.fail( + "Migration dependencies mismatch for %s.%s (expected %s):\n%s" + % ( + app_label, + migration.name, + dependencies, + self.repr_changes(changes, include_dependencies=True), + ) + ) def assertOperationTypes(self, changes, app_label, position, types): if not changes.get(app_label): - self.fail("No migrations found for %s\n%s" % (app_label, self.repr_changes(changes))) + self.fail( + "No migrations found for %s\n%s" + % (app_label, self.repr_changes(changes)) + ) if len(changes[app_label]) < position + 1: - self.fail("No migration at index %s for %s\n%s" % (position, app_label, self.repr_changes(changes))) + self.fail( + "No migration at index %s for %s\n%s" + % (position, app_label, self.repr_changes(changes)) + ) migration = changes[app_label][position] - real_types = [operation.__class__.__name__ for operation in migration.operations] + real_types = [ + operation.__class__.__name__ for operation in migration.operations + ] if types != real_types: - self.fail("Operation type mismatch for %s.%s (expected %s):\n%s" % ( - app_label, - migration.name, - types, - self.repr_changes(changes), - )) + self.fail( + "Operation type mismatch for %s.%s (expected %s):\n%s" + % ( + app_label, + migration.name, + types, + self.repr_changes(changes), + ) + ) - def assertOperationAttributes(self, changes, app_label, position, operation_position, **attrs): + def assertOperationAttributes( + self, changes, app_label, position, operation_position, **attrs + ): if not changes.get(app_label): - self.fail("No migrations found for %s\n%s" % (app_label, self.repr_changes(changes))) + self.fail( + "No migrations found for %s\n%s" + % (app_label, self.repr_changes(changes)) + ) if len(changes[app_label]) < position + 1: - self.fail("No migration at index %s for %s\n%s" % (position, app_label, self.repr_changes(changes))) + self.fail( + "No migration at index %s for %s\n%s" + % (position, app_label, self.repr_changes(changes)) + ) migration = changes[app_label][position] if len(changes[app_label]) < position + 1: - self.fail("No operation at index %s for %s.%s\n%s" % ( - operation_position, - app_label, - migration.name, - self.repr_changes(changes), - )) - operation = migration.operations[operation_position] - for attr, value in attrs.items(): - if getattr(operation, attr, None) != value: - self.fail("Attribute mismatch for %s.%s op #%s, %s (expected %r, got %r):\n%s" % ( + self.fail( + "No operation at index %s for %s.%s\n%s" + % ( + operation_position, app_label, migration.name, - operation_position, - attr, - value, - getattr(operation, attr, None), self.repr_changes(changes), - )) + ) + ) + operation = migration.operations[operation_position] + for attr, value in attrs.items(): + if getattr(operation, attr, None) != value: + self.fail( + "Attribute mismatch for %s.%s op #%s, %s (expected %r, got %r):\n%s" + % ( + app_label, + migration.name, + operation_position, + attr, + value, + getattr(operation, attr, None), + self.repr_changes(changes), + ) + ) - def assertOperationFieldAttributes(self, changes, app_label, position, operation_position, **attrs): + def assertOperationFieldAttributes( + self, changes, app_label, position, operation_position, **attrs + ): if not changes.get(app_label): - self.fail("No migrations found for %s\n%s" % (app_label, self.repr_changes(changes))) + self.fail( + "No migrations found for %s\n%s" + % (app_label, self.repr_changes(changes)) + ) if len(changes[app_label]) < position + 1: - self.fail("No migration at index %s for %s\n%s" % (position, app_label, self.repr_changes(changes))) + self.fail( + "No migration at index %s for %s\n%s" + % (position, app_label, self.repr_changes(changes)) + ) migration = changes[app_label][position] if len(changes[app_label]) < position + 1: - self.fail("No operation at index %s for %s.%s\n%s" % ( - operation_position, - app_label, - migration.name, - self.repr_changes(changes), - )) + self.fail( + "No operation at index %s for %s.%s\n%s" + % ( + operation_position, + app_label, + migration.name, + self.repr_changes(changes), + ) + ) operation = migration.operations[operation_position] - if not hasattr(operation, 'field'): - self.fail("No field attribute for %s.%s op #%s." % ( - app_label, - migration.name, - operation_position, - )) - field = operation.field - for attr, value in attrs.items(): - if getattr(field, attr, None) != value: - self.fail("Field attribute mismatch for %s.%s op #%s, field.%s (expected %r, got %r):\n%s" % ( + if not hasattr(operation, "field"): + self.fail( + "No field attribute for %s.%s op #%s." + % ( app_label, migration.name, operation_position, - attr, - value, - getattr(field, attr, None), - self.repr_changes(changes), - )) + ) + ) + field = operation.field + for attr, value in attrs.items(): + if getattr(field, attr, None) != value: + self.fail( + "Field attribute mismatch for %s.%s op #%s, field.%s (expected %r, got %r):\n%s" + % ( + app_label, + migration.name, + operation_position, + attr, + value, + getattr(field, attr, None), + self.repr_changes(changes), + ) + ) def make_project_state(self, model_states): "Shortcut to make ProjectStates from lists of predefined models" @@ -601,42 +1135,65 @@ class AutodetectorTests(TestCase): graph.add_node(("testapp", "0001_initial"), None) graph.add_node(("testapp", "0002_foobar"), None) graph.add_node(("otherapp", "0001_initial"), None) - graph.add_dependency("testapp.0002_foobar", ("testapp", "0002_foobar"), ("testapp", "0001_initial")) - graph.add_dependency("testapp.0002_foobar", ("testapp", "0002_foobar"), ("otherapp", "0001_initial")) + graph.add_dependency( + "testapp.0002_foobar", + ("testapp", "0002_foobar"), + ("testapp", "0001_initial"), + ) + graph.add_dependency( + "testapp.0002_foobar", + ("testapp", "0002_foobar"), + ("otherapp", "0001_initial"), + ) # Use project state to make a new migration change set before = self.make_project_state([self.publisher, self.other_pony]) - after = self.make_project_state([ - self.author_empty, self.publisher, self.other_pony, self.other_stable, - ]) + after = self.make_project_state( + [ + self.author_empty, + self.publisher, + self.other_pony, + self.other_stable, + ] + ) autodetector = MigrationAutodetector(before, after) changes = autodetector._detect_changes() # Run through arrange_for_graph changes = autodetector.arrange_for_graph(changes, graph) # Make sure there's a new name, deps match, etc. self.assertEqual(changes["testapp"][0].name, "0003_author") - self.assertEqual(changes["testapp"][0].dependencies, [("testapp", "0002_foobar")]) - self.assertEqual(changes["otherapp"][0].name, '0002_stable') - self.assertEqual(changes["otherapp"][0].dependencies, [("otherapp", "0001_initial")]) + self.assertEqual( + changes["testapp"][0].dependencies, [("testapp", "0002_foobar")] + ) + self.assertEqual(changes["otherapp"][0].name, "0002_stable") + self.assertEqual( + changes["otherapp"][0].dependencies, [("otherapp", "0001_initial")] + ) def test_arrange_for_graph_with_multiple_initial(self): # Make a fake graph. graph = MigrationGraph() # Use project state to make a new migration change set. before = self.make_project_state([]) - after = self.make_project_state([self.author_with_book, self.book, self.attribution]) - autodetector = MigrationAutodetector(before, after, MigrationQuestioner({'ask_initial': True})) + after = self.make_project_state( + [self.author_with_book, self.book, self.attribution] + ) + autodetector = MigrationAutodetector( + before, after, MigrationQuestioner({"ask_initial": True}) + ) changes = autodetector._detect_changes() changes = autodetector.arrange_for_graph(changes, graph) - self.assertEqual(changes['otherapp'][0].name, '0001_initial') - self.assertEqual(changes['otherapp'][0].dependencies, []) - self.assertEqual(changes['otherapp'][1].name, '0002_initial') + self.assertEqual(changes["otherapp"][0].name, "0001_initial") + self.assertEqual(changes["otherapp"][0].dependencies, []) + self.assertEqual(changes["otherapp"][1].name, "0002_initial") self.assertCountEqual( - changes['otherapp'][1].dependencies, - [('testapp', '0001_initial'), ('otherapp', '0001_initial')], + changes["otherapp"][1].dependencies, + [("testapp", "0001_initial"), ("otherapp", "0001_initial")], + ) + self.assertEqual(changes["testapp"][0].name, "0001_initial") + self.assertEqual( + changes["testapp"][0].dependencies, [("otherapp", "0001_initial")] ) - self.assertEqual(changes['testapp'][0].name, '0001_initial') - self.assertEqual(changes['testapp'][0].dependencies, [('otherapp', '0001_initial')]) def test_trim_apps(self): """ @@ -644,8 +1201,12 @@ class AutodetectorTests(TestCase): """ # Use project state to make a new migration change set before = self.make_project_state([]) - after = self.make_project_state([self.author_empty, self.other_pony, self.other_stable, self.third_thing]) - autodetector = MigrationAutodetector(before, after, MigrationQuestioner({"ask_initial": True})) + after = self.make_project_state( + [self.author_empty, self.other_pony, self.other_stable, self.third_thing] + ) + autodetector = MigrationAutodetector( + before, after, MigrationQuestioner({"ask_initial": True}) + ) changes = autodetector._detect_changes() # Run through arrange_for_graph graph = MigrationGraph() @@ -664,78 +1225,114 @@ class AutodetectorTests(TestCase): graph.add_node(("testapp", "0001_initial"), None) graph.add_node(("testapp", "0002_foobar"), None) graph.add_node(("otherapp", "0001_initial"), None) - graph.add_dependency("testapp.0002_foobar", ("testapp", "0002_foobar"), ("testapp", "0001_initial")) + graph.add_dependency( + "testapp.0002_foobar", + ("testapp", "0002_foobar"), + ("testapp", "0001_initial"), + ) # Use project state to make a new migration change set before = self.make_project_state([]) - after = self.make_project_state([self.author_empty, self.other_pony, self.other_stable]) + after = self.make_project_state( + [self.author_empty, self.other_pony, self.other_stable] + ) autodetector = MigrationAutodetector(before, after) changes = autodetector._detect_changes() # Run through arrange_for_graph - migration_name = 'custom_name' + migration_name = "custom_name" changes = autodetector.arrange_for_graph(changes, graph, migration_name) # Make sure there's a new name, deps match, etc. self.assertEqual(changes["testapp"][0].name, "0003_%s" % migration_name) - self.assertEqual(changes["testapp"][0].dependencies, [("testapp", "0002_foobar")]) + self.assertEqual( + changes["testapp"][0].dependencies, [("testapp", "0002_foobar")] + ) self.assertEqual(changes["otherapp"][0].name, "0002_%s" % migration_name) - self.assertEqual(changes["otherapp"][0].dependencies, [("otherapp", "0001_initial")]) + self.assertEqual( + changes["otherapp"][0].dependencies, [("otherapp", "0001_initial")] + ) def test_new_model(self): """Tests autodetection of new models.""" changes = self.get_changes([], [self.other_pony_food]) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'otherapp', 1) - self.assertOperationTypes(changes, 'otherapp', 0, ["CreateModel"]) + self.assertNumberMigrations(changes, "otherapp", 1) + self.assertOperationTypes(changes, "otherapp", 0, ["CreateModel"]) self.assertOperationAttributes(changes, "otherapp", 0, 0, name="Pony") - self.assertEqual([name for name, mgr in changes['otherapp'][0].operations[0].managers], - ['food_qs', 'food_mgr', 'food_mgr_kwargs']) + self.assertEqual( + [name for name, mgr in changes["otherapp"][0].operations[0].managers], + ["food_qs", "food_mgr", "food_mgr_kwargs"], + ) def test_old_model(self): """Tests deletion of old models.""" changes = self.get_changes([self.author_empty], []) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["DeleteModel"]) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["DeleteModel"]) self.assertOperationAttributes(changes, "testapp", 0, 0, name="Author") def test_add_field(self): """Tests autodetection of new fields.""" changes = self.get_changes([self.author_empty], [self.author_name]) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AddField"]) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["AddField"]) self.assertOperationAttributes(changes, "testapp", 0, 0, name="name") - @mock.patch('django.db.migrations.questioner.MigrationQuestioner.ask_not_null_addition', - side_effect=AssertionError("Should not have prompted for not null addition")) - def test_add_date_fields_with_auto_now_not_asking_for_default(self, mocked_ask_method): - changes = self.get_changes([self.author_empty], [self.author_dates_of_birth_auto_now]) + @mock.patch( + "django.db.migrations.questioner.MigrationQuestioner.ask_not_null_addition", + side_effect=AssertionError("Should not have prompted for not null addition"), + ) + def test_add_date_fields_with_auto_now_not_asking_for_default( + self, mocked_ask_method + ): + changes = self.get_changes( + [self.author_empty], [self.author_dates_of_birth_auto_now] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AddField", "AddField", "AddField"]) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes( + changes, "testapp", 0, ["AddField", "AddField", "AddField"] + ) self.assertOperationFieldAttributes(changes, "testapp", 0, 0, auto_now=True) self.assertOperationFieldAttributes(changes, "testapp", 0, 1, auto_now=True) self.assertOperationFieldAttributes(changes, "testapp", 0, 2, auto_now=True) - @mock.patch('django.db.migrations.questioner.MigrationQuestioner.ask_not_null_addition', - side_effect=AssertionError("Should not have prompted for not null addition")) - def test_add_date_fields_with_auto_now_add_not_asking_for_null_addition(self, mocked_ask_method): - changes = self.get_changes([self.author_empty], [self.author_dates_of_birth_auto_now_add]) + @mock.patch( + "django.db.migrations.questioner.MigrationQuestioner.ask_not_null_addition", + side_effect=AssertionError("Should not have prompted for not null addition"), + ) + def test_add_date_fields_with_auto_now_add_not_asking_for_null_addition( + self, mocked_ask_method + ): + changes = self.get_changes( + [self.author_empty], [self.author_dates_of_birth_auto_now_add] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AddField", "AddField", "AddField"]) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes( + changes, "testapp", 0, ["AddField", "AddField", "AddField"] + ) self.assertOperationFieldAttributes(changes, "testapp", 0, 0, auto_now_add=True) self.assertOperationFieldAttributes(changes, "testapp", 0, 1, auto_now_add=True) self.assertOperationFieldAttributes(changes, "testapp", 0, 2, auto_now_add=True) - @mock.patch('django.db.migrations.questioner.MigrationQuestioner.ask_auto_now_add_addition') - def test_add_date_fields_with_auto_now_add_asking_for_default(self, mocked_ask_method): - changes = self.get_changes([self.author_empty], [self.author_dates_of_birth_auto_now_add]) + @mock.patch( + "django.db.migrations.questioner.MigrationQuestioner.ask_auto_now_add_addition" + ) + def test_add_date_fields_with_auto_now_add_asking_for_default( + self, mocked_ask_method + ): + changes = self.get_changes( + [self.author_empty], [self.author_dates_of_birth_auto_now_add] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AddField", "AddField", "AddField"]) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes( + changes, "testapp", 0, ["AddField", "AddField", "AddField"] + ) self.assertOperationFieldAttributes(changes, "testapp", 0, 0, auto_now_add=True) self.assertOperationFieldAttributes(changes, "testapp", 0, 1, auto_now_add=True) self.assertOperationFieldAttributes(changes, "testapp", 0, 2, auto_now_add=True) @@ -745,83 +1342,136 @@ class AutodetectorTests(TestCase): """Tests autodetection of removed fields.""" changes = self.get_changes([self.author_name], [self.author_empty]) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["RemoveField"]) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["RemoveField"]) self.assertOperationAttributes(changes, "testapp", 0, 0, name="name") def test_alter_field(self): """Tests autodetection of new fields.""" changes = self.get_changes([self.author_name], [self.author_name_longer]) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AlterField"]) - self.assertOperationAttributes(changes, "testapp", 0, 0, name="name", preserve_default=True) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["AlterField"]) + self.assertOperationAttributes( + changes, "testapp", 0, 0, name="name", preserve_default=True + ) def test_supports_functools_partial(self): def _content_file_name(instance, filename, key, **kwargs): - return '{}/{}'.format(instance, filename) + return "{}/{}".format(instance, filename) def content_file_name(key, **kwargs): return functools.partial(_content_file_name, key, **kwargs) # An unchanged partial reference. - before = [ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("file", models.FileField(max_length=200, upload_to=content_file_name('file'))), - ])] - after = [ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("file", models.FileField(max_length=200, upload_to=content_file_name('file'))), - ])] + before = [ + ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "file", + models.FileField( + max_length=200, upload_to=content_file_name("file") + ), + ), + ], + ) + ] + after = [ + ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "file", + models.FileField( + max_length=200, upload_to=content_file_name("file") + ), + ), + ], + ) + ] changes = self.get_changes(before, after) - self.assertNumberMigrations(changes, 'testapp', 0) + self.assertNumberMigrations(changes, "testapp", 0) # A changed partial reference. - args_changed = [ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("file", models.FileField(max_length=200, upload_to=content_file_name('other-file'))), - ])] + args_changed = [ + ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "file", + models.FileField( + max_length=200, upload_to=content_file_name("other-file") + ), + ), + ], + ) + ] changes = self.get_changes(before, args_changed) - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ['AlterField']) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["AlterField"]) # Can't use assertOperationFieldAttributes because we need the # deconstructed version, i.e., the exploded func/args/keywords rather # than the partial: we don't care if it's not the same instance of the # partial, only if it's the same source function, args, and keywords. - value = changes['testapp'][0].operations[0].field.upload_to + value = changes["testapp"][0].operations[0].field.upload_to self.assertEqual( - (_content_file_name, ('other-file',), {}), - (value.func, value.args, value.keywords) + (_content_file_name, ("other-file",), {}), + (value.func, value.args, value.keywords), ) - kwargs_changed = [ModelState("testapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("file", models.FileField(max_length=200, upload_to=content_file_name('file', spam='eggs'))), - ])] + kwargs_changed = [ + ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ( + "file", + models.FileField( + max_length=200, + upload_to=content_file_name("file", spam="eggs"), + ), + ), + ], + ) + ] changes = self.get_changes(before, kwargs_changed) - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ['AlterField']) - value = changes['testapp'][0].operations[0].field.upload_to + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["AlterField"]) + value = changes["testapp"][0].operations[0].field.upload_to self.assertEqual( - (_content_file_name, ('file',), {'spam': 'eggs'}), - (value.func, value.args, value.keywords) + (_content_file_name, ("file",), {"spam": "eggs"}), + (value.func, value.args, value.keywords), ) - @mock.patch('django.db.migrations.questioner.MigrationQuestioner.ask_not_null_alteration', - side_effect=AssertionError("Should not have prompted for not null addition")) + @mock.patch( + "django.db.migrations.questioner.MigrationQuestioner.ask_not_null_alteration", + side_effect=AssertionError("Should not have prompted for not null addition"), + ) def test_alter_field_to_not_null_with_default(self, mocked_ask_method): """ #23609 - Tests autodetection of nullable to non-nullable alterations. """ changes = self.get_changes([self.author_name_null], [self.author_name_default]) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AlterField"]) - self.assertOperationAttributes(changes, "testapp", 0, 0, name="name", preserve_default=True) - self.assertOperationFieldAttributes(changes, "testapp", 0, 0, default='Ada Lovelace') + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["AlterField"]) + self.assertOperationAttributes( + changes, "testapp", 0, 0, name="name", preserve_default=True + ) + self.assertOperationFieldAttributes( + changes, "testapp", 0, 0, default="Ada Lovelace" + ) @mock.patch( - 'django.db.migrations.questioner.MigrationQuestioner.ask_not_null_alteration', + "django.db.migrations.questioner.MigrationQuestioner.ask_not_null_alteration", return_value=models.NOT_PROVIDED, ) def test_alter_field_to_not_null_without_default(self, mocked_ask_method): @@ -831,14 +1481,18 @@ class AutodetectorTests(TestCase): changes = self.get_changes([self.author_name_null], [self.author_name]) self.assertEqual(mocked_ask_method.call_count, 1) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AlterField"]) - self.assertOperationAttributes(changes, "testapp", 0, 0, name="name", preserve_default=True) - self.assertOperationFieldAttributes(changes, "testapp", 0, 0, default=models.NOT_PROVIDED) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["AlterField"]) + self.assertOperationAttributes( + changes, "testapp", 0, 0, name="name", preserve_default=True + ) + self.assertOperationFieldAttributes( + changes, "testapp", 0, 0, default=models.NOT_PROVIDED + ) @mock.patch( - 'django.db.migrations.questioner.MigrationQuestioner.ask_not_null_alteration', - return_value='Some Name', + "django.db.migrations.questioner.MigrationQuestioner.ask_not_null_alteration", + return_value="Some Name", ) def test_alter_field_to_not_null_oneoff_default(self, mocked_ask_method): """ @@ -847,140 +1501,269 @@ class AutodetectorTests(TestCase): changes = self.get_changes([self.author_name_null], [self.author_name]) self.assertEqual(mocked_ask_method.call_count, 1) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AlterField"]) - self.assertOperationAttributes(changes, "testapp", 0, 0, name="name", preserve_default=False) - self.assertOperationFieldAttributes(changes, "testapp", 0, 0, default="Some Name") + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["AlterField"]) + self.assertOperationAttributes( + changes, "testapp", 0, 0, name="name", preserve_default=False + ) + self.assertOperationFieldAttributes( + changes, "testapp", 0, 0, default="Some Name" + ) def test_rename_field(self): """Tests autodetection of renamed fields.""" changes = self.get_changes( - [self.author_name], [self.author_name_renamed], MigrationQuestioner({"ask_rename": True}) + [self.author_name], + [self.author_name_renamed], + MigrationQuestioner({"ask_rename": True}), ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["RenameField"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, old_name="name", new_name="names") + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["RenameField"]) + self.assertOperationAttributes( + changes, "testapp", 0, 0, old_name="name", new_name="names" + ) def test_rename_field_foreign_key_to_field(self): before = [ - ModelState('app', 'Foo', [ - ('id', models.AutoField(primary_key=True)), - ('field', models.IntegerField(unique=True)), - ]), - ModelState('app', 'Bar', [ - ('id', models.AutoField(primary_key=True)), - ('foo', models.ForeignKey('app.Foo', models.CASCADE, to_field='field')), - ]), + ModelState( + "app", + "Foo", + [ + ("id", models.AutoField(primary_key=True)), + ("field", models.IntegerField(unique=True)), + ], + ), + ModelState( + "app", + "Bar", + [ + ("id", models.AutoField(primary_key=True)), + ( + "foo", + models.ForeignKey("app.Foo", models.CASCADE, to_field="field"), + ), + ], + ), ] after = [ - ModelState('app', 'Foo', [ - ('id', models.AutoField(primary_key=True)), - ('renamed_field', models.IntegerField(unique=True)), - ]), - ModelState('app', 'Bar', [ - ('id', models.AutoField(primary_key=True)), - ('foo', models.ForeignKey('app.Foo', models.CASCADE, to_field='renamed_field')), - ]), + ModelState( + "app", + "Foo", + [ + ("id", models.AutoField(primary_key=True)), + ("renamed_field", models.IntegerField(unique=True)), + ], + ), + ModelState( + "app", + "Bar", + [ + ("id", models.AutoField(primary_key=True)), + ( + "foo", + models.ForeignKey( + "app.Foo", models.CASCADE, to_field="renamed_field" + ), + ), + ], + ), ] - changes = self.get_changes(before, after, MigrationQuestioner({'ask_rename': True})) + changes = self.get_changes( + before, after, MigrationQuestioner({"ask_rename": True}) + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'app', 1) - self.assertOperationTypes(changes, 'app', 0, ['RenameField']) - self.assertOperationAttributes(changes, 'app', 0, 0, old_name='field', new_name='renamed_field') + self.assertNumberMigrations(changes, "app", 1) + self.assertOperationTypes(changes, "app", 0, ["RenameField"]) + self.assertOperationAttributes( + changes, "app", 0, 0, old_name="field", new_name="renamed_field" + ) def test_rename_foreign_object_fields(self): - fields = ('first', 'second') - renamed_fields = ('first_renamed', 'second_renamed') + fields = ("first", "second") + renamed_fields = ("first_renamed", "second_renamed") before = [ - ModelState('app', 'Foo', [ - ('id', models.AutoField(primary_key=True)), - ('first', models.IntegerField()), - ('second', models.IntegerField()), - ], options={'unique_together': {fields}}), - ModelState('app', 'Bar', [ - ('id', models.AutoField(primary_key=True)), - ('first', models.IntegerField()), - ('second', models.IntegerField()), - ('foo', models.ForeignObject( - 'app.Foo', models.CASCADE, from_fields=fields, to_fields=fields, - )), - ]), + ModelState( + "app", + "Foo", + [ + ("id", models.AutoField(primary_key=True)), + ("first", models.IntegerField()), + ("second", models.IntegerField()), + ], + options={"unique_together": {fields}}, + ), + ModelState( + "app", + "Bar", + [ + ("id", models.AutoField(primary_key=True)), + ("first", models.IntegerField()), + ("second", models.IntegerField()), + ( + "foo", + models.ForeignObject( + "app.Foo", + models.CASCADE, + from_fields=fields, + to_fields=fields, + ), + ), + ], + ), ] # Case 1: to_fields renames. after = [ - ModelState('app', 'Foo', [ - ('id', models.AutoField(primary_key=True)), - ('first_renamed', models.IntegerField()), - ('second_renamed', models.IntegerField()), - ], options={'unique_together': {renamed_fields}}), - ModelState('app', 'Bar', [ - ('id', models.AutoField(primary_key=True)), - ('first', models.IntegerField()), - ('second', models.IntegerField()), - ('foo', models.ForeignObject( - 'app.Foo', models.CASCADE, from_fields=fields, to_fields=renamed_fields, - )), - ]), + ModelState( + "app", + "Foo", + [ + ("id", models.AutoField(primary_key=True)), + ("first_renamed", models.IntegerField()), + ("second_renamed", models.IntegerField()), + ], + options={"unique_together": {renamed_fields}}, + ), + ModelState( + "app", + "Bar", + [ + ("id", models.AutoField(primary_key=True)), + ("first", models.IntegerField()), + ("second", models.IntegerField()), + ( + "foo", + models.ForeignObject( + "app.Foo", + models.CASCADE, + from_fields=fields, + to_fields=renamed_fields, + ), + ), + ], + ), ] - changes = self.get_changes(before, after, MigrationQuestioner({'ask_rename': True})) - self.assertNumberMigrations(changes, 'app', 1) - self.assertOperationTypes(changes, 'app', 0, ['RenameField', 'RenameField', 'AlterUniqueTogether']) + changes = self.get_changes( + before, after, MigrationQuestioner({"ask_rename": True}) + ) + self.assertNumberMigrations(changes, "app", 1) + self.assertOperationTypes( + changes, "app", 0, ["RenameField", "RenameField", "AlterUniqueTogether"] + ) self.assertOperationAttributes( - changes, 'app', 0, 0, model_name='foo', old_name='first', new_name='first_renamed', + changes, + "app", + 0, + 0, + model_name="foo", + old_name="first", + new_name="first_renamed", ) self.assertOperationAttributes( - changes, 'app', 0, 1, model_name='foo', old_name='second', new_name='second_renamed', + changes, + "app", + 0, + 1, + model_name="foo", + old_name="second", + new_name="second_renamed", ) # Case 2: from_fields renames. after = [ - ModelState('app', 'Foo', [ - ('id', models.AutoField(primary_key=True)), - ('first', models.IntegerField()), - ('second', models.IntegerField()), - ], options={'unique_together': {fields}}), - ModelState('app', 'Bar', [ - ('id', models.AutoField(primary_key=True)), - ('first_renamed', models.IntegerField()), - ('second_renamed', models.IntegerField()), - ('foo', models.ForeignObject( - 'app.Foo', models.CASCADE, from_fields=renamed_fields, to_fields=fields, - )), - ]), + ModelState( + "app", + "Foo", + [ + ("id", models.AutoField(primary_key=True)), + ("first", models.IntegerField()), + ("second", models.IntegerField()), + ], + options={"unique_together": {fields}}, + ), + ModelState( + "app", + "Bar", + [ + ("id", models.AutoField(primary_key=True)), + ("first_renamed", models.IntegerField()), + ("second_renamed", models.IntegerField()), + ( + "foo", + models.ForeignObject( + "app.Foo", + models.CASCADE, + from_fields=renamed_fields, + to_fields=fields, + ), + ), + ], + ), ] - changes = self.get_changes(before, after, MigrationQuestioner({'ask_rename': True})) - self.assertNumberMigrations(changes, 'app', 1) - self.assertOperationTypes(changes, 'app', 0, ['RenameField', 'RenameField']) + changes = self.get_changes( + before, after, MigrationQuestioner({"ask_rename": True}) + ) + self.assertNumberMigrations(changes, "app", 1) + self.assertOperationTypes(changes, "app", 0, ["RenameField", "RenameField"]) self.assertOperationAttributes( - changes, 'app', 0, 0, model_name='bar', old_name='first', new_name='first_renamed', + changes, + "app", + 0, + 0, + model_name="bar", + old_name="first", + new_name="first_renamed", ) self.assertOperationAttributes( - changes, 'app', 0, 1, model_name='bar', old_name='second', new_name='second_renamed', + changes, + "app", + 0, + 1, + model_name="bar", + old_name="second", + new_name="second_renamed", ) def test_rename_referenced_primary_key(self): before = [ - ModelState('app', 'Foo', [ - ('id', models.CharField(primary_key=True, serialize=False)), - ]), - ModelState('app', 'Bar', [ - ('id', models.AutoField(primary_key=True)), - ('foo', models.ForeignKey('app.Foo', models.CASCADE)), - ]), + ModelState( + "app", + "Foo", + [ + ("id", models.CharField(primary_key=True, serialize=False)), + ], + ), + ModelState( + "app", + "Bar", + [ + ("id", models.AutoField(primary_key=True)), + ("foo", models.ForeignKey("app.Foo", models.CASCADE)), + ], + ), ] after = [ - ModelState('app', 'Foo', [ - ('renamed_id', models.CharField(primary_key=True, serialize=False)) - ]), - ModelState('app', 'Bar', [ - ('id', models.AutoField(primary_key=True)), - ('foo', models.ForeignKey('app.Foo', models.CASCADE)), - ]), + ModelState( + "app", + "Foo", + [("renamed_id", models.CharField(primary_key=True, serialize=False))], + ), + ModelState( + "app", + "Bar", + [ + ("id", models.AutoField(primary_key=True)), + ("foo", models.ForeignKey("app.Foo", models.CASCADE)), + ], + ), ] - changes = self.get_changes(before, after, MigrationQuestioner({'ask_rename': True})) - self.assertNumberMigrations(changes, 'app', 1) - self.assertOperationTypes(changes, 'app', 0, ['RenameField']) - self.assertOperationAttributes(changes, 'app', 0, 0, old_name='id', new_name='renamed_id') + changes = self.get_changes( + before, after, MigrationQuestioner({"ask_rename": True}) + ) + self.assertNumberMigrations(changes, "app", 1) + self.assertOperationTypes(changes, "app", 0, ["RenameField"]) + self.assertOperationAttributes( + changes, "app", 0, 0, old_name="id", new_name="renamed_id" + ) def test_rename_field_preserved_db_column(self): """ @@ -988,85 +1771,161 @@ class AutodetectorTests(TestCase): old field's column is added. """ before = [ - ModelState('app', 'Foo', [ - ('id', models.AutoField(primary_key=True)), - ('field', models.IntegerField()), - ]), + ModelState( + "app", + "Foo", + [ + ("id", models.AutoField(primary_key=True)), + ("field", models.IntegerField()), + ], + ), ] after = [ - ModelState('app', 'Foo', [ - ('id', models.AutoField(primary_key=True)), - ('renamed_field', models.IntegerField(db_column='field')), - ]), + ModelState( + "app", + "Foo", + [ + ("id", models.AutoField(primary_key=True)), + ("renamed_field", models.IntegerField(db_column="field")), + ], + ), ] - changes = self.get_changes(before, after, MigrationQuestioner({'ask_rename': True})) - self.assertNumberMigrations(changes, 'app', 1) - self.assertOperationTypes(changes, 'app', 0, ['AlterField', 'RenameField']) + changes = self.get_changes( + before, after, MigrationQuestioner({"ask_rename": True}) + ) + self.assertNumberMigrations(changes, "app", 1) + self.assertOperationTypes(changes, "app", 0, ["AlterField", "RenameField"]) self.assertOperationAttributes( - changes, 'app', 0, 0, model_name='foo', name='field', + changes, + "app", + 0, + 0, + model_name="foo", + name="field", + ) + self.assertEqual( + changes["app"][0].operations[0].field.deconstruct(), + ( + "field", + "django.db.models.IntegerField", + [], + {"db_column": "field"}, + ), ) - self.assertEqual(changes['app'][0].operations[0].field.deconstruct(), ( - 'field', 'django.db.models.IntegerField', [], {'db_column': 'field'}, - )) self.assertOperationAttributes( - changes, 'app', 0, 1, model_name='foo', old_name='field', - new_name='renamed_field', + changes, + "app", + 0, + 1, + model_name="foo", + old_name="field", + new_name="renamed_field", ) def test_rename_related_field_preserved_db_column(self): before = [ - ModelState('app', 'Foo', [ - ('id', models.AutoField(primary_key=True)), - ]), - ModelState('app', 'Bar', [ - ('id', models.AutoField(primary_key=True)), - ('foo', models.ForeignKey('app.Foo', models.CASCADE)), - ]), + ModelState( + "app", + "Foo", + [ + ("id", models.AutoField(primary_key=True)), + ], + ), + ModelState( + "app", + "Bar", + [ + ("id", models.AutoField(primary_key=True)), + ("foo", models.ForeignKey("app.Foo", models.CASCADE)), + ], + ), ] after = [ - ModelState('app', 'Foo', [ - ('id', models.AutoField(primary_key=True)), - ]), - ModelState('app', 'Bar', [ - ('id', models.AutoField(primary_key=True)), - ('renamed_foo', models.ForeignKey('app.Foo', models.CASCADE, db_column='foo_id')), - ]), + ModelState( + "app", + "Foo", + [ + ("id", models.AutoField(primary_key=True)), + ], + ), + ModelState( + "app", + "Bar", + [ + ("id", models.AutoField(primary_key=True)), + ( + "renamed_foo", + models.ForeignKey( + "app.Foo", models.CASCADE, db_column="foo_id" + ), + ), + ], + ), ] - changes = self.get_changes(before, after, MigrationQuestioner({'ask_rename': True})) - self.assertNumberMigrations(changes, 'app', 1) - self.assertOperationTypes(changes, 'app', 0, ['AlterField', 'RenameField']) + changes = self.get_changes( + before, after, MigrationQuestioner({"ask_rename": True}) + ) + self.assertNumberMigrations(changes, "app", 1) + self.assertOperationTypes(changes, "app", 0, ["AlterField", "RenameField"]) self.assertOperationAttributes( - changes, 'app', 0, 0, model_name='bar', name='foo', + changes, + "app", + 0, + 0, + model_name="bar", + name="foo", + ) + self.assertEqual( + changes["app"][0].operations[0].field.deconstruct(), + ( + "foo", + "django.db.models.ForeignKey", + [], + {"to": "app.foo", "on_delete": models.CASCADE, "db_column": "foo_id"}, + ), ) - self.assertEqual(changes['app'][0].operations[0].field.deconstruct(), ( - 'foo', - 'django.db.models.ForeignKey', - [], - {'to': 'app.foo', 'on_delete': models.CASCADE, 'db_column': 'foo_id'}, - )) self.assertOperationAttributes( - changes, 'app', 0, 1, model_name='bar', old_name='foo', - new_name='renamed_foo', + changes, + "app", + 0, + 1, + model_name="bar", + old_name="foo", + new_name="renamed_foo", ) def test_rename_field_with_renamed_model(self): changes = self.get_changes( [self.author_name], [ - ModelState('testapp', 'RenamedAuthor', [ - ('id', models.AutoField(primary_key=True)), - ('renamed_name', models.CharField(max_length=200)), - ]), + ModelState( + "testapp", + "RenamedAuthor", + [ + ("id", models.AutoField(primary_key=True)), + ("renamed_name", models.CharField(max_length=200)), + ], + ), ], - MigrationQuestioner({'ask_rename_model': True, 'ask_rename': True}), + MigrationQuestioner({"ask_rename_model": True, "ask_rename": True}), ) - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ['RenameModel', 'RenameField']) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["RenameModel", "RenameField"]) self.assertOperationAttributes( - changes, 'testapp', 0, 0, old_name='Author', new_name='RenamedAuthor', + changes, + "testapp", + 0, + 0, + old_name="Author", + new_name="RenamedAuthor", ) self.assertOperationAttributes( - changes, 'testapp', 0, 1, old_name='name', new_name='renamed_name', + changes, + "testapp", + 0, + 1, + old_name="name", + new_name="renamed_name", ) def test_rename_model(self): @@ -1077,41 +1936,51 @@ class AutodetectorTests(TestCase): MigrationQuestioner({"ask_rename_model": True}), ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["RenameModel"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, old_name="Author", new_name="Writer") + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["RenameModel"]) + self.assertOperationAttributes( + changes, "testapp", 0, 0, old_name="Author", new_name="Writer" + ) # Now that RenameModel handles related fields too, there should be # no AlterField for the related field. - self.assertNumberMigrations(changes, 'otherapp', 0) + self.assertNumberMigrations(changes, "otherapp", 0) def test_rename_model_case(self): """ Model name is case-insensitive. Changing case doesn't lead to any autodetected operations. """ - author_renamed = ModelState('testapp', 'author', [ - ('id', models.AutoField(primary_key=True)), - ]) + author_renamed = ModelState( + "testapp", + "author", + [ + ("id", models.AutoField(primary_key=True)), + ], + ) changes = self.get_changes( [self.author_empty, self.book], [author_renamed, self.book], - questioner=MigrationQuestioner({'ask_rename_model': True}), + questioner=MigrationQuestioner({"ask_rename_model": True}), ) - self.assertNumberMigrations(changes, 'testapp', 0) - self.assertNumberMigrations(changes, 'otherapp', 0) + self.assertNumberMigrations(changes, "testapp", 0) + self.assertNumberMigrations(changes, "otherapp", 0) def test_renamed_referenced_m2m_model_case(self): - publisher_renamed = ModelState('testapp', 'publisher', [ - ('id', models.AutoField(primary_key=True)), - ('name', models.CharField(max_length=100)), - ]) + publisher_renamed = ModelState( + "testapp", + "publisher", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=100)), + ], + ) changes = self.get_changes( [self.publisher, self.author_with_m2m], [publisher_renamed, self.author_with_m2m], - questioner=MigrationQuestioner({'ask_rename_model': True}), + questioner=MigrationQuestioner({"ask_rename_model": True}), ) - self.assertNumberMigrations(changes, 'testapp', 0) - self.assertNumberMigrations(changes, 'otherapp', 0) + self.assertNumberMigrations(changes, "testapp", 0) + self.assertNumberMigrations(changes, "otherapp", 0) def test_rename_m2m_through_model(self): """ @@ -1120,13 +1989,19 @@ class AutodetectorTests(TestCase): """ changes = self.get_changes( [self.author_with_m2m_through, self.publisher, self.contract], - [self.author_with_renamed_m2m_through, self.publisher, self.contract_renamed], - MigrationQuestioner({'ask_rename_model': True}) + [ + self.author_with_renamed_m2m_through, + self.publisher, + self.contract_renamed, + ], + MigrationQuestioner({"ask_rename_model": True}), ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ['RenameModel']) - self.assertOperationAttributes(changes, 'testapp', 0, 0, old_name='Contract', new_name='Deal') + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["RenameModel"]) + self.assertOperationAttributes( + changes, "testapp", 0, 0, old_name="Contract", new_name="Deal" + ) def test_rename_model_with_renamed_rel_field(self): """ @@ -1139,14 +2014,18 @@ class AutodetectorTests(TestCase): MigrationQuestioner({"ask_rename": True, "ask_rename_model": True}), ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["RenameModel"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, old_name="Author", new_name="Writer") + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["RenameModel"]) + self.assertOperationAttributes( + changes, "testapp", 0, 0, old_name="Author", new_name="Writer" + ) # Right number/type of migrations for related field rename? # Alter is already taken care of. - self.assertNumberMigrations(changes, 'otherapp', 1) - self.assertOperationTypes(changes, 'otherapp', 0, ["RenameField"]) - self.assertOperationAttributes(changes, 'otherapp', 0, 0, old_name="author", new_name="writer") + self.assertNumberMigrations(changes, "otherapp", 1) + self.assertOperationTypes(changes, "otherapp", 0, ["RenameField"]) + self.assertOperationAttributes( + changes, "otherapp", 0, 0, old_name="author", new_name="writer" + ) def test_rename_model_with_fks_in_different_position(self): """ @@ -1154,29 +2033,49 @@ class AutodetectorTests(TestCase): the RenameModel detection. """ before = [ - ModelState("testapp", "EntityA", [ - ("id", models.AutoField(primary_key=True)), - ]), - ModelState("testapp", "EntityB", [ - ("id", models.AutoField(primary_key=True)), - ("some_label", models.CharField(max_length=255)), - ("entity_a", models.ForeignKey("testapp.EntityA", models.CASCADE)), - ]), + ModelState( + "testapp", + "EntityA", + [ + ("id", models.AutoField(primary_key=True)), + ], + ), + ModelState( + "testapp", + "EntityB", + [ + ("id", models.AutoField(primary_key=True)), + ("some_label", models.CharField(max_length=255)), + ("entity_a", models.ForeignKey("testapp.EntityA", models.CASCADE)), + ], + ), ] after = [ - ModelState("testapp", "EntityA", [ - ("id", models.AutoField(primary_key=True)), - ]), - ModelState("testapp", "RenamedEntityB", [ - ("id", models.AutoField(primary_key=True)), - ("entity_a", models.ForeignKey("testapp.EntityA", models.CASCADE)), - ("some_label", models.CharField(max_length=255)), - ]), + ModelState( + "testapp", + "EntityA", + [ + ("id", models.AutoField(primary_key=True)), + ], + ), + ModelState( + "testapp", + "RenamedEntityB", + [ + ("id", models.AutoField(primary_key=True)), + ("entity_a", models.ForeignKey("testapp.EntityA", models.CASCADE)), + ("some_label", models.CharField(max_length=255)), + ], + ), ] - changes = self.get_changes(before, after, MigrationQuestioner({"ask_rename_model": True})) + changes = self.get_changes( + before, after, MigrationQuestioner({"ask_rename_model": True}) + ) self.assertNumberMigrations(changes, "testapp", 1) self.assertOperationTypes(changes, "testapp", 0, ["RenameModel"]) - self.assertOperationAttributes(changes, "testapp", 0, 0, old_name="EntityB", new_name="RenamedEntityB") + self.assertOperationAttributes( + changes, "testapp", 0, 0, old_name="EntityB", new_name="RenamedEntityB" + ) def test_rename_model_reverse_relation_dependencies(self): """ @@ -1186,28 +2085,53 @@ class AutodetectorTests(TestCase): dependency on that other migration. """ before = [ - ModelState('testapp', 'EntityA', [ - ('id', models.AutoField(primary_key=True)), - ]), - ModelState('otherapp', 'EntityB', [ - ('id', models.AutoField(primary_key=True)), - ('entity_a', models.ForeignKey('testapp.EntityA', models.CASCADE)), - ]), + ModelState( + "testapp", + "EntityA", + [ + ("id", models.AutoField(primary_key=True)), + ], + ), + ModelState( + "otherapp", + "EntityB", + [ + ("id", models.AutoField(primary_key=True)), + ("entity_a", models.ForeignKey("testapp.EntityA", models.CASCADE)), + ], + ), ] after = [ - ModelState('testapp', 'RenamedEntityA', [ - ('id', models.AutoField(primary_key=True)), - ]), - ModelState('otherapp', 'EntityB', [ - ('id', models.AutoField(primary_key=True)), - ('entity_a', models.ForeignKey('testapp.RenamedEntityA', models.CASCADE)), - ]), + ModelState( + "testapp", + "RenamedEntityA", + [ + ("id", models.AutoField(primary_key=True)), + ], + ), + ModelState( + "otherapp", + "EntityB", + [ + ("id", models.AutoField(primary_key=True)), + ( + "entity_a", + models.ForeignKey("testapp.RenamedEntityA", models.CASCADE), + ), + ], + ), ] - changes = self.get_changes(before, after, MigrationQuestioner({'ask_rename_model': True})) - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertMigrationDependencies(changes, 'testapp', 0, [('otherapp', '__first__')]) - self.assertOperationTypes(changes, 'testapp', 0, ['RenameModel']) - self.assertOperationAttributes(changes, 'testapp', 0, 0, old_name='EntityA', new_name='RenamedEntityA') + changes = self.get_changes( + before, after, MigrationQuestioner({"ask_rename_model": True}) + ) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertMigrationDependencies( + changes, "testapp", 0, [("otherapp", "__first__")] + ) + self.assertOperationTypes(changes, "testapp", 0, ["RenameModel"]) + self.assertOperationAttributes( + changes, "testapp", 0, 0, old_name="EntityA", new_name="RenamedEntityA" + ) def test_fk_dependency(self): """Having a ForeignKey automatically adds a dependency.""" @@ -1216,41 +2140,51 @@ class AutodetectorTests(TestCase): # thirdapp (edition) depends on otherapp (book) changes = self.get_changes([], [self.author_name, self.book, self.edition]) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Author") - self.assertMigrationDependencies(changes, 'testapp', 0, []) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["CreateModel"]) + self.assertOperationAttributes(changes, "testapp", 0, 0, name="Author") + self.assertMigrationDependencies(changes, "testapp", 0, []) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'otherapp', 1) - self.assertOperationTypes(changes, 'otherapp', 0, ["CreateModel"]) - self.assertOperationAttributes(changes, 'otherapp', 0, 0, name="Book") - self.assertMigrationDependencies(changes, 'otherapp', 0, [("testapp", "auto_1")]) + self.assertNumberMigrations(changes, "otherapp", 1) + self.assertOperationTypes(changes, "otherapp", 0, ["CreateModel"]) + self.assertOperationAttributes(changes, "otherapp", 0, 0, name="Book") + self.assertMigrationDependencies( + changes, "otherapp", 0, [("testapp", "auto_1")] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'thirdapp', 1) - self.assertOperationTypes(changes, 'thirdapp', 0, ["CreateModel"]) - self.assertOperationAttributes(changes, 'thirdapp', 0, 0, name="Edition") - self.assertMigrationDependencies(changes, 'thirdapp', 0, [("otherapp", "auto_1")]) + self.assertNumberMigrations(changes, "thirdapp", 1) + self.assertOperationTypes(changes, "thirdapp", 0, ["CreateModel"]) + self.assertOperationAttributes(changes, "thirdapp", 0, 0, name="Edition") + self.assertMigrationDependencies( + changes, "thirdapp", 0, [("otherapp", "auto_1")] + ) def test_proxy_fk_dependency(self): """FK dependencies still work on proxy models.""" # Note that testapp (author) has no dependencies, # otherapp (book) depends on testapp (authorproxy) - changes = self.get_changes([], [self.author_empty, self.author_proxy_third, self.book_proxy_fk]) + changes = self.get_changes( + [], [self.author_empty, self.author_proxy_third, self.book_proxy_fk] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Author") - self.assertMigrationDependencies(changes, 'testapp', 0, []) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["CreateModel"]) + self.assertOperationAttributes(changes, "testapp", 0, 0, name="Author") + self.assertMigrationDependencies(changes, "testapp", 0, []) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'otherapp', 1) - self.assertOperationTypes(changes, 'otherapp', 0, ["CreateModel"]) - self.assertOperationAttributes(changes, 'otherapp', 0, 0, name="Book") - self.assertMigrationDependencies(changes, 'otherapp', 0, [("thirdapp", "auto_1")]) + self.assertNumberMigrations(changes, "otherapp", 1) + self.assertOperationTypes(changes, "otherapp", 0, ["CreateModel"]) + self.assertOperationAttributes(changes, "otherapp", 0, 0, name="Book") + self.assertMigrationDependencies( + changes, "otherapp", 0, [("thirdapp", "auto_1")] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'thirdapp', 1) - self.assertOperationTypes(changes, 'thirdapp', 0, ["CreateModel"]) - self.assertOperationAttributes(changes, 'thirdapp', 0, 0, name="AuthorProxy") - self.assertMigrationDependencies(changes, 'thirdapp', 0, [("testapp", "auto_1")]) + self.assertNumberMigrations(changes, "thirdapp", 1) + self.assertOperationTypes(changes, "thirdapp", 0, ["CreateModel"]) + self.assertOperationAttributes(changes, "thirdapp", 0, 0, name="AuthorProxy") + self.assertMigrationDependencies( + changes, "thirdapp", 0, [("testapp", "auto_1")] + ) def test_same_app_no_fk_dependency(self): """ @@ -1259,47 +2193,57 @@ class AutodetectorTests(TestCase): """ changes = self.get_changes([], [self.author_with_publisher, self.publisher]) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel", "CreateModel"]) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["CreateModel", "CreateModel"]) self.assertOperationAttributes(changes, "testapp", 0, 0, name="Publisher") self.assertOperationAttributes(changes, "testapp", 0, 1, name="Author") - self.assertMigrationDependencies(changes, 'testapp', 0, []) + self.assertMigrationDependencies(changes, "testapp", 0, []) def test_circular_fk_dependency(self): """ Having a circular ForeignKey dependency automatically resolves the situation into 2 migrations on one side and 1 on the other. """ - changes = self.get_changes([], [self.author_with_book, self.book, self.publisher_with_book]) + changes = self.get_changes( + [], [self.author_with_book, self.book, self.publisher_with_book] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel", "CreateModel"]) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["CreateModel", "CreateModel"]) self.assertOperationAttributes(changes, "testapp", 0, 0, name="Publisher") self.assertOperationAttributes(changes, "testapp", 0, 1, name="Author") - self.assertMigrationDependencies(changes, 'testapp', 0, [("otherapp", "auto_1")]) + self.assertMigrationDependencies( + changes, "testapp", 0, [("otherapp", "auto_1")] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'otherapp', 2) - self.assertOperationTypes(changes, 'otherapp', 0, ["CreateModel"]) - self.assertOperationTypes(changes, 'otherapp', 1, ["AddField"]) - self.assertMigrationDependencies(changes, 'otherapp', 0, []) - self.assertMigrationDependencies(changes, 'otherapp', 1, [("otherapp", "auto_1"), ("testapp", "auto_1")]) + self.assertNumberMigrations(changes, "otherapp", 2) + self.assertOperationTypes(changes, "otherapp", 0, ["CreateModel"]) + self.assertOperationTypes(changes, "otherapp", 1, ["AddField"]) + self.assertMigrationDependencies(changes, "otherapp", 0, []) + self.assertMigrationDependencies( + changes, "otherapp", 1, [("otherapp", "auto_1"), ("testapp", "auto_1")] + ) # both split migrations should be `initial` - self.assertTrue(changes['otherapp'][0].initial) - self.assertTrue(changes['otherapp'][1].initial) + self.assertTrue(changes["otherapp"][0].initial) + self.assertTrue(changes["otherapp"][1].initial) def test_same_app_circular_fk_dependency(self): """ A migration with a FK between two models of the same app does not have a dependency to itself. """ - changes = self.get_changes([], [self.author_with_publisher, self.publisher_with_author]) + changes = self.get_changes( + [], [self.author_with_publisher, self.publisher_with_author] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel", "CreateModel", "AddField"]) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes( + changes, "testapp", 0, ["CreateModel", "CreateModel", "AddField"] + ) self.assertOperationAttributes(changes, "testapp", 0, 0, name="Author") self.assertOperationAttributes(changes, "testapp", 0, 1, name="Publisher") self.assertOperationAttributes(changes, "testapp", 0, 2, name="publisher") - self.assertMigrationDependencies(changes, 'testapp', 0, []) + self.assertMigrationDependencies(changes, "testapp", 0, []) def test_same_app_circular_fk_dependency_with_unique_together_and_indexes(self): """ @@ -1309,43 +2253,60 @@ class AutodetectorTests(TestCase): """ changes = self.get_changes([], [self.knight, self.rabbit]) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'eggs', 1) + self.assertNumberMigrations(changes, "eggs", 1) self.assertOperationTypes( - changes, 'eggs', 0, ["CreateModel", "CreateModel", "AddIndex", "AlterUniqueTogether"] + changes, + "eggs", + 0, + ["CreateModel", "CreateModel", "AddIndex", "AlterUniqueTogether"], ) - self.assertNotIn("unique_together", changes['eggs'][0].operations[0].options) - self.assertNotIn("unique_together", changes['eggs'][0].operations[1].options) - self.assertMigrationDependencies(changes, 'eggs', 0, []) + self.assertNotIn("unique_together", changes["eggs"][0].operations[0].options) + self.assertNotIn("unique_together", changes["eggs"][0].operations[1].options) + self.assertMigrationDependencies(changes, "eggs", 0, []) def test_alter_db_table_add(self): """Tests detection for adding db_table in model's options.""" - changes = self.get_changes([self.author_empty], [self.author_with_db_table_options]) + changes = self.get_changes( + [self.author_empty], [self.author_with_db_table_options] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AlterModelTable"]) - self.assertOperationAttributes(changes, "testapp", 0, 0, name="author", table="author_one") + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["AlterModelTable"]) + self.assertOperationAttributes( + changes, "testapp", 0, 0, name="author", table="author_one" + ) def test_alter_db_table_change(self): """Tests detection for changing db_table in model's options'.""" - changes = self.get_changes([self.author_with_db_table_options], [self.author_with_new_db_table_options]) + changes = self.get_changes( + [self.author_with_db_table_options], [self.author_with_new_db_table_options] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AlterModelTable"]) - self.assertOperationAttributes(changes, "testapp", 0, 0, name="author", table="author_two") + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["AlterModelTable"]) + self.assertOperationAttributes( + changes, "testapp", 0, 0, name="author", table="author_two" + ) def test_alter_db_table_remove(self): """Tests detection for removing db_table in model's options.""" - changes = self.get_changes([self.author_with_db_table_options], [self.author_empty]) + changes = self.get_changes( + [self.author_with_db_table_options], [self.author_empty] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AlterModelTable"]) - self.assertOperationAttributes(changes, "testapp", 0, 0, name="author", table=None) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["AlterModelTable"]) + self.assertOperationAttributes( + changes, "testapp", 0, 0, name="author", table=None + ) def test_alter_db_table_no_changes(self): """ Alter_db_table doesn't generate a migration if no changes have been made. """ - changes = self.get_changes([self.author_with_db_table_options], [self.author_with_db_table_options]) + changes = self.get_changes( + [self.author_with_db_table_options], [self.author_with_db_table_options] + ) # Right number of migrations? self.assertEqual(len(changes), 0) @@ -1360,9 +2321,11 @@ class AutodetectorTests(TestCase): MigrationQuestioner({"ask_rename_model": True}), ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["RenameModel"]) - self.assertOperationAttributes(changes, "testapp", 0, 0, old_name="Author", new_name="NewAuthor") + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["RenameModel"]) + self.assertOperationAttributes( + changes, "testapp", 0, 0, old_name="Author", new_name="NewAuthor" + ) def test_alter_db_table_with_model_change(self): """ @@ -1375,23 +2338,41 @@ class AutodetectorTests(TestCase): MigrationQuestioner({"ask_rename_model": True}), ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["RenameModel", "AlterModelTable"]) - self.assertOperationAttributes(changes, "testapp", 0, 0, old_name="Author", new_name="NewAuthor") - self.assertOperationAttributes(changes, "testapp", 0, 1, name="newauthor", table="author_three") + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes( + changes, "testapp", 0, ["RenameModel", "AlterModelTable"] + ) + self.assertOperationAttributes( + changes, "testapp", 0, 0, old_name="Author", new_name="NewAuthor" + ) + self.assertOperationAttributes( + changes, "testapp", 0, 1, name="newauthor", table="author_three" + ) def test_identical_regex_doesnt_alter(self): from_state = ModelState( - "testapp", "model", [("id", models.AutoField(primary_key=True, validators=[ - RegexValidator( - re.compile('^[-a-zA-Z0-9_]+\\Z'), - 'Enter a valid “slug” consisting of letters, numbers, underscores or hyphens.', - 'invalid' + "testapp", + "model", + [ + ( + "id", + models.AutoField( + primary_key=True, + validators=[ + RegexValidator( + re.compile("^[-a-zA-Z0-9_]+\\Z"), + "Enter a valid “slug” consisting of letters, numbers, underscores or hyphens.", + "invalid", + ) + ], + ), ) - ]))] + ], ) to_state = ModelState( - "testapp", "model", [("id", models.AutoField(primary_key=True, validators=[validate_slug]))] + "testapp", + "model", + [("id", models.AutoField(primary_key=True, validators=[validate_slug]))], ) changes = self.get_changes([from_state], [to_state]) # Right number/type of migrations? @@ -1399,16 +2380,28 @@ class AutodetectorTests(TestCase): def test_different_regex_does_alter(self): from_state = ModelState( - "testapp", "model", [("id", models.AutoField(primary_key=True, validators=[ - RegexValidator( - re.compile('^[a-z]+\\Z', 32), - 'Enter a valid “slug” consisting of letters, numbers, underscores or hyphens.', - 'invalid' + "testapp", + "model", + [ + ( + "id", + models.AutoField( + primary_key=True, + validators=[ + RegexValidator( + re.compile("^[a-z]+\\Z", 32), + "Enter a valid “slug” consisting of letters, numbers, underscores or hyphens.", + "invalid", + ) + ], + ), ) - ]))] + ], ) to_state = ModelState( - "testapp", "model", [("id", models.AutoField(primary_key=True, validators=[validate_slug]))] + "testapp", + "model", + [("id", models.AutoField(primary_key=True, validators=[validate_slug]))], ) changes = self.get_changes([from_state], [to_state]) self.assertNumberMigrations(changes, "testapp", 1) @@ -1420,38 +2413,60 @@ class AutodetectorTests(TestCase): """ # Explicitly testing for not specified, since this is the case after # a CreateModel operation w/o any definition on the original model - model_state_not_specified = ModelState("a", "model", [("id", models.AutoField(primary_key=True))]) + model_state_not_specified = ModelState( + "a", "model", [("id", models.AutoField(primary_key=True))] + ) # Explicitly testing for None, since this was the issue in #23452 after # an AlterFooTogether operation with e.g. () as value - model_state_none = ModelState("a", "model", [ - ("id", models.AutoField(primary_key=True)) - ], { - "index_together": None, - "unique_together": None, - }) + model_state_none = ModelState( + "a", + "model", + [("id", models.AutoField(primary_key=True))], + { + "index_together": None, + "unique_together": None, + }, + ) # Explicitly testing for the empty set, since we now always have sets. # During removal (('col1', 'col2'),) --> () this becomes set([]) - model_state_empty = ModelState("a", "model", [ - ("id", models.AutoField(primary_key=True)) - ], { - "index_together": set(), - "unique_together": set(), - }) + model_state_empty = ModelState( + "a", + "model", + [("id", models.AutoField(primary_key=True))], + { + "index_together": set(), + "unique_together": set(), + }, + ) def test(from_state, to_state, msg): changes = self.get_changes([from_state], [to_state]) if changes: - ops = ', '.join(o.__class__.__name__ for o in changes['a'][0].operations) - self.fail('Created operation(s) %s from %s' % (ops, msg)) + ops = ", ".join( + o.__class__.__name__ for o in changes["a"][0].operations + ) + self.fail("Created operation(s) %s from %s" % (ops, msg)) tests = ( - (model_state_not_specified, model_state_not_specified, '"not specified" to "not specified"'), + ( + model_state_not_specified, + model_state_not_specified, + '"not specified" to "not specified"', + ), (model_state_not_specified, model_state_none, '"not specified" to "None"'), - (model_state_not_specified, model_state_empty, '"not specified" to "empty"'), + ( + model_state_not_specified, + model_state_empty, + '"not specified" to "empty"', + ), (model_state_none, model_state_not_specified, '"None" to "not specified"'), (model_state_none, model_state_none, '"None" to "None"'), (model_state_none, model_state_empty, '"None" to "empty"'), - (model_state_empty, model_state_not_specified, '"empty" to "not specified"'), + ( + model_state_empty, + model_state_not_specified, + '"empty" to "not specified"', + ), (model_state_empty, model_state_none, '"empty" to "None"'), (model_state_empty, model_state_empty, '"empty" to "empty"'), ) @@ -1461,114 +2476,202 @@ class AutodetectorTests(TestCase): def test_create_model_with_indexes(self): """Test creation of new model with indexes already defined.""" - author = ModelState('otherapp', 'Author', [ - ('id', models.AutoField(primary_key=True)), - ('name', models.CharField(max_length=200)), - ], {'indexes': [models.Index(fields=['name'], name='create_model_with_indexes_idx')]}) + author = ModelState( + "otherapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200)), + ], + { + "indexes": [ + models.Index(fields=["name"], name="create_model_with_indexes_idx") + ] + }, + ) changes = self.get_changes([], [author]) - added_index = models.Index(fields=['name'], name='create_model_with_indexes_idx') + added_index = models.Index( + fields=["name"], name="create_model_with_indexes_idx" + ) # Right number of migrations? - self.assertEqual(len(changes['otherapp']), 1) + self.assertEqual(len(changes["otherapp"]), 1) # Right number of actions? - migration = changes['otherapp'][0] + migration = changes["otherapp"][0] self.assertEqual(len(migration.operations), 2) # Right actions order? - self.assertOperationTypes(changes, 'otherapp', 0, ['CreateModel', 'AddIndex']) - self.assertOperationAttributes(changes, 'otherapp', 0, 0, name='Author') - self.assertOperationAttributes(changes, 'otherapp', 0, 1, model_name='author', index=added_index) + self.assertOperationTypes(changes, "otherapp", 0, ["CreateModel", "AddIndex"]) + self.assertOperationAttributes(changes, "otherapp", 0, 0, name="Author") + self.assertOperationAttributes( + changes, "otherapp", 0, 1, model_name="author", index=added_index + ) def test_add_indexes(self): """Test change detection of new indexes.""" - changes = self.get_changes([self.author_empty, self.book], [self.author_empty, self.book_indexes]) - self.assertNumberMigrations(changes, 'otherapp', 1) - self.assertOperationTypes(changes, 'otherapp', 0, ['AddIndex']) - added_index = models.Index(fields=['author', 'title'], name='book_title_author_idx') - self.assertOperationAttributes(changes, 'otherapp', 0, 0, model_name='book', index=added_index) + changes = self.get_changes( + [self.author_empty, self.book], [self.author_empty, self.book_indexes] + ) + self.assertNumberMigrations(changes, "otherapp", 1) + self.assertOperationTypes(changes, "otherapp", 0, ["AddIndex"]) + added_index = models.Index( + fields=["author", "title"], name="book_title_author_idx" + ) + self.assertOperationAttributes( + changes, "otherapp", 0, 0, model_name="book", index=added_index + ) def test_remove_indexes(self): """Test change detection of removed indexes.""" - changes = self.get_changes([self.author_empty, self.book_indexes], [self.author_empty, self.book]) + changes = self.get_changes( + [self.author_empty, self.book_indexes], [self.author_empty, self.book] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'otherapp', 1) - self.assertOperationTypes(changes, 'otherapp', 0, ['RemoveIndex']) - self.assertOperationAttributes(changes, 'otherapp', 0, 0, model_name='book', name='book_title_author_idx') + self.assertNumberMigrations(changes, "otherapp", 1) + self.assertOperationTypes(changes, "otherapp", 0, ["RemoveIndex"]) + self.assertOperationAttributes( + changes, "otherapp", 0, 0, model_name="book", name="book_title_author_idx" + ) def test_order_fields_indexes(self): """Test change detection of reordering of fields in indexes.""" changes = self.get_changes( - [self.author_empty, self.book_indexes], [self.author_empty, self.book_unordered_indexes] + [self.author_empty, self.book_indexes], + [self.author_empty, self.book_unordered_indexes], + ) + self.assertNumberMigrations(changes, "otherapp", 1) + self.assertOperationTypes(changes, "otherapp", 0, ["RemoveIndex", "AddIndex"]) + self.assertOperationAttributes( + changes, "otherapp", 0, 0, model_name="book", name="book_title_author_idx" + ) + added_index = models.Index( + fields=["title", "author"], name="book_author_title_idx" + ) + self.assertOperationAttributes( + changes, "otherapp", 0, 1, model_name="book", index=added_index ) - self.assertNumberMigrations(changes, 'otherapp', 1) - self.assertOperationTypes(changes, 'otherapp', 0, ['RemoveIndex', 'AddIndex']) - self.assertOperationAttributes(changes, 'otherapp', 0, 0, model_name='book', name='book_title_author_idx') - added_index = models.Index(fields=['title', 'author'], name='book_author_title_idx') - self.assertOperationAttributes(changes, 'otherapp', 0, 1, model_name='book', index=added_index) def test_create_model_with_check_constraint(self): """Test creation of new model with constraints already defined.""" - author = ModelState('otherapp', 'Author', [ - ('id', models.AutoField(primary_key=True)), - ('name', models.CharField(max_length=200)), - ], {'constraints': [models.CheckConstraint(check=models.Q(name__contains='Bob'), name='name_contains_bob')]}) + author = ModelState( + "otherapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200)), + ], + { + "constraints": [ + models.CheckConstraint( + check=models.Q(name__contains="Bob"), name="name_contains_bob" + ) + ] + }, + ) changes = self.get_changes([], [author]) - added_constraint = models.CheckConstraint(check=models.Q(name__contains='Bob'), name='name_contains_bob') + added_constraint = models.CheckConstraint( + check=models.Q(name__contains="Bob"), name="name_contains_bob" + ) # Right number of migrations? - self.assertEqual(len(changes['otherapp']), 1) + self.assertEqual(len(changes["otherapp"]), 1) # Right number of actions? - migration = changes['otherapp'][0] + migration = changes["otherapp"][0] self.assertEqual(len(migration.operations), 2) # Right actions order? - self.assertOperationTypes(changes, 'otherapp', 0, ['CreateModel', 'AddConstraint']) - self.assertOperationAttributes(changes, 'otherapp', 0, 0, name='Author') - self.assertOperationAttributes(changes, 'otherapp', 0, 1, model_name='author', constraint=added_constraint) + self.assertOperationTypes( + changes, "otherapp", 0, ["CreateModel", "AddConstraint"] + ) + self.assertOperationAttributes(changes, "otherapp", 0, 0, name="Author") + self.assertOperationAttributes( + changes, "otherapp", 0, 1, model_name="author", constraint=added_constraint + ) def test_add_constraints(self): """Test change detection of new constraints.""" - changes = self.get_changes([self.author_name], [self.author_name_check_constraint]) - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ['AddConstraint']) - added_constraint = models.CheckConstraint(check=models.Q(name__contains='Bob'), name='name_contains_bob') - self.assertOperationAttributes(changes, 'testapp', 0, 0, model_name='author', constraint=added_constraint) + changes = self.get_changes( + [self.author_name], [self.author_name_check_constraint] + ) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["AddConstraint"]) + added_constraint = models.CheckConstraint( + check=models.Q(name__contains="Bob"), name="name_contains_bob" + ) + self.assertOperationAttributes( + changes, "testapp", 0, 0, model_name="author", constraint=added_constraint + ) def test_remove_constraints(self): """Test change detection of removed constraints.""" - changes = self.get_changes([self.author_name_check_constraint], [self.author_name]) + changes = self.get_changes( + [self.author_name_check_constraint], [self.author_name] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ['RemoveConstraint']) - self.assertOperationAttributes(changes, 'testapp', 0, 0, model_name='author', name='name_contains_bob') + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["RemoveConstraint"]) + self.assertOperationAttributes( + changes, "testapp", 0, 0, model_name="author", name="name_contains_bob" + ) def test_add_foo_together(self): """Tests index/unique_together detection.""" - changes = self.get_changes([self.author_empty, self.book], [self.author_empty, self.book_foo_together]) + changes = self.get_changes( + [self.author_empty, self.book], [self.author_empty, self.book_foo_together] + ) # Right number/type of migrations? self.assertNumberMigrations(changes, "otherapp", 1) - self.assertOperationTypes(changes, "otherapp", 0, ["AlterUniqueTogether", "AlterIndexTogether"]) - self.assertOperationAttributes(changes, "otherapp", 0, 0, name="book", unique_together={("author", "title")}) - self.assertOperationAttributes(changes, "otherapp", 0, 1, name="book", index_together={("author", "title")}) + self.assertOperationTypes( + changes, "otherapp", 0, ["AlterUniqueTogether", "AlterIndexTogether"] + ) + self.assertOperationAttributes( + changes, + "otherapp", + 0, + 0, + name="book", + unique_together={("author", "title")}, + ) + self.assertOperationAttributes( + changes, "otherapp", 0, 1, name="book", index_together={("author", "title")} + ) def test_remove_foo_together(self): """Tests index/unique_together detection.""" - changes = self.get_changes([self.author_empty, self.book_foo_together], [self.author_empty, self.book]) + changes = self.get_changes( + [self.author_empty, self.book_foo_together], [self.author_empty, self.book] + ) # Right number/type of migrations? self.assertNumberMigrations(changes, "otherapp", 1) - self.assertOperationTypes(changes, "otherapp", 0, ["AlterUniqueTogether", "AlterIndexTogether"]) - self.assertOperationAttributes(changes, "otherapp", 0, 0, name="book", unique_together=set()) - self.assertOperationAttributes(changes, "otherapp", 0, 1, name="book", index_together=set()) + self.assertOperationTypes( + changes, "otherapp", 0, ["AlterUniqueTogether", "AlterIndexTogether"] + ) + self.assertOperationAttributes( + changes, "otherapp", 0, 0, name="book", unique_together=set() + ) + self.assertOperationAttributes( + changes, "otherapp", 0, 1, name="book", index_together=set() + ) def test_foo_together_remove_fk(self): """Tests unique_together and field removal detection & ordering""" changes = self.get_changes( - [self.author_empty, self.book_foo_together], [self.author_empty, self.book_with_no_author] + [self.author_empty, self.book_foo_together], + [self.author_empty, self.book_with_no_author], ) # Right number/type of migrations? self.assertNumberMigrations(changes, "otherapp", 1) - self.assertOperationTypes(changes, "otherapp", 0, [ - "AlterUniqueTogether", "AlterIndexTogether", "RemoveField" - ]) - self.assertOperationAttributes(changes, "otherapp", 0, 0, name="book", unique_together=set()) - self.assertOperationAttributes(changes, "otherapp", 0, 1, name="book", index_together=set()) - self.assertOperationAttributes(changes, "otherapp", 0, 2, model_name="book", name="author") + self.assertOperationTypes( + changes, + "otherapp", + 0, + ["AlterUniqueTogether", "AlterIndexTogether", "RemoveField"], + ) + self.assertOperationAttributes( + changes, "otherapp", 0, 0, name="book", unique_together=set() + ) + self.assertOperationAttributes( + changes, "otherapp", 0, 1, name="book", index_together=set() + ) + self.assertOperationAttributes( + changes, "otherapp", 0, 2, model_name="book", name="author" + ) def test_foo_together_no_changes(self): """ @@ -1576,7 +2679,8 @@ class AutodetectorTests(TestCase): changes have been made. """ changes = self.get_changes( - [self.author_empty, self.book_foo_together], [self.author_empty, self.book_foo_together] + [self.author_empty, self.book_foo_together], + [self.author_empty, self.book_foo_together], ) # Right number of migrations? self.assertEqual(len(changes), 0) @@ -1586,57 +2690,106 @@ class AutodetectorTests(TestCase): index/unique_together also triggers on ordering changes. """ changes = self.get_changes( - [self.author_empty, self.book_foo_together], [self.author_empty, self.book_foo_together_2] + [self.author_empty, self.book_foo_together], + [self.author_empty, self.book_foo_together_2], ) # Right number/type of migrations? self.assertNumberMigrations(changes, "otherapp", 1) - self.assertOperationTypes(changes, 'otherapp', 0, [ - 'AlterUniqueTogether', - 'AlterIndexTogether', - ]) + self.assertOperationTypes( + changes, + "otherapp", + 0, + [ + "AlterUniqueTogether", + "AlterIndexTogether", + ], + ) self.assertOperationAttributes( - changes, 'otherapp', 0, 0, name='book', - unique_together={('title', 'author')}, + changes, + "otherapp", + 0, + 0, + name="book", + unique_together={("title", "author")}, ) self.assertOperationAttributes( - changes, 'otherapp', 0, 1, name='book', - index_together={('title', 'author')}, + changes, + "otherapp", + 0, + 1, + name="book", + index_together={("title", "author")}, ) def test_add_field_and_foo_together(self): """ Added fields will be created before using them in index/unique_together. """ - changes = self.get_changes([self.author_empty, self.book], [self.author_empty, self.book_foo_together_3]) + changes = self.get_changes( + [self.author_empty, self.book], + [self.author_empty, self.book_foo_together_3], + ) # Right number/type of migrations? self.assertNumberMigrations(changes, "otherapp", 1) - self.assertOperationTypes(changes, "otherapp", 0, ["AddField", "AlterUniqueTogether", "AlterIndexTogether"]) - self.assertOperationAttributes(changes, "otherapp", 0, 1, name="book", unique_together={("title", "newfield")}) - self.assertOperationAttributes(changes, "otherapp", 0, 2, name="book", index_together={("title", "newfield")}) + self.assertOperationTypes( + changes, + "otherapp", + 0, + ["AddField", "AlterUniqueTogether", "AlterIndexTogether"], + ) + self.assertOperationAttributes( + changes, + "otherapp", + 0, + 1, + name="book", + unique_together={("title", "newfield")}, + ) + self.assertOperationAttributes( + changes, + "otherapp", + 0, + 2, + name="book", + index_together={("title", "newfield")}, + ) def test_create_model_and_unique_together(self): - author = ModelState("otherapp", "Author", [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=200)), - ]) - book_with_author = ModelState("otherapp", "Book", [ - ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("otherapp.Author", models.CASCADE)), - ("title", models.CharField(max_length=200)), - ], { - "index_together": {("title", "author")}, - "unique_together": {("title", "author")}, - }) - changes = self.get_changes([self.book_with_no_author], [author, book_with_author]) + author = ModelState( + "otherapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200)), + ], + ) + book_with_author = ModelState( + "otherapp", + "Book", + [ + ("id", models.AutoField(primary_key=True)), + ("author", models.ForeignKey("otherapp.Author", models.CASCADE)), + ("title", models.CharField(max_length=200)), + ], + { + "index_together": {("title", "author")}, + "unique_together": {("title", "author")}, + }, + ) + changes = self.get_changes( + [self.book_with_no_author], [author, book_with_author] + ) # Right number of migrations? - self.assertEqual(len(changes['otherapp']), 1) + self.assertEqual(len(changes["otherapp"]), 1) # Right number of actions? - migration = changes['otherapp'][0] + migration = changes["otherapp"][0] self.assertEqual(len(migration.operations), 4) # Right actions order? self.assertOperationTypes( - changes, 'otherapp', 0, - ['CreateModel', 'AddField', 'AlterUniqueTogether', 'AlterIndexTogether'] + changes, + "otherapp", + 0, + ["CreateModel", "AddField", "AlterUniqueTogether", "AlterIndexTogether"], ) def test_remove_field_and_foo_together(self): @@ -1644,95 +2797,173 @@ class AutodetectorTests(TestCase): Removed fields will be removed after updating index/unique_together. """ changes = self.get_changes( - [self.author_empty, self.book_foo_together_3], [self.author_empty, self.book_foo_together] + [self.author_empty, self.book_foo_together_3], + [self.author_empty, self.book_foo_together], ) # Right number/type of migrations? self.assertNumberMigrations(changes, "otherapp", 1) - self.assertOperationTypes(changes, 'otherapp', 0, [ - 'AlterUniqueTogether', - 'AlterIndexTogether', - 'RemoveField', - ]) + self.assertOperationTypes( + changes, + "otherapp", + 0, + [ + "AlterUniqueTogether", + "AlterIndexTogether", + "RemoveField", + ], + ) self.assertOperationAttributes( - changes, 'otherapp', 0, 0, name='book', - unique_together={('author', 'title')}, + changes, + "otherapp", + 0, + 0, + name="book", + unique_together={("author", "title")}, ) self.assertOperationAttributes( - changes, 'otherapp', 0, 1, name='book', - index_together={('author', 'title')}, + changes, + "otherapp", + 0, + 1, + name="book", + index_together={("author", "title")}, ) self.assertOperationAttributes( - changes, 'otherapp', 0, 2, model_name='book', name='newfield', + changes, + "otherapp", + 0, + 2, + model_name="book", + name="newfield", ) def test_alter_field_and_foo_together(self): """Fields are altered after deleting some index/unique_together.""" - initial_author = ModelState('testapp', 'Author', [ - ('id', models.AutoField(primary_key=True)), - ('name', models.CharField(max_length=200)), - ('age', models.IntegerField(db_index=True)), - ], { - 'unique_together': {('name',)}, - }) - author_reversed_constraints = ModelState('testapp', 'Author', [ - ('id', models.AutoField(primary_key=True)), - ('name', models.CharField(max_length=200, unique=True)), - ('age', models.IntegerField()), - ], { - 'index_together': {('age',)}, - }) + initial_author = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200)), + ("age", models.IntegerField(db_index=True)), + ], + { + "unique_together": {("name",)}, + }, + ) + author_reversed_constraints = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200, unique=True)), + ("age", models.IntegerField()), + ], + { + "index_together": {("age",)}, + }, + ) changes = self.get_changes([initial_author], [author_reversed_constraints]) - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, [ - 'AlterUniqueTogether', - 'AlterField', - 'AlterField', - 'AlterIndexTogether', - ]) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes( + changes, + "testapp", + 0, + [ + "AlterUniqueTogether", + "AlterField", + "AlterField", + "AlterIndexTogether", + ], + ) self.assertOperationAttributes( - changes, 'testapp', 0, 0, name='author', unique_together=set(), + changes, + "testapp", + 0, + 0, + name="author", + unique_together=set(), ) self.assertOperationAttributes( - changes, 'testapp', 0, 1, model_name='author', name='age', + changes, + "testapp", + 0, + 1, + model_name="author", + name="age", ) self.assertOperationAttributes( - changes, 'testapp', 0, 2, model_name='author', name='name', + changes, + "testapp", + 0, + 2, + model_name="author", + name="name", ) self.assertOperationAttributes( - changes, 'testapp', 0, 3, name='author', index_together={('age',)}, + changes, + "testapp", + 0, + 3, + name="author", + index_together={("age",)}, ) def test_partly_alter_foo_together(self): - initial_author = ModelState('testapp', 'Author', [ - ('id', models.AutoField(primary_key=True)), - ('name', models.CharField(max_length=200)), - ('age', models.IntegerField()), - ], { - 'unique_together': {('name',), ('age',)}, - 'index_together': {('name',)}, - }) - author_reversed_constraints = ModelState('testapp', 'Author', [ - ('id', models.AutoField(primary_key=True)), - ('name', models.CharField(max_length=200)), - ('age', models.IntegerField()), - ], { - 'unique_together': {('age',)}, - 'index_together': {('name',), ('age',)}, - }) + initial_author = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200)), + ("age", models.IntegerField()), + ], + { + "unique_together": {("name",), ("age",)}, + "index_together": {("name",)}, + }, + ) + author_reversed_constraints = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200)), + ("age", models.IntegerField()), + ], + { + "unique_together": {("age",)}, + "index_together": {("name",), ("age",)}, + }, + ) changes = self.get_changes([initial_author], [author_reversed_constraints]) - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, [ - 'AlterUniqueTogether', - 'AlterIndexTogether', - ]) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes( + changes, + "testapp", + 0, + [ + "AlterUniqueTogether", + "AlterIndexTogether", + ], + ) self.assertOperationAttributes( - changes, 'testapp', 0, 0, name='author', unique_together={('age',)}, + changes, + "testapp", + 0, + 0, + name="author", + unique_together={("age",)}, ) self.assertOperationAttributes( - changes, 'testapp', 0, 1, name='author', - index_together={('name',), ('age',)}, + changes, + "testapp", + 0, + 1, + name="author", + index_together={("name",), ("age",)}, ) def test_rename_field_and_foo_together(self): @@ -1744,62 +2975,89 @@ class AutodetectorTests(TestCase): ) # Right number/type of migrations? self.assertNumberMigrations(changes, "otherapp", 1) - self.assertOperationTypes(changes, 'otherapp', 0, [ - 'RenameField', - 'AlterUniqueTogether', - 'AlterIndexTogether', - ]) + self.assertOperationTypes( + changes, + "otherapp", + 0, + [ + "RenameField", + "AlterUniqueTogether", + "AlterIndexTogether", + ], + ) self.assertOperationAttributes( - changes, 'otherapp', 0, 1, name='book', - unique_together={('title', 'newfield2')}, + changes, + "otherapp", + 0, + 1, + name="book", + unique_together={("title", "newfield2")}, ) self.assertOperationAttributes( - changes, 'otherapp', 0, 2, name='book', - index_together={('title', 'newfield2')}, + changes, + "otherapp", + 0, + 2, + name="book", + index_together={("title", "newfield2")}, ) def test_proxy(self): """The autodetector correctly deals with proxy models.""" # First, we test adding a proxy model - changes = self.get_changes([self.author_empty], [self.author_empty, self.author_proxy]) + changes = self.get_changes( + [self.author_empty], [self.author_empty, self.author_proxy] + ) # Right number/type of migrations? self.assertNumberMigrations(changes, "testapp", 1) self.assertOperationTypes(changes, "testapp", 0, ["CreateModel"]) self.assertOperationAttributes( - changes, "testapp", 0, 0, name="AuthorProxy", options={"proxy": True, "indexes": [], "constraints": []} + changes, + "testapp", + 0, + 0, + name="AuthorProxy", + options={"proxy": True, "indexes": [], "constraints": []}, ) # Now, we test turning a proxy model into a non-proxy model # It should delete the proxy then make the real one changes = self.get_changes( - [self.author_empty, self.author_proxy], [self.author_empty, self.author_proxy_notproxy] + [self.author_empty, self.author_proxy], + [self.author_empty, self.author_proxy_notproxy], ) # Right number/type of migrations? self.assertNumberMigrations(changes, "testapp", 1) self.assertOperationTypes(changes, "testapp", 0, ["DeleteModel", "CreateModel"]) self.assertOperationAttributes(changes, "testapp", 0, 0, name="AuthorProxy") - self.assertOperationAttributes(changes, "testapp", 0, 1, name="AuthorProxy", options={}) + self.assertOperationAttributes( + changes, "testapp", 0, 1, name="AuthorProxy", options={} + ) def test_proxy_non_model_parent(self): class Mixin: pass author_proxy_non_model_parent = ModelState( - 'testapp', - 'AuthorProxy', + "testapp", + "AuthorProxy", [], - {'proxy': True}, - (Mixin, 'testapp.author'), + {"proxy": True}, + (Mixin, "testapp.author"), ) changes = self.get_changes( [self.author_empty], [self.author_empty, author_proxy_non_model_parent], ) - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ['CreateModel']) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["CreateModel"]) self.assertOperationAttributes( - changes, 'testapp', 0, 0, name='AuthorProxy', - options={'proxy': True, 'indexes': [], 'constraints': []}, - bases=(Mixin, 'testapp.author'), + changes, + "testapp", + 0, + 0, + name="AuthorProxy", + options={"proxy": True, "indexes": [], "constraints": []}, + bases=(Mixin, "testapp.author"), ) def test_proxy_custom_pk(self): @@ -1808,18 +3066,22 @@ class AutodetectorTests(TestCase): models. """ # First, we test the default pk field name - changes = self.get_changes([], [self.author_empty, self.author_proxy_third, self.book_proxy_fk]) + changes = self.get_changes( + [], [self.author_empty, self.author_proxy_third, self.book_proxy_fk] + ) # The model the FK is pointing from and to. self.assertEqual( - changes['otherapp'][0].operations[0].fields[2][1].remote_field.model, - 'thirdapp.AuthorProxy', + changes["otherapp"][0].operations[0].fields[2][1].remote_field.model, + "thirdapp.AuthorProxy", ) # Now, we test the custom pk field name - changes = self.get_changes([], [self.author_custom_pk, self.author_proxy_third, self.book_proxy_fk]) + changes = self.get_changes( + [], [self.author_custom_pk, self.author_proxy_third, self.book_proxy_fk] + ) # The model the FK is pointing from and to. self.assertEqual( - changes['otherapp'][0].operations[0].fields[2][1].remote_field.model, - 'thirdapp.AuthorProxy', + changes["otherapp"][0].operations[0].fields[2][1].remote_field.model, + "thirdapp.AuthorProxy", ) def test_proxy_to_mti_with_fk_to_proxy(self): @@ -1828,12 +3090,12 @@ class AutodetectorTests(TestCase): [self.author_empty, self.author_proxy_third, self.book_proxy_fk], ) changes = self.get_changes([], to_state) - fk_field = changes['otherapp'][0].operations[0].fields[2][1] + fk_field = changes["otherapp"][0].operations[0].fields[2][1] self.assertEqual( to_state.get_concrete_model_key(fk_field.remote_field.model), - ('testapp', 'author'), + ("testapp", "author"), ) - self.assertEqual(fk_field.remote_field.model, 'thirdapp.AuthorProxy') + self.assertEqual(fk_field.remote_field.model, "thirdapp.AuthorProxy") # Change AuthorProxy to use MTI. from_state = to_state.clone() @@ -1842,98 +3104,120 @@ class AutodetectorTests(TestCase): ) changes = self.get_changes(from_state, to_state) # Right number/type of migrations for the AuthorProxy model? - self.assertNumberMigrations(changes, 'thirdapp', 1) - self.assertOperationTypes(changes, 'thirdapp', 0, ['DeleteModel', 'CreateModel']) + self.assertNumberMigrations(changes, "thirdapp", 1) + self.assertOperationTypes( + changes, "thirdapp", 0, ["DeleteModel", "CreateModel"] + ) # Right number/type of migrations for the Book model with a FK to # AuthorProxy? - self.assertNumberMigrations(changes, 'otherapp', 1) - self.assertOperationTypes(changes, 'otherapp', 0, ['AlterField']) + self.assertNumberMigrations(changes, "otherapp", 1) + self.assertOperationTypes(changes, "otherapp", 0, ["AlterField"]) # otherapp should depend on thirdapp. - self.assertMigrationDependencies(changes, 'otherapp', 0, [('thirdapp', 'auto_1')]) + self.assertMigrationDependencies( + changes, "otherapp", 0, [("thirdapp", "auto_1")] + ) # Now, test the pk table and field name. - fk_field = changes['otherapp'][0].operations[0].field + fk_field = changes["otherapp"][0].operations[0].field self.assertEqual( to_state.get_concrete_model_key(fk_field.remote_field.model), - ('thirdapp', 'authorproxy'), + ("thirdapp", "authorproxy"), ) - self.assertEqual(fk_field.remote_field.model, 'thirdapp.AuthorProxy') + self.assertEqual(fk_field.remote_field.model, "thirdapp.AuthorProxy") def test_proxy_to_mti_with_fk_to_proxy_proxy(self): # First, test the pk table and field name. - to_state = self.make_project_state([ - self.author_empty, - self.author_proxy, - self.author_proxy_proxy, - self.book_proxy_proxy_fk, - ]) + to_state = self.make_project_state( + [ + self.author_empty, + self.author_proxy, + self.author_proxy_proxy, + self.book_proxy_proxy_fk, + ] + ) changes = self.get_changes([], to_state) - fk_field = changes['otherapp'][0].operations[0].fields[1][1] + fk_field = changes["otherapp"][0].operations[0].fields[1][1] self.assertEqual( to_state.get_concrete_model_key(fk_field.remote_field.model), - ('testapp', 'author'), + ("testapp", "author"), ) - self.assertEqual(fk_field.remote_field.model, 'testapp.AAuthorProxyProxy') + self.assertEqual(fk_field.remote_field.model, "testapp.AAuthorProxyProxy") # Change AuthorProxy to use MTI. FK still points to AAuthorProxyProxy, # a proxy of AuthorProxy. from_state = to_state.clone() - to_state = self.make_project_state([ - self.author_empty, - self.author_proxy_notproxy, - self.author_proxy_proxy, - self.book_proxy_proxy_fk, - ]) + to_state = self.make_project_state( + [ + self.author_empty, + self.author_proxy_notproxy, + self.author_proxy_proxy, + self.book_proxy_proxy_fk, + ] + ) changes = self.get_changes(from_state, to_state) # Right number/type of migrations for the AuthorProxy model? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ['DeleteModel', 'CreateModel']) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["DeleteModel", "CreateModel"]) # Right number/type of migrations for the Book model with a FK to # AAuthorProxyProxy? - self.assertNumberMigrations(changes, 'otherapp', 1) - self.assertOperationTypes(changes, 'otherapp', 0, ['AlterField']) + self.assertNumberMigrations(changes, "otherapp", 1) + self.assertOperationTypes(changes, "otherapp", 0, ["AlterField"]) # otherapp should depend on testapp. - self.assertMigrationDependencies(changes, 'otherapp', 0, [('testapp', 'auto_1')]) + self.assertMigrationDependencies( + changes, "otherapp", 0, [("testapp", "auto_1")] + ) # Now, test the pk table and field name. - fk_field = changes['otherapp'][0].operations[0].field + fk_field = changes["otherapp"][0].operations[0].field self.assertEqual( to_state.get_concrete_model_key(fk_field.remote_field.model), - ('testapp', 'authorproxy'), + ("testapp", "authorproxy"), ) - self.assertEqual(fk_field.remote_field.model, 'testapp.AAuthorProxyProxy') + self.assertEqual(fk_field.remote_field.model, "testapp.AAuthorProxyProxy") def test_unmanaged_create(self): """The autodetector correctly deals with managed models.""" # First, we test adding an unmanaged model - changes = self.get_changes([self.author_empty], [self.author_empty, self.author_unmanaged]) + changes = self.get_changes( + [self.author_empty], [self.author_empty, self.author_unmanaged] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name="AuthorUnmanaged", options={"managed": False}) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["CreateModel"]) + self.assertOperationAttributes( + changes, "testapp", 0, 0, name="AuthorUnmanaged", options={"managed": False} + ) def test_unmanaged_delete(self): - changes = self.get_changes([self.author_empty, self.author_unmanaged], [self.author_empty]) - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ['DeleteModel']) + changes = self.get_changes( + [self.author_empty, self.author_unmanaged], [self.author_empty] + ) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["DeleteModel"]) def test_unmanaged_to_managed(self): # Now, we test turning an unmanaged model into a managed model changes = self.get_changes( - [self.author_empty, self.author_unmanaged], [self.author_empty, self.author_unmanaged_managed] + [self.author_empty, self.author_unmanaged], + [self.author_empty, self.author_unmanaged_managed], ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AlterModelOptions"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name="authorunmanaged", options={}) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["AlterModelOptions"]) + self.assertOperationAttributes( + changes, "testapp", 0, 0, name="authorunmanaged", options={} + ) def test_managed_to_unmanaged(self): # Now, we turn managed to unmanaged. changes = self.get_changes( - [self.author_empty, self.author_unmanaged_managed], [self.author_empty, self.author_unmanaged] + [self.author_empty, self.author_unmanaged_managed], + [self.author_empty, self.author_unmanaged], ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) + self.assertNumberMigrations(changes, "testapp", 1) self.assertOperationTypes(changes, "testapp", 0, ["AlterModelOptions"]) - self.assertOperationAttributes(changes, "testapp", 0, 0, name="authorunmanaged", options={"managed": False}) + self.assertOperationAttributes( + changes, "testapp", 0, 0, name="authorunmanaged", options={"managed": False} + ) def test_unmanaged_custom_pk(self): """ @@ -1943,74 +3227,97 @@ class AutodetectorTests(TestCase): # First, we test the default pk field name changes = self.get_changes([], [self.author_unmanaged_default_pk, self.book]) # The model the FK on the book model points to. - fk_field = changes['otherapp'][0].operations[0].fields[2][1] - self.assertEqual(fk_field.remote_field.model, 'testapp.Author') + fk_field = changes["otherapp"][0].operations[0].fields[2][1] + self.assertEqual(fk_field.remote_field.model, "testapp.Author") # Now, we test the custom pk field name changes = self.get_changes([], [self.author_unmanaged_custom_pk, self.book]) # The model the FK on the book model points to. - fk_field = changes['otherapp'][0].operations[0].fields[2][1] - self.assertEqual(fk_field.remote_field.model, 'testapp.Author') + fk_field = changes["otherapp"][0].operations[0].fields[2][1] + self.assertEqual(fk_field.remote_field.model, "testapp.Author") @override_settings(AUTH_USER_MODEL="thirdapp.CustomUser") def test_swappable(self): with isolate_lru_cache(apps.get_swappable_settings_name): - changes = self.get_changes([self.custom_user], [self.custom_user, self.author_with_custom_user]) + changes = self.get_changes( + [self.custom_user], [self.custom_user, self.author_with_custom_user] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Author") - self.assertMigrationDependencies(changes, 'testapp', 0, [("__setting__", "AUTH_USER_MODEL")]) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["CreateModel"]) + self.assertOperationAttributes(changes, "testapp", 0, 0, name="Author") + self.assertMigrationDependencies( + changes, "testapp", 0, [("__setting__", "AUTH_USER_MODEL")] + ) def test_swappable_lowercase(self): - model_state = ModelState('testapp', 'Document', [ - ('id', models.AutoField(primary_key=True)), - ('owner', models.ForeignKey( - settings.AUTH_USER_MODEL.lower(), models.CASCADE, - )), - ]) + model_state = ModelState( + "testapp", + "Document", + [ + ("id", models.AutoField(primary_key=True)), + ( + "owner", + models.ForeignKey( + settings.AUTH_USER_MODEL.lower(), + models.CASCADE, + ), + ), + ], + ) with isolate_lru_cache(apps.get_swappable_settings_name): changes = self.get_changes([], [model_state]) - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ['CreateModel']) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name='Document') + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["CreateModel"]) + self.assertOperationAttributes(changes, "testapp", 0, 0, name="Document") self.assertMigrationDependencies( - changes, 'testapp', 0, [('__setting__', 'AUTH_USER_MODEL')], + changes, + "testapp", + 0, + [("__setting__", "AUTH_USER_MODEL")], ) def test_swappable_changed(self): with isolate_lru_cache(apps.get_swappable_settings_name): before = self.make_project_state([self.custom_user, self.author_with_user]) with override_settings(AUTH_USER_MODEL="thirdapp.CustomUser"): - after = self.make_project_state([self.custom_user, self.author_with_custom_user]) + after = self.make_project_state( + [self.custom_user, self.author_with_custom_user] + ) autodetector = MigrationAutodetector(before, after) changes = autodetector._detect_changes() # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AlterField"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, model_name="author", name='user') - fk_field = changes['testapp'][0].operations[0].field - self.assertEqual(fk_field.remote_field.model, 'thirdapp.CustomUser') + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["AlterField"]) + self.assertOperationAttributes( + changes, "testapp", 0, 0, model_name="author", name="user" + ) + fk_field = changes["testapp"][0].operations[0].field + self.assertEqual(fk_field.remote_field.model, "thirdapp.CustomUser") def test_add_field_with_default(self): """#22030 - Adding a field with a default should work.""" changes = self.get_changes([self.author_empty], [self.author_name_default]) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AddField"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name="name") + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["AddField"]) + self.assertOperationAttributes(changes, "testapp", 0, 0, name="name") def test_custom_deconstructible(self): """ Two instances which deconstruct to the same value aren't considered a change. """ - changes = self.get_changes([self.author_name_deconstructible_1], [self.author_name_deconstructible_2]) + changes = self.get_changes( + [self.author_name_deconstructible_1], [self.author_name_deconstructible_2] + ) # Right number of migrations? self.assertEqual(len(changes), 0) def test_deconstruct_field_kwarg(self): """Field instances are handled correctly by nested deconstruction.""" - changes = self.get_changes([self.author_name_deconstructible_3], [self.author_name_deconstructible_4]) + changes = self.get_changes( + [self.author_name_deconstructible_3], [self.author_name_deconstructible_4] + ) self.assertEqual(changes, {}) def test_deconstructible_list(self): @@ -2019,13 +3326,15 @@ class AutodetectorTests(TestCase): # should be considered equal for the purpose of detecting state changes # (even if the original items are unequal). changes = self.get_changes( - [self.author_name_deconstructible_list_1], [self.author_name_deconstructible_list_2] + [self.author_name_deconstructible_list_1], + [self.author_name_deconstructible_list_2], ) self.assertEqual(changes, {}) # Legitimate differences within the deconstructed lists should be reported # as a change changes = self.get_changes( - [self.author_name_deconstructible_list_1], [self.author_name_deconstructible_list_3] + [self.author_name_deconstructible_list_1], + [self.author_name_deconstructible_list_3], ) self.assertEqual(len(changes), 1) @@ -2035,13 +3344,15 @@ class AutodetectorTests(TestCase): # should be considered equal for the purpose of detecting state changes # (even if the original items are unequal). changes = self.get_changes( - [self.author_name_deconstructible_tuple_1], [self.author_name_deconstructible_tuple_2] + [self.author_name_deconstructible_tuple_1], + [self.author_name_deconstructible_tuple_2], ) self.assertEqual(changes, {}) # Legitimate differences within the deconstructed tuples should be reported # as a change changes = self.get_changes( - [self.author_name_deconstructible_tuple_1], [self.author_name_deconstructible_tuple_3] + [self.author_name_deconstructible_tuple_1], + [self.author_name_deconstructible_tuple_3], ) self.assertEqual(len(changes), 1) @@ -2051,13 +3362,15 @@ class AutodetectorTests(TestCase): # those dicts should be considered equal for the purpose of detecting # state changes (even if the original values are unequal). changes = self.get_changes( - [self.author_name_deconstructible_dict_1], [self.author_name_deconstructible_dict_2] + [self.author_name_deconstructible_dict_1], + [self.author_name_deconstructible_dict_2], ) self.assertEqual(changes, {}) # Legitimate differences within the deconstructed dicts should be reported # as a change changes = self.get_changes( - [self.author_name_deconstructible_dict_1], [self.author_name_deconstructible_dict_3] + [self.author_name_deconstructible_dict_1], + [self.author_name_deconstructible_dict_3], ) self.assertEqual(len(changes), 1) @@ -2070,29 +3383,34 @@ class AutodetectorTests(TestCase): # deconstructed values - whether or not the items themselves are different # instances - then the object as a whole is regarded as unchanged. changes = self.get_changes( - [self.author_name_nested_deconstructible_1], [self.author_name_nested_deconstructible_2] + [self.author_name_nested_deconstructible_1], + [self.author_name_nested_deconstructible_2], ) self.assertEqual(changes, {}) # Differences that exist solely within the args list of a deconstructed object # should be reported as changes changes = self.get_changes( - [self.author_name_nested_deconstructible_1], [self.author_name_nested_deconstructible_changed_arg] + [self.author_name_nested_deconstructible_1], + [self.author_name_nested_deconstructible_changed_arg], ) self.assertEqual(len(changes), 1) # Additional args should also be reported as a change changes = self.get_changes( - [self.author_name_nested_deconstructible_1], [self.author_name_nested_deconstructible_extra_arg] + [self.author_name_nested_deconstructible_1], + [self.author_name_nested_deconstructible_extra_arg], ) self.assertEqual(len(changes), 1) # Differences that exist solely within the kwargs dict of a deconstructed object # should be reported as changes changes = self.get_changes( - [self.author_name_nested_deconstructible_1], [self.author_name_nested_deconstructible_changed_kwarg] + [self.author_name_nested_deconstructible_1], + [self.author_name_nested_deconstructible_changed_kwarg], ) self.assertEqual(len(changes), 1) # Additional kwargs should also be reported as a change changes = self.get_changes( - [self.author_name_nested_deconstructible_1], [self.author_name_nested_deconstructible_extra_kwarg] + [self.author_name_nested_deconstructible_1], + [self.author_name_nested_deconstructible_extra_kwarg], ) self.assertEqual(len(changes), 1) @@ -2106,30 +3424,38 @@ class AutodetectorTests(TestCase): "Author", [ ("id", models.AutoField(primary_key=True)), - ("name", models.CharField( - max_length=200, - # IntegerField intentionally not instantiated. - default=models.IntegerField, - )) + ( + "name", + models.CharField( + max_length=200, + # IntegerField intentionally not instantiated. + default=models.IntegerField, + ), + ), ], ) changes = self.get_changes([], [author]) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel"]) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["CreateModel"]) def test_replace_string_with_foreignkey(self): """ #22300 - Adding an FK in the same "spot" as a deleted CharField should work. """ - changes = self.get_changes([self.author_with_publisher_string], [self.author_with_publisher, self.publisher]) + changes = self.get_changes( + [self.author_with_publisher_string], + [self.author_with_publisher, self.publisher], + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel", "RemoveField", "AddField"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Publisher") - self.assertOperationAttributes(changes, 'testapp', 0, 1, name="publisher_name") - self.assertOperationAttributes(changes, 'testapp', 0, 2, name="publisher") + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes( + changes, "testapp", 0, ["CreateModel", "RemoveField", "AddField"] + ) + self.assertOperationAttributes(changes, "testapp", 0, 0, name="Publisher") + self.assertOperationAttributes(changes, "testapp", 0, 1, name="publisher_name") + self.assertOperationAttributes(changes, "testapp", 0, 2, name="publisher") def test_foreign_key_removed_before_target_model(self): """ @@ -2140,45 +3466,62 @@ class AutodetectorTests(TestCase): [self.author_with_publisher, self.publisher], [self.author_name] ) # removes both the model and FK # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["RemoveField", "DeleteModel"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name="publisher") - self.assertOperationAttributes(changes, 'testapp', 0, 1, name="Publisher") + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["RemoveField", "DeleteModel"]) + self.assertOperationAttributes(changes, "testapp", 0, 0, name="publisher") + self.assertOperationAttributes(changes, "testapp", 0, 1, name="Publisher") - @mock.patch('django.db.migrations.questioner.MigrationQuestioner.ask_not_null_addition', - side_effect=AssertionError("Should not have prompted for not null addition")) + @mock.patch( + "django.db.migrations.questioner.MigrationQuestioner.ask_not_null_addition", + side_effect=AssertionError("Should not have prompted for not null addition"), + ) def test_add_many_to_many(self, mocked_ask_method): """#22435 - Adding a ManyToManyField should not prompt for a default.""" - changes = self.get_changes([self.author_empty, self.publisher], [self.author_with_m2m, self.publisher]) + changes = self.get_changes( + [self.author_empty, self.publisher], [self.author_with_m2m, self.publisher] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AddField"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name="publishers") + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["AddField"]) + self.assertOperationAttributes(changes, "testapp", 0, 0, name="publishers") def test_alter_many_to_many(self): changes = self.get_changes( - [self.author_with_m2m, self.publisher], [self.author_with_m2m_blank, self.publisher] + [self.author_with_m2m, self.publisher], + [self.author_with_m2m_blank, self.publisher], ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AlterField"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name="publishers") + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["AlterField"]) + self.assertOperationAttributes(changes, "testapp", 0, 0, name="publishers") def test_create_with_through_model(self): """ Adding a m2m with a through model and the models that use it should be ordered correctly. """ - changes = self.get_changes([], [self.author_with_m2m_through, self.publisher, self.contract]) + changes = self.get_changes( + [], [self.author_with_m2m_through, self.publisher, self.contract] + ) # Right number/type of migrations? self.assertNumberMigrations(changes, "testapp", 1) - self.assertOperationTypes(changes, "testapp", 0, [ - 'CreateModel', 'CreateModel', 'CreateModel', 'AddField', - ]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name='Author') - self.assertOperationAttributes(changes, 'testapp', 0, 1, name='Publisher') - self.assertOperationAttributes(changes, 'testapp', 0, 2, name='Contract') - self.assertOperationAttributes(changes, 'testapp', 0, 3, model_name='author', name='publishers') + self.assertOperationTypes( + changes, + "testapp", + 0, + [ + "CreateModel", + "CreateModel", + "CreateModel", + "AddField", + ], + ) + self.assertOperationAttributes(changes, "testapp", 0, 0, name="Author") + self.assertOperationAttributes(changes, "testapp", 0, 1, name="Publisher") + self.assertOperationAttributes(changes, "testapp", 0, 2, name="Contract") + self.assertOperationAttributes( + changes, "testapp", 0, 3, model_name="author", name="publishers" + ) def test_many_to_many_removed_before_through_model(self): """ @@ -2186,15 +3529,23 @@ class AutodetectorTests(TestCase): must remove the field before the model to maintain consistency. """ changes = self.get_changes( - [self.book_with_multiple_authors_through_attribution, self.author_name, self.attribution], + [ + self.book_with_multiple_authors_through_attribution, + self.author_name, + self.attribution, + ], [self.book_with_no_author, self.author_name], ) # Remove both the through model and ManyToMany # Right number/type of migrations? self.assertNumberMigrations(changes, "otherapp", 1) - self.assertOperationTypes(changes, 'otherapp', 0, ['RemoveField', 'DeleteModel']) - self.assertOperationAttributes(changes, 'otherapp', 0, 0, name='authors', model_name='book') - self.assertOperationAttributes(changes, 'otherapp', 0, 1, name='Attribution') + self.assertOperationTypes( + changes, "otherapp", 0, ["RemoveField", "DeleteModel"] + ) + self.assertOperationAttributes( + changes, "otherapp", 0, 0, name="authors", model_name="book" + ) + self.assertOperationAttributes(changes, "otherapp", 0, 1, name="Attribution") def test_many_to_many_removed_before_through_model_2(self): """ @@ -2203,16 +3554,24 @@ class AutodetectorTests(TestCase): consistency. """ changes = self.get_changes( - [self.book_with_multiple_authors_through_attribution, self.author_name, self.attribution], + [ + self.book_with_multiple_authors_through_attribution, + self.author_name, + self.attribution, + ], [self.author_name], ) # Remove both the through model and ManyToMany # Right number/type of migrations? self.assertNumberMigrations(changes, "otherapp", 1) - self.assertOperationTypes(changes, 'otherapp', 0, ['RemoveField', 'DeleteModel', 'DeleteModel']) - self.assertOperationAttributes(changes, 'otherapp', 0, 0, name='authors', model_name='book') - self.assertOperationAttributes(changes, 'otherapp', 0, 1, name='Attribution') - self.assertOperationAttributes(changes, 'otherapp', 0, 2, name='Book') + self.assertOperationTypes( + changes, "otherapp", 0, ["RemoveField", "DeleteModel", "DeleteModel"] + ) + self.assertOperationAttributes( + changes, "otherapp", 0, 0, name="authors", model_name="book" + ) + self.assertOperationAttributes(changes, "otherapp", 0, 1, name="Attribution") + self.assertOperationAttributes(changes, "otherapp", 0, 2, name="Book") def test_m2m_w_through_multistep_remove(self): """ @@ -2221,14 +3580,24 @@ class AutodetectorTests(TestCase): pass through an inconsistent state. The autodetector should produce two migrations to avoid this issue. """ - changes = self.get_changes([self.author_with_m2m_through, self.publisher, self.contract], [self.publisher]) + changes = self.get_changes( + [self.author_with_m2m_through, self.publisher, self.contract], + [self.publisher], + ) # Right number/type of migrations? self.assertNumberMigrations(changes, "testapp", 1) - self.assertOperationTypes(changes, "testapp", 0, [ - "RemoveField", "RemoveField", "DeleteModel", "DeleteModel" - ]) - self.assertOperationAttributes(changes, "testapp", 0, 0, name="author", model_name='contract') - self.assertOperationAttributes(changes, "testapp", 0, 1, name="publisher", model_name='contract') + self.assertOperationTypes( + changes, + "testapp", + 0, + ["RemoveField", "RemoveField", "DeleteModel", "DeleteModel"], + ) + self.assertOperationAttributes( + changes, "testapp", 0, 0, name="author", model_name="contract" + ) + self.assertOperationAttributes( + changes, "testapp", 0, 1, name="publisher", model_name="contract" + ) self.assertOperationAttributes(changes, "testapp", 0, 2, name="Author") self.assertOperationAttributes(changes, "testapp", 0, 3, name="Contract") @@ -2237,38 +3606,60 @@ class AutodetectorTests(TestCase): #23938 - Changing a concrete field into a ManyToManyField first removes the concrete field and then adds the m2m field. """ - changes = self.get_changes([self.author_with_former_m2m], [self.author_with_m2m, self.publisher]) + changes = self.get_changes( + [self.author_with_former_m2m], [self.author_with_m2m, self.publisher] + ) # Right number/type of migrations? self.assertNumberMigrations(changes, "testapp", 1) - self.assertOperationTypes(changes, "testapp", 0, ["CreateModel", "RemoveField", "AddField"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name='Publisher') - self.assertOperationAttributes(changes, 'testapp', 0, 1, name="publishers", model_name='author') - self.assertOperationAttributes(changes, 'testapp', 0, 2, name="publishers", model_name='author') + self.assertOperationTypes( + changes, "testapp", 0, ["CreateModel", "RemoveField", "AddField"] + ) + self.assertOperationAttributes(changes, "testapp", 0, 0, name="Publisher") + self.assertOperationAttributes( + changes, "testapp", 0, 1, name="publishers", model_name="author" + ) + self.assertOperationAttributes( + changes, "testapp", 0, 2, name="publishers", model_name="author" + ) def test_many_to_many_changed_to_concrete_field(self): """ #23938 - Changing a ManyToManyField into a concrete field first removes the m2m field and then adds the concrete field. """ - changes = self.get_changes([self.author_with_m2m, self.publisher], [self.author_with_former_m2m]) + changes = self.get_changes( + [self.author_with_m2m, self.publisher], [self.author_with_former_m2m] + ) # Right number/type of migrations? self.assertNumberMigrations(changes, "testapp", 1) - self.assertOperationTypes(changes, "testapp", 0, ["RemoveField", "AddField", "DeleteModel"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name="publishers", model_name='author') - self.assertOperationAttributes(changes, 'testapp', 0, 1, name="publishers", model_name='author') - self.assertOperationAttributes(changes, 'testapp', 0, 2, name='Publisher') - self.assertOperationFieldAttributes(changes, 'testapp', 0, 1, max_length=100) + self.assertOperationTypes( + changes, "testapp", 0, ["RemoveField", "AddField", "DeleteModel"] + ) + self.assertOperationAttributes( + changes, "testapp", 0, 0, name="publishers", model_name="author" + ) + self.assertOperationAttributes( + changes, "testapp", 0, 1, name="publishers", model_name="author" + ) + self.assertOperationAttributes(changes, "testapp", 0, 2, name="Publisher") + self.assertOperationFieldAttributes(changes, "testapp", 0, 1, max_length=100) def test_non_circular_foreignkey_dependency_removal(self): """ If two models with a ForeignKey from one to the other are removed at the same time, the autodetector should remove them in the correct order. """ - changes = self.get_changes([self.author_with_publisher, self.publisher_with_author], []) + changes = self.get_changes( + [self.author_with_publisher, self.publisher_with_author], [] + ) # Right number/type of migrations? self.assertNumberMigrations(changes, "testapp", 1) - self.assertOperationTypes(changes, "testapp", 0, ["RemoveField", "DeleteModel", "DeleteModel"]) - self.assertOperationAttributes(changes, "testapp", 0, 0, name="author", model_name='publisher') + self.assertOperationTypes( + changes, "testapp", 0, ["RemoveField", "DeleteModel", "DeleteModel"] + ) + self.assertOperationAttributes( + changes, "testapp", 0, 0, name="author", model_name="publisher" + ) self.assertOperationAttributes(changes, "testapp", 0, 1, name="Author") self.assertOperationAttributes(changes, "testapp", 0, 2, name="Publisher") @@ -2278,61 +3669,96 @@ class AutodetectorTests(TestCase): # Right number/type of migrations? self.assertNumberMigrations(changes, "testapp", 1) self.assertOperationTypes(changes, "testapp", 0, ["AlterModelOptions"]) - self.assertOperationAttributes(changes, "testapp", 0, 0, options={ - "permissions": [('can_hire', 'Can hire')], - "verbose_name": "Authi", - }) + self.assertOperationAttributes( + changes, + "testapp", + 0, + 0, + options={ + "permissions": [("can_hire", "Can hire")], + "verbose_name": "Authi", + }, + ) # Changing them back to empty should also make a change changes = self.get_changes([self.author_with_options], [self.author_empty]) # Right number/type of migrations? self.assertNumberMigrations(changes, "testapp", 1) self.assertOperationTypes(changes, "testapp", 0, ["AlterModelOptions"]) - self.assertOperationAttributes(changes, "testapp", 0, 0, name="author", options={}) + self.assertOperationAttributes( + changes, "testapp", 0, 0, name="author", options={} + ) def test_alter_model_options_proxy(self): """Changing a proxy model's options should also make a change.""" changes = self.get_changes( - [self.author_proxy, self.author_empty], [self.author_proxy_options, self.author_empty] + [self.author_proxy, self.author_empty], + [self.author_proxy_options, self.author_empty], ) # Right number/type of migrations? self.assertNumberMigrations(changes, "testapp", 1) self.assertOperationTypes(changes, "testapp", 0, ["AlterModelOptions"]) - self.assertOperationAttributes(changes, "testapp", 0, 0, name="authorproxy", options={ - "verbose_name": "Super Author" - }) + self.assertOperationAttributes( + changes, + "testapp", + 0, + 0, + name="authorproxy", + options={"verbose_name": "Super Author"}, + ) def test_set_alter_order_with_respect_to(self): """Setting order_with_respect_to adds a field.""" - changes = self.get_changes([self.book, self.author_with_book], [self.book, self.author_with_book_order_wrt]) + changes = self.get_changes( + [self.book, self.author_with_book], + [self.book, self.author_with_book_order_wrt], + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AlterOrderWithRespectTo"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name="author", order_with_respect_to="book") + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["AlterOrderWithRespectTo"]) + self.assertOperationAttributes( + changes, "testapp", 0, 0, name="author", order_with_respect_to="book" + ) def test_add_alter_order_with_respect_to(self): """ Setting order_with_respect_to when adding the FK too does things in the right order. """ - changes = self.get_changes([self.author_name], [self.book, self.author_with_book_order_wrt]) + changes = self.get_changes( + [self.author_name], [self.book, self.author_with_book_order_wrt] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AddField", "AlterOrderWithRespectTo"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, model_name="author", name="book") - self.assertOperationAttributes(changes, 'testapp', 0, 1, name="author", order_with_respect_to="book") + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes( + changes, "testapp", 0, ["AddField", "AlterOrderWithRespectTo"] + ) + self.assertOperationAttributes( + changes, "testapp", 0, 0, model_name="author", name="book" + ) + self.assertOperationAttributes( + changes, "testapp", 0, 1, name="author", order_with_respect_to="book" + ) def test_remove_alter_order_with_respect_to(self): """ Removing order_with_respect_to when removing the FK too does things in the right order. """ - changes = self.get_changes([self.book, self.author_with_book_order_wrt], [self.author_name]) + changes = self.get_changes( + [self.book, self.author_with_book_order_wrt], [self.author_name] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AlterOrderWithRespectTo", "RemoveField"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name="author", order_with_respect_to=None) - self.assertOperationAttributes(changes, 'testapp', 0, 1, model_name="author", name="book") + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes( + changes, "testapp", 0, ["AlterOrderWithRespectTo", "RemoveField"] + ) + self.assertOperationAttributes( + changes, "testapp", 0, 0, name="author", order_with_respect_to=None + ) + self.assertOperationAttributes( + changes, "testapp", 0, 1, model_name="author", name="book" + ) def test_add_model_order_with_respect_to(self): """ @@ -2341,121 +3767,167 @@ class AutodetectorTests(TestCase): """ changes = self.get_changes([], [self.book, self.author_with_book_order_wrt]) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel"]) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["CreateModel"]) self.assertOperationAttributes( - changes, 'testapp', 0, 0, name="Author", options={'order_with_respect_to': 'book'} + changes, + "testapp", + 0, + 0, + name="Author", + options={"order_with_respect_to": "book"}, + ) + self.assertNotIn( + "_order", + [name for name, field in changes["testapp"][0].operations[0].fields], ) - self.assertNotIn("_order", [name for name, field in changes['testapp'][0].operations[0].fields]) def test_add_model_order_with_respect_to_index_foo_together(self): - changes = self.get_changes([], [ - self.book, - ModelState('testapp', 'Author', [ - ('id', models.AutoField(primary_key=True)), - ('name', models.CharField(max_length=200)), - ('book', models.ForeignKey('otherapp.Book', models.CASCADE)), - ], options={ - 'order_with_respect_to': 'book', - 'index_together': {('name', '_order')}, - 'unique_together': {('id', '_order')}, - }), - ]) - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ['CreateModel']) + changes = self.get_changes( + [], + [ + self.book, + ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200)), + ("book", models.ForeignKey("otherapp.Book", models.CASCADE)), + ], + options={ + "order_with_respect_to": "book", + "index_together": {("name", "_order")}, + "unique_together": {("id", "_order")}, + }, + ), + ], + ) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["CreateModel"]) self.assertOperationAttributes( changes, - 'testapp', + "testapp", 0, 0, - name='Author', + name="Author", options={ - 'order_with_respect_to': 'book', - 'index_together': {('name', '_order')}, - 'unique_together': {('id', '_order')}, + "order_with_respect_to": "book", + "index_together": {("name", "_order")}, + "unique_together": {("id", "_order")}, }, ) def test_add_model_order_with_respect_to_index_constraint(self): tests = [ ( - 'AddIndex', - {'indexes': [ - models.Index(fields=['_order'], name='book_order_idx'), - ]}, + "AddIndex", + { + "indexes": [ + models.Index(fields=["_order"], name="book_order_idx"), + ] + }, ), ( - 'AddConstraint', - {'constraints': [ - models.CheckConstraint( - check=models.Q(_order__gt=1), - name='book_order_gt_1', - ), - ]}, + "AddConstraint", + { + "constraints": [ + models.CheckConstraint( + check=models.Q(_order__gt=1), + name="book_order_gt_1", + ), + ] + }, ), ] for operation, extra_option in tests: with self.subTest(operation=operation): - after = ModelState('testapp', 'Author', [ - ('id', models.AutoField(primary_key=True)), - ('name', models.CharField(max_length=200)), - ('book', models.ForeignKey('otherapp.Book', models.CASCADE)), - ], options={ - 'order_with_respect_to': 'book', - **extra_option, - }) + after = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200)), + ("book", models.ForeignKey("otherapp.Book", models.CASCADE)), + ], + options={ + "order_with_respect_to": "book", + **extra_option, + }, + ) changes = self.get_changes([], [self.book, after]) - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, [ - 'CreateModel', operation, - ]) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes( + changes, + "testapp", + 0, + [ + "CreateModel", + operation, + ], + ) self.assertOperationAttributes( changes, - 'testapp', + "testapp", 0, 0, - name='Author', - options={'order_with_respect_to': 'book'}, + name="Author", + options={"order_with_respect_to": "book"}, ) def test_set_alter_order_with_respect_to_index_constraint_foo_together(self): tests = [ ( - 'AddIndex', - {'indexes': [ - models.Index(fields=['_order'], name='book_order_idx'), - ]}, + "AddIndex", + { + "indexes": [ + models.Index(fields=["_order"], name="book_order_idx"), + ] + }, ), ( - 'AddConstraint', - {'constraints': [ - models.CheckConstraint( - check=models.Q(_order__gt=1), - name='book_order_gt_1', - ), - ]}, + "AddConstraint", + { + "constraints": [ + models.CheckConstraint( + check=models.Q(_order__gt=1), + name="book_order_gt_1", + ), + ] + }, ), - ('AlterIndexTogether', {'index_together': {('name', '_order')}}), - ('AlterUniqueTogether', {'unique_together': {('id', '_order')}}), + ("AlterIndexTogether", {"index_together": {("name", "_order")}}), + ("AlterUniqueTogether", {"unique_together": {("id", "_order")}}), ] for operation, extra_option in tests: with self.subTest(operation=operation): - after = ModelState('testapp', 'Author', [ - ('id', models.AutoField(primary_key=True)), - ('name', models.CharField(max_length=200)), - ('book', models.ForeignKey('otherapp.Book', models.CASCADE)), - ], options={ - 'order_with_respect_to': 'book', - **extra_option, - }) + after = ModelState( + "testapp", + "Author", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=200)), + ("book", models.ForeignKey("otherapp.Book", models.CASCADE)), + ], + options={ + "order_with_respect_to": "book", + **extra_option, + }, + ) changes = self.get_changes( [self.book, self.author_with_book], [self.book, after], ) - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, [ - 'AlterOrderWithRespectTo', operation, - ]) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes( + changes, + "testapp", + 0, + [ + "AlterOrderWithRespectTo", + operation, + ], + ) def test_alter_model_managers(self): """ @@ -2463,41 +3935,62 @@ class AutodetectorTests(TestCase): """ changes = self.get_changes([self.other_pony], [self.other_pony_food]) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'otherapp', 1) - self.assertOperationTypes(changes, 'otherapp', 0, ["AlterModelManagers"]) - self.assertOperationAttributes(changes, 'otherapp', 0, 0, name="pony") - self.assertEqual([name for name, mgr in changes['otherapp'][0].operations[0].managers], - ['food_qs', 'food_mgr', 'food_mgr_kwargs']) - self.assertEqual(changes['otherapp'][0].operations[0].managers[1][1].args, ('a', 'b', 1, 2)) - self.assertEqual(changes['otherapp'][0].operations[0].managers[2][1].args, ('x', 'y', 3, 4)) + self.assertNumberMigrations(changes, "otherapp", 1) + self.assertOperationTypes(changes, "otherapp", 0, ["AlterModelManagers"]) + self.assertOperationAttributes(changes, "otherapp", 0, 0, name="pony") + self.assertEqual( + [name for name, mgr in changes["otherapp"][0].operations[0].managers], + ["food_qs", "food_mgr", "food_mgr_kwargs"], + ) + self.assertEqual( + changes["otherapp"][0].operations[0].managers[1][1].args, ("a", "b", 1, 2) + ) + self.assertEqual( + changes["otherapp"][0].operations[0].managers[2][1].args, ("x", "y", 3, 4) + ) def test_swappable_first_inheritance(self): """Swappable models get their CreateModel first.""" changes = self.get_changes([], [self.custom_user, self.aardvark]) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'thirdapp', 1) - self.assertOperationTypes(changes, 'thirdapp', 0, ["CreateModel", "CreateModel"]) - self.assertOperationAttributes(changes, 'thirdapp', 0, 0, name="CustomUser") - self.assertOperationAttributes(changes, 'thirdapp', 0, 1, name="Aardvark") + self.assertNumberMigrations(changes, "thirdapp", 1) + self.assertOperationTypes( + changes, "thirdapp", 0, ["CreateModel", "CreateModel"] + ) + self.assertOperationAttributes(changes, "thirdapp", 0, 0, name="CustomUser") + self.assertOperationAttributes(changes, "thirdapp", 0, 1, name="Aardvark") def test_default_related_name_option(self): - model_state = ModelState('app', 'model', [ - ('id', models.AutoField(primary_key=True)), - ], options={'default_related_name': 'related_name'}) + model_state = ModelState( + "app", + "model", + [ + ("id", models.AutoField(primary_key=True)), + ], + options={"default_related_name": "related_name"}, + ) changes = self.get_changes([], [model_state]) - self.assertNumberMigrations(changes, 'app', 1) - self.assertOperationTypes(changes, 'app', 0, ['CreateModel']) + self.assertNumberMigrations(changes, "app", 1) + self.assertOperationTypes(changes, "app", 0, ["CreateModel"]) self.assertOperationAttributes( - changes, 'app', 0, 0, name='model', - options={'default_related_name': 'related_name'}, + changes, + "app", + 0, + 0, + name="model", + options={"default_related_name": "related_name"}, + ) + altered_model_state = ModelState( + "app", + "Model", + [ + ("id", models.AutoField(primary_key=True)), + ], ) - altered_model_state = ModelState('app', 'Model', [ - ('id', models.AutoField(primary_key=True)), - ]) changes = self.get_changes([model_state], [altered_model_state]) - self.assertNumberMigrations(changes, 'app', 1) - self.assertOperationTypes(changes, 'app', 0, ['AlterModelOptions']) - self.assertOperationAttributes(changes, 'app', 0, 0, name='model', options={}) + self.assertNumberMigrations(changes, "app", 1) + self.assertOperationTypes(changes, "app", 0, ["AlterModelOptions"]) + self.assertOperationAttributes(changes, "app", 0, 0, name="model", options={}) @override_settings(AUTH_USER_MODEL="thirdapp.CustomUser") def test_swappable_first_setting(self): @@ -2505,39 +3998,64 @@ class AutodetectorTests(TestCase): with isolate_lru_cache(apps.get_swappable_settings_name): changes = self.get_changes([], [self.custom_user_no_inherit, self.aardvark]) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'thirdapp', 1) - self.assertOperationTypes(changes, 'thirdapp', 0, ["CreateModel", "CreateModel"]) - self.assertOperationAttributes(changes, 'thirdapp', 0, 0, name="CustomUser") - self.assertOperationAttributes(changes, 'thirdapp', 0, 1, name="Aardvark") + self.assertNumberMigrations(changes, "thirdapp", 1) + self.assertOperationTypes( + changes, "thirdapp", 0, ["CreateModel", "CreateModel"] + ) + self.assertOperationAttributes(changes, "thirdapp", 0, 0, name="CustomUser") + self.assertOperationAttributes(changes, "thirdapp", 0, 1, name="Aardvark") def test_bases_first(self): """Bases of other models come first.""" - changes = self.get_changes([], [self.aardvark_based_on_author, self.author_name]) + changes = self.get_changes( + [], [self.aardvark_based_on_author, self.author_name] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel", "CreateModel"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Author") - self.assertOperationAttributes(changes, 'testapp', 0, 1, name="Aardvark") + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["CreateModel", "CreateModel"]) + self.assertOperationAttributes(changes, "testapp", 0, 0, name="Author") + self.assertOperationAttributes(changes, "testapp", 0, 1, name="Aardvark") def test_bases_first_mixed_case_app_label(self): - app_label = 'MiXedCaseApp' - changes = self.get_changes([], [ - ModelState(app_label, 'owner', [ - ('id', models.AutoField(primary_key=True)), - ]), - ModelState(app_label, 'place', [ - ('id', models.AutoField(primary_key=True)), - ('owner', models.ForeignKey('MiXedCaseApp.owner', models.CASCADE)), - ]), - ModelState(app_label, 'restaurant', [], bases=('MiXedCaseApp.place',)), - ]) + app_label = "MiXedCaseApp" + changes = self.get_changes( + [], + [ + ModelState( + app_label, + "owner", + [ + ("id", models.AutoField(primary_key=True)), + ], + ), + ModelState( + app_label, + "place", + [ + ("id", models.AutoField(primary_key=True)), + ( + "owner", + models.ForeignKey("MiXedCaseApp.owner", models.CASCADE), + ), + ], + ), + ModelState(app_label, "restaurant", [], bases=("MiXedCaseApp.place",)), + ], + ) self.assertNumberMigrations(changes, app_label, 1) - self.assertOperationTypes(changes, app_label, 0, [ - 'CreateModel', 'CreateModel', 'CreateModel', - ]) - self.assertOperationAttributes(changes, app_label, 0, 0, name='owner') - self.assertOperationAttributes(changes, app_label, 0, 1, name='place') - self.assertOperationAttributes(changes, app_label, 0, 2, name='restaurant') + self.assertOperationTypes( + changes, + app_label, + 0, + [ + "CreateModel", + "CreateModel", + "CreateModel", + ], + ) + self.assertOperationAttributes(changes, app_label, 0, 0, name="owner") + self.assertOperationAttributes(changes, app_label, 0, 1, name="place") + self.assertOperationAttributes(changes, app_label, 0, 2, name="restaurant") def test_multiple_bases(self): """#23956 - Inheriting models doesn't move *_ptr fields into AddField operations.""" @@ -2549,9 +4067,12 @@ class AutodetectorTests(TestCase): changes = self.get_changes([], [A, B, C, D, E]) # Right number/type of migrations? self.assertNumberMigrations(changes, "app", 1) - self.assertOperationTypes(changes, "app", 0, [ - "CreateModel", "CreateModel", "CreateModel", "CreateModel", "CreateModel" - ]) + self.assertOperationTypes( + changes, + "app", + 0, + ["CreateModel", "CreateModel", "CreateModel", "CreateModel", "CreateModel"], + ) self.assertOperationAttributes(changes, "app", 0, 0, name="A") self.assertOperationAttributes(changes, "app", 0, 1, name="B") self.assertOperationAttributes(changes, "app", 0, 2, name="C") @@ -2560,13 +4081,19 @@ class AutodetectorTests(TestCase): def test_proxy_bases_first(self): """Bases of proxies come first.""" - changes = self.get_changes([], [self.author_empty, self.author_proxy, self.author_proxy_proxy]) + changes = self.get_changes( + [], [self.author_empty, self.author_proxy, self.author_proxy_proxy] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel", "CreateModel", "CreateModel"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Author") - self.assertOperationAttributes(changes, 'testapp', 0, 1, name="AuthorProxy") - self.assertOperationAttributes(changes, 'testapp', 0, 2, name="AAuthorProxyProxy") + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes( + changes, "testapp", 0, ["CreateModel", "CreateModel", "CreateModel"] + ) + self.assertOperationAttributes(changes, "testapp", 0, 0, name="Author") + self.assertOperationAttributes(changes, "testapp", 0, 1, name="AuthorProxy") + self.assertOperationAttributes( + changes, "testapp", 0, 2, name="AAuthorProxyProxy" + ) def test_pk_fk_included(self): """ @@ -2574,10 +4101,10 @@ class AutodetectorTests(TestCase): """ changes = self.get_changes([], [self.aardvark_pk_fk_author, self.author_name]) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel", "CreateModel"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Author") - self.assertOperationAttributes(changes, 'testapp', 0, 1, name="Aardvark") + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["CreateModel", "CreateModel"]) + self.assertOperationAttributes(changes, "testapp", 0, 0, name="Author") + self.assertOperationAttributes(changes, "testapp", 0, 1, name="Aardvark") def test_first_dependency(self): """ @@ -2587,14 +4114,16 @@ class AutodetectorTests(TestCase): loader = MigrationLoader(connection) before = self.make_project_state([]) after = self.make_project_state([self.book_migrations_fk]) - after.real_apps = {'migrations'} + after.real_apps = {"migrations"} autodetector = MigrationAutodetector(before, after) changes = autodetector._detect_changes(graph=loader.graph) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'otherapp', 1) - self.assertOperationTypes(changes, 'otherapp', 0, ["CreateModel"]) - self.assertOperationAttributes(changes, 'otherapp', 0, 0, name="Book") - self.assertMigrationDependencies(changes, 'otherapp', 0, [("migrations", "__first__")]) + self.assertNumberMigrations(changes, "otherapp", 1) + self.assertOperationTypes(changes, "otherapp", 0, ["CreateModel"]) + self.assertOperationAttributes(changes, "otherapp", 0, 0, name="Book") + self.assertMigrationDependencies( + changes, "otherapp", 0, [("migrations", "__first__")] + ) @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"}) def test_last_dependency(self): @@ -2606,14 +4135,16 @@ class AutodetectorTests(TestCase): loader = MigrationLoader(connection) before = self.make_project_state([]) after = self.make_project_state([self.book_migrations_fk]) - after.real_apps = {'migrations'} + after.real_apps = {"migrations"} autodetector = MigrationAutodetector(before, after) changes = autodetector._detect_changes(graph=loader.graph) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'otherapp', 1) - self.assertOperationTypes(changes, 'otherapp', 0, ["CreateModel"]) - self.assertOperationAttributes(changes, 'otherapp', 0, 0, name="Book") - self.assertMigrationDependencies(changes, 'otherapp', 0, [("migrations", "0002_second")]) + self.assertNumberMigrations(changes, "otherapp", 1) + self.assertOperationTypes(changes, "otherapp", 0, ["CreateModel"]) + self.assertOperationAttributes(changes, "otherapp", 0, 0, name="Book") + self.assertMigrationDependencies( + changes, "otherapp", 0, [("migrations", "0002_second")] + ) def test_alter_fk_before_model_deletion(self): """ @@ -2622,61 +4153,85 @@ class AutodetectorTests(TestCase): """ changes = self.get_changes( [self.author_name, self.publisher_with_author], - [self.aardvark_testapp, self.publisher_with_aardvark_author] + [self.aardvark_testapp, self.publisher_with_aardvark_author], ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel", "AlterField", "DeleteModel"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Aardvark") - self.assertOperationAttributes(changes, 'testapp', 0, 1, name="author") - self.assertOperationAttributes(changes, 'testapp', 0, 2, name="Author") + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes( + changes, "testapp", 0, ["CreateModel", "AlterField", "DeleteModel"] + ) + self.assertOperationAttributes(changes, "testapp", 0, 0, name="Aardvark") + self.assertOperationAttributes(changes, "testapp", 0, 1, name="author") + self.assertOperationAttributes(changes, "testapp", 0, 2, name="Author") def test_fk_dependency_other_app(self): """ #23100 - ForeignKeys correctly depend on other apps' models. """ - changes = self.get_changes([self.author_name, self.book], [self.author_with_book, self.book]) + changes = self.get_changes( + [self.author_name, self.book], [self.author_with_book, self.book] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AddField"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name="book") - self.assertMigrationDependencies(changes, 'testapp', 0, [("otherapp", "__first__")]) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["AddField"]) + self.assertOperationAttributes(changes, "testapp", 0, 0, name="book") + self.assertMigrationDependencies( + changes, "testapp", 0, [("otherapp", "__first__")] + ) def test_alter_field_to_fk_dependency_other_app(self): changes = self.get_changes( [self.author_empty, self.book_with_no_author_fk], [self.author_empty, self.book], ) - self.assertNumberMigrations(changes, 'otherapp', 1) - self.assertOperationTypes(changes, 'otherapp', 0, ['AlterField']) - self.assertMigrationDependencies(changes, 'otherapp', 0, [('testapp', '__first__')]) + self.assertNumberMigrations(changes, "otherapp", 1) + self.assertOperationTypes(changes, "otherapp", 0, ["AlterField"]) + self.assertMigrationDependencies( + changes, "otherapp", 0, [("testapp", "__first__")] + ) def test_circular_dependency_mixed_addcreate(self): """ #23315 - The dependency resolver knows to put all CreateModel before AddField and not become unsolvable. """ - address = ModelState("a", "Address", [ - ("id", models.AutoField(primary_key=True)), - ("country", models.ForeignKey("b.DeliveryCountry", models.CASCADE)), - ]) - person = ModelState("a", "Person", [ - ("id", models.AutoField(primary_key=True)), - ]) - apackage = ModelState("b", "APackage", [ - ("id", models.AutoField(primary_key=True)), - ("person", models.ForeignKey("a.Person", models.CASCADE)), - ]) - country = ModelState("b", "DeliveryCountry", [ - ("id", models.AutoField(primary_key=True)), - ]) + address = ModelState( + "a", + "Address", + [ + ("id", models.AutoField(primary_key=True)), + ("country", models.ForeignKey("b.DeliveryCountry", models.CASCADE)), + ], + ) + person = ModelState( + "a", + "Person", + [ + ("id", models.AutoField(primary_key=True)), + ], + ) + apackage = ModelState( + "b", + "APackage", + [ + ("id", models.AutoField(primary_key=True)), + ("person", models.ForeignKey("a.Person", models.CASCADE)), + ], + ) + country = ModelState( + "b", + "DeliveryCountry", + [ + ("id", models.AutoField(primary_key=True)), + ], + ) changes = self.get_changes([], [address, person, apackage, country]) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'a', 2) - self.assertNumberMigrations(changes, 'b', 1) - self.assertOperationTypes(changes, 'a', 0, ["CreateModel", "CreateModel"]) - self.assertOperationTypes(changes, 'a', 1, ["AddField"]) - self.assertOperationTypes(changes, 'b', 0, ["CreateModel", "CreateModel"]) + self.assertNumberMigrations(changes, "a", 2) + self.assertNumberMigrations(changes, "b", 1) + self.assertOperationTypes(changes, "a", 0, ["CreateModel", "CreateModel"]) + self.assertOperationTypes(changes, "a", 1, ["AddField"]) + self.assertOperationTypes(changes, "b", 0, ["CreateModel", "CreateModel"]) @override_settings(AUTH_USER_MODEL="a.Tenant") def test_circular_dependency_swappable(self): @@ -2685,27 +4240,42 @@ class AutodetectorTests(TestCase): swappable models. """ with isolate_lru_cache(apps.get_swappable_settings_name): - tenant = ModelState("a", "Tenant", [ - ("id", models.AutoField(primary_key=True)), - ("primary_address", models.ForeignKey("b.Address", models.CASCADE))], - bases=(AbstractBaseUser,) + tenant = ModelState( + "a", + "Tenant", + [ + ("id", models.AutoField(primary_key=True)), + ("primary_address", models.ForeignKey("b.Address", models.CASCADE)), + ], + bases=(AbstractBaseUser,), + ) + address = ModelState( + "b", + "Address", + [ + ("id", models.AutoField(primary_key=True)), + ( + "tenant", + models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE), + ), + ], ) - address = ModelState("b", "Address", [ - ("id", models.AutoField(primary_key=True)), - ("tenant", models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE)), - ]) changes = self.get_changes([], [address, tenant]) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'a', 2) - self.assertOperationTypes(changes, 'a', 0, ["CreateModel"]) - self.assertOperationTypes(changes, 'a', 1, ["AddField"]) - self.assertMigrationDependencies(changes, 'a', 0, []) - self.assertMigrationDependencies(changes, 'a', 1, [('a', 'auto_1'), ('b', 'auto_1')]) + self.assertNumberMigrations(changes, "a", 2) + self.assertOperationTypes(changes, "a", 0, ["CreateModel"]) + self.assertOperationTypes(changes, "a", 1, ["AddField"]) + self.assertMigrationDependencies(changes, "a", 0, []) + self.assertMigrationDependencies( + changes, "a", 1, [("a", "auto_1"), ("b", "auto_1")] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'b', 1) - self.assertOperationTypes(changes, 'b', 0, ["CreateModel"]) - self.assertMigrationDependencies(changes, 'b', 0, [('__setting__', 'AUTH_USER_MODEL')]) + self.assertNumberMigrations(changes, "b", 1) + self.assertOperationTypes(changes, "b", 0, ["CreateModel"]) + self.assertMigrationDependencies( + changes, "b", 0, [("__setting__", "AUTH_USER_MODEL")] + ) @override_settings(AUTH_USER_MODEL="b.Tenant") def test_circular_dependency_swappable2(self): @@ -2715,26 +4285,39 @@ class AutodetectorTests(TestCase): model. """ with isolate_lru_cache(apps.get_swappable_settings_name): - address = ModelState("a", "Address", [ - ("id", models.AutoField(primary_key=True)), - ("tenant", models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE)), - ]) - tenant = ModelState("b", "Tenant", [ - ("id", models.AutoField(primary_key=True)), - ("primary_address", models.ForeignKey("a.Address", models.CASCADE))], - bases=(AbstractBaseUser,) + address = ModelState( + "a", + "Address", + [ + ("id", models.AutoField(primary_key=True)), + ( + "tenant", + models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE), + ), + ], + ) + tenant = ModelState( + "b", + "Tenant", + [ + ("id", models.AutoField(primary_key=True)), + ("primary_address", models.ForeignKey("a.Address", models.CASCADE)), + ], + bases=(AbstractBaseUser,), ) changes = self.get_changes([], [address, tenant]) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'a', 2) - self.assertOperationTypes(changes, 'a', 0, ["CreateModel"]) - self.assertOperationTypes(changes, 'a', 1, ["AddField"]) - self.assertMigrationDependencies(changes, 'a', 0, []) - self.assertMigrationDependencies(changes, 'a', 1, [('__setting__', 'AUTH_USER_MODEL'), ('a', 'auto_1')]) + self.assertNumberMigrations(changes, "a", 2) + self.assertOperationTypes(changes, "a", 0, ["CreateModel"]) + self.assertOperationTypes(changes, "a", 1, ["AddField"]) + self.assertMigrationDependencies(changes, "a", 0, []) + self.assertMigrationDependencies( + changes, "a", 1, [("__setting__", "AUTH_USER_MODEL"), ("a", "auto_1")] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'b', 1) - self.assertOperationTypes(changes, 'b', 0, ["CreateModel"]) - self.assertMigrationDependencies(changes, 'b', 0, [('a', 'auto_1')]) + self.assertNumberMigrations(changes, "b", 1) + self.assertOperationTypes(changes, "b", 0, ["CreateModel"]) + self.assertMigrationDependencies(changes, "b", 0, [("a", "auto_1")]) @override_settings(AUTH_USER_MODEL="a.Person") def test_circular_dependency_swappable_self(self): @@ -2743,63 +4326,90 @@ class AutodetectorTests(TestCase): swappable models. """ with isolate_lru_cache(apps.get_swappable_settings_name): - person = ModelState("a", "Person", [ - ("id", models.AutoField(primary_key=True)), - ("parent1", models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE, related_name='children')) - ]) + person = ModelState( + "a", + "Person", + [ + ("id", models.AutoField(primary_key=True)), + ( + "parent1", + models.ForeignKey( + settings.AUTH_USER_MODEL, + models.CASCADE, + related_name="children", + ), + ), + ], + ) changes = self.get_changes([], [person]) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'a', 1) - self.assertOperationTypes(changes, 'a', 0, ["CreateModel"]) - self.assertMigrationDependencies(changes, 'a', 0, []) + self.assertNumberMigrations(changes, "a", 1) + self.assertOperationTypes(changes, "a", 0, ["CreateModel"]) + self.assertMigrationDependencies(changes, "a", 0, []) - @override_settings(AUTH_USER_MODEL='a.User') + @override_settings(AUTH_USER_MODEL="a.User") def test_swappable_circular_multi_mti(self): with isolate_lru_cache(apps.get_swappable_settings_name): - parent = ModelState('a', 'Parent', [ - ('user', models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE)) - ]) - child = ModelState('a', 'Child', [], bases=('a.Parent',)) - user = ModelState('a', 'User', [], bases=(AbstractBaseUser, 'a.Child')) + parent = ModelState( + "a", + "Parent", + [("user", models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE))], + ) + child = ModelState("a", "Child", [], bases=("a.Parent",)) + user = ModelState("a", "User", [], bases=(AbstractBaseUser, "a.Child")) changes = self.get_changes([], [parent, child, user]) - self.assertNumberMigrations(changes, 'a', 1) - self.assertOperationTypes(changes, 'a', 0, ['CreateModel', 'CreateModel', 'CreateModel', 'AddField']) + self.assertNumberMigrations(changes, "a", 1) + self.assertOperationTypes( + changes, "a", 0, ["CreateModel", "CreateModel", "CreateModel", "AddField"] + ) - @mock.patch('django.db.migrations.questioner.MigrationQuestioner.ask_not_null_addition', - side_effect=AssertionError("Should not have prompted for not null addition")) + @mock.patch( + "django.db.migrations.questioner.MigrationQuestioner.ask_not_null_addition", + side_effect=AssertionError("Should not have prompted for not null addition"), + ) def test_add_blank_textfield_and_charfield(self, mocked_ask_method): """ #23405 - Adding a NOT NULL and blank `CharField` or `TextField` without default should not prompt for a default. """ - changes = self.get_changes([self.author_empty], [self.author_with_biography_blank]) + changes = self.get_changes( + [self.author_empty], [self.author_with_biography_blank] + ) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AddField", "AddField"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["AddField", "AddField"]) + self.assertOperationAttributes(changes, "testapp", 0, 0) - @mock.patch('django.db.migrations.questioner.MigrationQuestioner.ask_not_null_addition') + @mock.patch( + "django.db.migrations.questioner.MigrationQuestioner.ask_not_null_addition" + ) def test_add_non_blank_textfield_and_charfield(self, mocked_ask_method): """ #23405 - Adding a NOT NULL and non-blank `CharField` or `TextField` without default should prompt for a default. """ - changes = self.get_changes([self.author_empty], [self.author_with_biography_non_blank]) + changes = self.get_changes( + [self.author_empty], [self.author_with_biography_non_blank] + ) self.assertEqual(mocked_ask_method.call_count, 2) # Right number/type of migrations? - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ["AddField", "AddField"]) - self.assertOperationAttributes(changes, 'testapp', 0, 0) + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["AddField", "AddField"]) + self.assertOperationAttributes(changes, "testapp", 0, 0) def test_mti_inheritance_model_removal(self): - Animal = ModelState('app', 'Animal', [ - ("id", models.AutoField(primary_key=True)), - ]) - Dog = ModelState('app', 'Dog', [], bases=('app.Animal',)) + Animal = ModelState( + "app", + "Animal", + [ + ("id", models.AutoField(primary_key=True)), + ], + ) + Dog = ModelState("app", "Dog", [], bases=("app.Animal",)) changes = self.get_changes([Animal, Dog], [Animal]) - self.assertNumberMigrations(changes, 'app', 1) - self.assertOperationTypes(changes, 'app', 0, ['DeleteModel']) - self.assertOperationAttributes(changes, 'app', 0, 0, name='Dog') + self.assertNumberMigrations(changes, "app", 1) + self.assertOperationTypes(changes, "app", 0, ["DeleteModel"]) + self.assertOperationAttributes(changes, "app", 0, 0, name="Dog") def test_add_model_with_field_removed_from_base_model(self): """ @@ -2807,37 +4417,52 @@ class AutodetectorTests(TestCase): that has a field with the same name. """ before = [ - ModelState('app', 'readable', [ - ('id', models.AutoField(primary_key=True)), - ('title', models.CharField(max_length=200)), - ]), + ModelState( + "app", + "readable", + [ + ("id", models.AutoField(primary_key=True)), + ("title", models.CharField(max_length=200)), + ], + ), ] after = [ - ModelState('app', 'readable', [ - ('id', models.AutoField(primary_key=True)), - ]), - ModelState('app', 'book', [ - ('title', models.CharField(max_length=200)), - ], bases=('app.readable',)), + ModelState( + "app", + "readable", + [ + ("id", models.AutoField(primary_key=True)), + ], + ), + ModelState( + "app", + "book", + [ + ("title", models.CharField(max_length=200)), + ], + bases=("app.readable",), + ), ] changes = self.get_changes(before, after) - self.assertNumberMigrations(changes, 'app', 1) - self.assertOperationTypes(changes, 'app', 0, ['RemoveField', 'CreateModel']) - self.assertOperationAttributes(changes, 'app', 0, 0, name='title', model_name='readable') - self.assertOperationAttributes(changes, 'app', 0, 1, name='book') + self.assertNumberMigrations(changes, "app", 1) + self.assertOperationTypes(changes, "app", 0, ["RemoveField", "CreateModel"]) + self.assertOperationAttributes( + changes, "app", 0, 0, name="title", model_name="readable" + ) + self.assertOperationAttributes(changes, "app", 0, 1, name="book") def test_parse_number(self): tests = [ - ('no_number', None), - ('0001_initial', 1), - ('0002_model3', 2), - ('0002_auto_20380101_1112', 2), - ('0002_squashed_0003', 3), - ('0002_model2_squashed_0003_other4', 3), - ('0002_squashed_0003_squashed_0004', 4), - ('0002_model2_squashed_0003_other4_squashed_0005_other6', 5), - ('0002_custom_name_20380101_1112_squashed_0003_model', 3), - ('2_squashed_4', 4), + ("no_number", None), + ("0001_initial", 1), + ("0002_model3", 2), + ("0002_auto_20380101_1112", 2), + ("0002_squashed_0003", 3), + ("0002_model2_squashed_0003_other4", 3), + ("0002_squashed_0003_squashed_0004", 4), + ("0002_model2_squashed_0003_other4_squashed_0005_other6", 5), + ("0002_custom_name_20380101_1112_squashed_0003_model", 3), + ("2_squashed_4", 4), ] for migration_name, expected_number in tests: with self.subTest(migration_name=migration_name): @@ -2849,24 +4474,28 @@ class AutodetectorTests(TestCase): def test_add_custom_fk_with_hardcoded_to(self): class HardcodedForeignKey(models.ForeignKey): def __init__(self, *args, **kwargs): - kwargs['to'] = 'testapp.Author' + kwargs["to"] = "testapp.Author" super().__init__(*args, **kwargs) def deconstruct(self): name, path, args, kwargs = super().deconstruct() - del kwargs['to'] + del kwargs["to"] return name, path, args, kwargs - book_hardcoded_fk_to = ModelState('testapp', 'Book', [ - ('author', HardcodedForeignKey(on_delete=models.CASCADE)), - ]) + book_hardcoded_fk_to = ModelState( + "testapp", + "Book", + [ + ("author", HardcodedForeignKey(on_delete=models.CASCADE)), + ], + ) changes = self.get_changes( [self.author_empty], [self.author_empty, book_hardcoded_fk_to], ) - self.assertNumberMigrations(changes, 'testapp', 1) - self.assertOperationTypes(changes, 'testapp', 0, ['CreateModel']) - self.assertOperationAttributes(changes, 'testapp', 0, 0, name='Book') + self.assertNumberMigrations(changes, "testapp", 1) + self.assertOperationTypes(changes, "testapp", 0, ["CreateModel"]) + self.assertOperationAttributes(changes, "testapp", 0, 0, name="Book") class MigrationSuggestNameTests(SimpleTestCase): @@ -2874,111 +4503,111 @@ class MigrationSuggestNameTests(SimpleTestCase): class Migration(migrations.Migration): operations = [] - migration = Migration('some_migration', 'test_app') - self.assertIs(migration.suggest_name().startswith('auto_'), True) + migration = Migration("some_migration", "test_app") + self.assertIs(migration.suggest_name().startswith("auto_"), True) def test_no_operations_initial(self): class Migration(migrations.Migration): initial = True operations = [] - migration = Migration('some_migration', 'test_app') - self.assertEqual(migration.suggest_name(), 'initial') + migration = Migration("some_migration", "test_app") + self.assertEqual(migration.suggest_name(), "initial") def test_single_operation(self): class Migration(migrations.Migration): - operations = [migrations.CreateModel('Person', fields=[])] + operations = [migrations.CreateModel("Person", fields=[])] - migration = Migration('0001_initial', 'test_app') - self.assertEqual(migration.suggest_name(), 'person') + migration = Migration("0001_initial", "test_app") + self.assertEqual(migration.suggest_name(), "person") class Migration(migrations.Migration): - operations = [migrations.DeleteModel('Person')] + operations = [migrations.DeleteModel("Person")] - migration = Migration('0002_initial', 'test_app') - self.assertEqual(migration.suggest_name(), 'delete_person') + migration = Migration("0002_initial", "test_app") + self.assertEqual(migration.suggest_name(), "delete_person") def test_single_operation_long_name(self): class Migration(migrations.Migration): - operations = [migrations.CreateModel('A' * 53, fields=[])] + operations = [migrations.CreateModel("A" * 53, fields=[])] - migration = Migration('some_migration', 'test_app') - self.assertEqual(migration.suggest_name(), 'a' * 53) + migration = Migration("some_migration", "test_app") + self.assertEqual(migration.suggest_name(), "a" * 53) def test_two_operations(self): class Migration(migrations.Migration): operations = [ - migrations.CreateModel('Person', fields=[]), - migrations.DeleteModel('Animal'), + migrations.CreateModel("Person", fields=[]), + migrations.DeleteModel("Animal"), ] - migration = Migration('some_migration', 'test_app') - self.assertEqual(migration.suggest_name(), 'person_delete_animal') + migration = Migration("some_migration", "test_app") + self.assertEqual(migration.suggest_name(), "person_delete_animal") def test_two_create_models(self): class Migration(migrations.Migration): operations = [ - migrations.CreateModel('Person', fields=[]), - migrations.CreateModel('Animal', fields=[]), + migrations.CreateModel("Person", fields=[]), + migrations.CreateModel("Animal", fields=[]), ] - migration = Migration('0001_initial', 'test_app') - self.assertEqual(migration.suggest_name(), 'person_animal') + migration = Migration("0001_initial", "test_app") + self.assertEqual(migration.suggest_name(), "person_animal") def test_two_create_models_with_initial_true(self): class Migration(migrations.Migration): initial = True operations = [ - migrations.CreateModel('Person', fields=[]), - migrations.CreateModel('Animal', fields=[]), + migrations.CreateModel("Person", fields=[]), + migrations.CreateModel("Animal", fields=[]), ] - migration = Migration('0001_initial', 'test_app') - self.assertEqual(migration.suggest_name(), 'initial') + migration = Migration("0001_initial", "test_app") + self.assertEqual(migration.suggest_name(), "initial") def test_many_operations_suffix(self): class Migration(migrations.Migration): operations = [ - migrations.CreateModel('Person1', fields=[]), - migrations.CreateModel('Person2', fields=[]), - migrations.CreateModel('Person3', fields=[]), - migrations.DeleteModel('Person4'), - migrations.DeleteModel('Person5'), + migrations.CreateModel("Person1", fields=[]), + migrations.CreateModel("Person2", fields=[]), + migrations.CreateModel("Person3", fields=[]), + migrations.DeleteModel("Person4"), + migrations.DeleteModel("Person5"), ] - migration = Migration('some_migration', 'test_app') + migration = Migration("some_migration", "test_app") self.assertEqual( migration.suggest_name(), - 'person1_person2_person3_delete_person4_and_more', + "person1_person2_person3_delete_person4_and_more", ) def test_operation_with_no_suggested_name(self): class Migration(migrations.Migration): operations = [ - migrations.CreateModel('Person', fields=[]), - migrations.RunSQL('SELECT 1 FROM person;'), + migrations.CreateModel("Person", fields=[]), + migrations.RunSQL("SELECT 1 FROM person;"), ] - migration = Migration('some_migration', 'test_app') - self.assertIs(migration.suggest_name().startswith('auto_'), True) + migration = Migration("some_migration", "test_app") + self.assertIs(migration.suggest_name().startswith("auto_"), True) def test_none_name(self): class Migration(migrations.Migration): - operations = [migrations.RunSQL('SELECT 1 FROM person;')] + operations = [migrations.RunSQL("SELECT 1 FROM person;")] - migration = Migration('0001_initial', 'test_app') + migration = Migration("0001_initial", "test_app") suggest_name = migration.suggest_name() - self.assertIs(suggest_name.startswith('auto_'), True) + self.assertIs(suggest_name.startswith("auto_"), True) def test_none_name_with_initial_true(self): class Migration(migrations.Migration): initial = True - operations = [migrations.RunSQL('SELECT 1 FROM person;')] + operations = [migrations.RunSQL("SELECT 1 FROM person;")] - migration = Migration('0001_initial', 'test_app') - self.assertEqual(migration.suggest_name(), 'initial') + migration = Migration("0001_initial", "test_app") + self.assertEqual(migration.suggest_name(), "initial") def test_auto(self): - migration = migrations.Migration('0001_initial', 'test_app') + migration = migrations.Migration("0001_initial", "test_app") suggest_name = migration.suggest_name() - self.assertIs(suggest_name.startswith('auto_'), True) + self.assertIs(suggest_name.startswith("auto_"), True) diff --git a/tests/migrations/test_base.py b/tests/migrations/test_base.py index 6f8081a462..955bfa99d0 100644 --- a/tests/migrations/test_base.py +++ b/tests/migrations/test_base.py @@ -20,52 +20,66 @@ class MigrationTestBase(TransactionTestCase): """ available_apps = ["migrations"] - databases = {'default', 'other'} + databases = {"default", "other"} def tearDown(self): # Reset applied-migrations state. for db in self.databases: recorder = MigrationRecorder(connections[db]) - recorder.migration_qs.filter(app='migrations').delete() + recorder.migration_qs.filter(app="migrations").delete() - def get_table_description(self, table, using='default'): + def get_table_description(self, table, using="default"): with connections[using].cursor() as cursor: return connections[using].introspection.get_table_description(cursor, table) - def assertTableExists(self, table, using='default'): + def assertTableExists(self, table, using="default"): with connections[using].cursor() as cursor: self.assertIn(table, connections[using].introspection.table_names(cursor)) - def assertTableNotExists(self, table, using='default'): + def assertTableNotExists(self, table, using="default"): with connections[using].cursor() as cursor: - self.assertNotIn(table, connections[using].introspection.table_names(cursor)) + self.assertNotIn( + table, connections[using].introspection.table_names(cursor) + ) - def assertColumnExists(self, table, column, using='default'): - self.assertIn(column, [c.name for c in self.get_table_description(table, using=using)]) + def assertColumnExists(self, table, column, using="default"): + self.assertIn( + column, [c.name for c in self.get_table_description(table, using=using)] + ) - def assertColumnNotExists(self, table, column, using='default'): - self.assertNotIn(column, [c.name for c in self.get_table_description(table, using=using)]) + def assertColumnNotExists(self, table, column, using="default"): + self.assertNotIn( + column, [c.name for c in self.get_table_description(table, using=using)] + ) def _get_column_allows_null(self, table, column, using): - return [c.null_ok for c in self.get_table_description(table, using=using) if c.name == column][0] + return [ + c.null_ok + for c in self.get_table_description(table, using=using) + if c.name == column + ][0] - def assertColumnNull(self, table, column, using='default'): + def assertColumnNull(self, table, column, using="default"): self.assertTrue(self._get_column_allows_null(table, column, using)) - def assertColumnNotNull(self, table, column, using='default'): + def assertColumnNotNull(self, table, column, using="default"): self.assertFalse(self._get_column_allows_null(table, column, using)) - def assertIndexExists(self, table, columns, value=True, using='default', index_type=None): + def assertIndexExists( + self, table, columns, value=True, using="default", index_type=None + ): with connections[using].cursor() as cursor: self.assertEqual( value, any( c["index"] - for c in connections[using].introspection.get_constraints(cursor, table).values() + for c in connections[using] + .introspection.get_constraints(cursor, table) + .values() if ( - c['columns'] == list(columns) and - (index_type is None or c['type'] == index_type) and - not c['unique'] + c["columns"] == list(columns) + and (index_type is None or c["type"] == index_type) + and not c["unique"] ) ), ) @@ -73,47 +87,53 @@ class MigrationTestBase(TransactionTestCase): def assertIndexNotExists(self, table, columns): return self.assertIndexExists(table, columns, False) - def assertIndexNameExists(self, table, index, using='default'): + def assertIndexNameExists(self, table, index, using="default"): with connections[using].cursor() as cursor: self.assertIn( index, connection.introspection.get_constraints(cursor, table), ) - def assertIndexNameNotExists(self, table, index, using='default'): + def assertIndexNameNotExists(self, table, index, using="default"): with connections[using].cursor() as cursor: self.assertNotIn( index, connection.introspection.get_constraints(cursor, table), ) - def assertConstraintExists(self, table, name, value=True, using='default'): + def assertConstraintExists(self, table, name, value=True, using="default"): with connections[using].cursor() as cursor: - constraints = connections[using].introspection.get_constraints(cursor, table).items() + constraints = ( + connections[using].introspection.get_constraints(cursor, table).items() + ) self.assertEqual( value, - any(c['check'] for n, c in constraints if n == name), + any(c["check"] for n, c in constraints if n == name), ) def assertConstraintNotExists(self, table, name): return self.assertConstraintExists(table, name, False) - def assertUniqueConstraintExists(self, table, columns, value=True, using='default'): + def assertUniqueConstraintExists(self, table, columns, value=True, using="default"): with connections[using].cursor() as cursor: - constraints = connections[using].introspection.get_constraints(cursor, table).values() + constraints = ( + connections[using].introspection.get_constraints(cursor, table).values() + ) self.assertEqual( value, - any(c['unique'] for c in constraints if c['columns'] == list(columns)), + any(c["unique"] for c in constraints if c["columns"] == list(columns)), ) - def assertFKExists(self, table, columns, to, value=True, using='default'): + def assertFKExists(self, table, columns, to, value=True, using="default"): with connections[using].cursor() as cursor: self.assertEqual( value, any( c["foreign_key"] == to - for c in connections[using].introspection.get_constraints(cursor, table).values() - if c['columns'] == list(columns) + for c in connections[using] + .introspection.get_constraints(cursor, table) + .values() + if c["columns"] == list(columns) ), ) @@ -121,7 +141,7 @@ class MigrationTestBase(TransactionTestCase): return self.assertFKExists(table, columns, to, False) @contextmanager - def temporary_migration_module(self, app_label='migrations', module=None): + def temporary_migration_module(self, app_label="migrations", module=None): """ Allows testing management commands in a temporary migrations module. @@ -140,12 +160,12 @@ class MigrationTestBase(TransactionTestCase): """ with tempfile.TemporaryDirectory() as temp_dir: target_dir = tempfile.mkdtemp(dir=temp_dir) - with open(os.path.join(target_dir, '__init__.py'), 'w'): + with open(os.path.join(target_dir, "__init__.py"), "w"): pass - target_migrations_dir = os.path.join(target_dir, 'migrations') + target_migrations_dir = os.path.join(target_dir, "migrations") if module is None: - module = apps.get_app_config(app_label).name + '.migrations' + module = apps.get_app_config(app_label).name + ".migrations" try: source_migrations_dir = module_dir(import_module(module)) @@ -155,7 +175,7 @@ class MigrationTestBase(TransactionTestCase): shutil.copytree(source_migrations_dir, target_migrations_dir) with extend_sys_path(temp_dir): - new_module = os.path.basename(target_dir) + '.migrations' + new_module = os.path.basename(target_dir) + ".migrations" with self.settings(MIGRATION_MODULES={app_label: new_module}): yield target_migrations_dir @@ -173,22 +193,28 @@ class OperationTestBase(MigrationTestBase): super().tearDown() def cleanup_test_tables(self): - table_names = frozenset(connection.introspection.table_names()) - self._initial_table_names + table_names = ( + frozenset(connection.introspection.table_names()) + - self._initial_table_names + ) with connection.schema_editor() as editor: with connection.constraint_checks_disabled(): for table_name in table_names: - editor.execute(editor.sql_delete_table % { - 'table': editor.quote_name(table_name), - }) + editor.execute( + editor.sql_delete_table + % { + "table": editor.quote_name(table_name), + } + ) def apply_operations(self, app_label, project_state, operations, atomic=True): - migration = Migration('name', app_label) + migration = Migration("name", app_label) migration.operations = operations with connection.schema_editor(atomic=atomic) as editor: return migration.apply(project_state, editor) def unapply_operations(self, app_label, project_state, operations, atomic=True): - migration = Migration('name', app_label) + migration = Migration("name", app_label) migration.operations = operations with connection.schema_editor(atomic=atomic) as editor: return migration.unapply(project_state, editor) @@ -204,106 +230,142 @@ class OperationTestBase(MigrationTestBase): return project_state, new_state def set_up_test_model( - self, app_label, second_model=False, third_model=False, index=False, - multicol_index=False, related_model=False, mti_model=False, - proxy_model=False, manager_model=False, unique_together=False, - options=False, db_table=None, index_together=False, constraints=None, + self, + app_label, + second_model=False, + third_model=False, + index=False, + multicol_index=False, + related_model=False, + mti_model=False, + proxy_model=False, + manager_model=False, + unique_together=False, + options=False, + db_table=None, + index_together=False, + constraints=None, indexes=None, ): """Creates a test model state and database table.""" # Make the "current" state. model_options = { - 'swappable': 'TEST_SWAP_MODEL', - 'index_together': [['weight', 'pink']] if index_together else [], - 'unique_together': [['pink', 'weight']] if unique_together else [], + "swappable": "TEST_SWAP_MODEL", + "index_together": [["weight", "pink"]] if index_together else [], + "unique_together": [["pink", "weight"]] if unique_together else [], } if options: - model_options['permissions'] = [('can_groom', 'Can groom')] + model_options["permissions"] = [("can_groom", "Can groom")] if db_table: - model_options['db_table'] = db_table - operations = [migrations.CreateModel( - 'Pony', - [ - ('id', models.AutoField(primary_key=True)), - ('pink', models.IntegerField(default=3)), - ('weight', models.FloatField()), - ], - options=model_options, - )] + model_options["db_table"] = db_table + operations = [ + migrations.CreateModel( + "Pony", + [ + ("id", models.AutoField(primary_key=True)), + ("pink", models.IntegerField(default=3)), + ("weight", models.FloatField()), + ], + options=model_options, + ) + ] if index: - operations.append(migrations.AddIndex( - 'Pony', - models.Index(fields=['pink'], name='pony_pink_idx'), - )) + operations.append( + migrations.AddIndex( + "Pony", + models.Index(fields=["pink"], name="pony_pink_idx"), + ) + ) if multicol_index: - operations.append(migrations.AddIndex( - 'Pony', - models.Index(fields=['pink', 'weight'], name='pony_test_idx'), - )) + operations.append( + migrations.AddIndex( + "Pony", + models.Index(fields=["pink", "weight"], name="pony_test_idx"), + ) + ) if indexes: for index in indexes: - operations.append(migrations.AddIndex('Pony', index)) + operations.append(migrations.AddIndex("Pony", index)) if constraints: for constraint in constraints: - operations.append(migrations.AddConstraint('Pony', constraint)) + operations.append(migrations.AddConstraint("Pony", constraint)) if second_model: - operations.append(migrations.CreateModel( - 'Stable', - [ - ('id', models.AutoField(primary_key=True)), - ] - )) + operations.append( + migrations.CreateModel( + "Stable", + [ + ("id", models.AutoField(primary_key=True)), + ], + ) + ) if third_model: - operations.append(migrations.CreateModel( - 'Van', - [ - ('id', models.AutoField(primary_key=True)), - ] - )) + operations.append( + migrations.CreateModel( + "Van", + [ + ("id", models.AutoField(primary_key=True)), + ], + ) + ) if related_model: - operations.append(migrations.CreateModel( - 'Rider', - [ - ('id', models.AutoField(primary_key=True)), - ('pony', models.ForeignKey('Pony', models.CASCADE)), - ('friend', models.ForeignKey('self', models.CASCADE, null=True)) - ], - )) + operations.append( + migrations.CreateModel( + "Rider", + [ + ("id", models.AutoField(primary_key=True)), + ("pony", models.ForeignKey("Pony", models.CASCADE)), + ( + "friend", + models.ForeignKey("self", models.CASCADE, null=True), + ), + ], + ) + ) if mti_model: - operations.append(migrations.CreateModel( - 'ShetlandPony', - fields=[ - ('pony_ptr', models.OneToOneField( - 'Pony', - models.CASCADE, - auto_created=True, - parent_link=True, - primary_key=True, - to_field='id', - serialize=False, - )), - ('cuteness', models.IntegerField(default=1)), - ], - bases=['%s.Pony' % app_label], - )) + operations.append( + migrations.CreateModel( + "ShetlandPony", + fields=[ + ( + "pony_ptr", + models.OneToOneField( + "Pony", + models.CASCADE, + auto_created=True, + parent_link=True, + primary_key=True, + to_field="id", + serialize=False, + ), + ), + ("cuteness", models.IntegerField(default=1)), + ], + bases=["%s.Pony" % app_label], + ) + ) if proxy_model: - operations.append(migrations.CreateModel( - 'ProxyPony', - fields=[], - options={'proxy': True}, - bases=['%s.Pony' % app_label], - )) + operations.append( + migrations.CreateModel( + "ProxyPony", + fields=[], + options={"proxy": True}, + bases=["%s.Pony" % app_label], + ) + ) if manager_model: from .models import FoodManager, FoodQuerySet - operations.append(migrations.CreateModel( - 'Food', - fields=[ - ('id', models.AutoField(primary_key=True)), - ], - managers=[ - ('food_qs', FoodQuerySet.as_manager()), - ('food_mgr', FoodManager('a', 'b')), - ('food_mgr_kwargs', FoodManager('x', 'y', 3, 4)), - ] - )) + + operations.append( + migrations.CreateModel( + "Food", + fields=[ + ("id", models.AutoField(primary_key=True)), + ], + managers=[ + ("food_qs", FoodQuerySet.as_manager()), + ("food_mgr", FoodManager("a", "b")), + ("food_mgr_kwargs", FoodManager("x", "y", 3, 4)), + ], + ) + ) return self.apply_operations(app_label, ProjectState(), operations) diff --git a/tests/migrations/test_commands.py b/tests/migrations/test_commands.py index 0c62db8ae6..099690aa30 100644 --- a/tests/migrations/test_commands.py +++ b/tests/migrations/test_commands.py @@ -8,8 +8,12 @@ from unittest import mock from django.apps import apps from django.core.management import CommandError, call_command from django.db import ( - ConnectionHandler, DatabaseError, OperationalError, connection, - connections, models, + ConnectionHandler, + DatabaseError, + OperationalError, + connection, + connections, + models, ) from django.db.backends.base.schema import BaseDatabaseSchemaEditor from django.db.backends.utils import truncate_name @@ -29,7 +33,8 @@ class MigrateTests(MigrationTestBase): """ Tests running the migrate command. """ - databases = {'default', 'other'} + + databases = {"default", "other"} @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"}) def test_migrate(self): @@ -42,12 +47,18 @@ class MigrateTests(MigrationTestBase): self.assertTableNotExists("migrations_book") # Run the migrations to 0001 only stdout = io.StringIO() - call_command('migrate', 'migrations', '0001', verbosity=2, stdout=stdout, no_color=True) + call_command( + "migrate", "migrations", "0001", verbosity=2, stdout=stdout, no_color=True + ) stdout = stdout.getvalue() - self.assertIn('Target specific migration: 0001_initial, from migrations', stdout) - self.assertIn('Applying migrations.0001_initial... OK', stdout) - self.assertIn('Running pre-migrate handlers for application migrations', stdout) - self.assertIn('Running post-migrate handlers for application migrations', stdout) + self.assertIn( + "Target specific migration: 0001_initial, from migrations", stdout + ) + self.assertIn("Applying migrations.0001_initial... OK", stdout) + self.assertIn("Running pre-migrate handlers for application migrations", stdout) + self.assertIn( + "Running post-migrate handlers for application migrations", stdout + ) # The correct tables exist self.assertTableExists("migrations_author") self.assertTableExists("migrations_tribble") @@ -60,49 +71,66 @@ class MigrateTests(MigrationTestBase): self.assertTableExists("migrations_book") # Unmigrate everything stdout = io.StringIO() - call_command('migrate', 'migrations', 'zero', verbosity=2, stdout=stdout, no_color=True) + call_command( + "migrate", "migrations", "zero", verbosity=2, stdout=stdout, no_color=True + ) stdout = stdout.getvalue() - self.assertIn('Unapply all migrations: migrations', stdout) - self.assertIn('Unapplying migrations.0002_second... OK', stdout) - self.assertIn('Running pre-migrate handlers for application migrations', stdout) - self.assertIn('Running post-migrate handlers for application migrations', stdout) + self.assertIn("Unapply all migrations: migrations", stdout) + self.assertIn("Unapplying migrations.0002_second... OK", stdout) + self.assertIn("Running pre-migrate handlers for application migrations", stdout) + self.assertIn( + "Running post-migrate handlers for application migrations", stdout + ) # Tables are gone self.assertTableNotExists("migrations_author") self.assertTableNotExists("migrations_tribble") self.assertTableNotExists("migrations_book") - @override_settings(INSTALLED_APPS=[ - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'migrations.migrations_test_apps.migrated_app', - ]) + @override_settings( + INSTALLED_APPS=[ + "django.contrib.auth", + "django.contrib.contenttypes", + "migrations.migrations_test_apps.migrated_app", + ] + ) def test_migrate_with_system_checks(self): out = io.StringIO() - call_command('migrate', skip_checks=False, no_color=True, stdout=out) - self.assertIn('Apply all migrations: migrated_app', out.getvalue()) + call_command("migrate", skip_checks=False, no_color=True, stdout=out) + self.assertIn("Apply all migrations: migrated_app", out.getvalue()) - @override_settings(INSTALLED_APPS=['migrations', 'migrations.migrations_test_apps.unmigrated_app_syncdb']) + @override_settings( + INSTALLED_APPS=[ + "migrations", + "migrations.migrations_test_apps.unmigrated_app_syncdb", + ] + ) def test_app_without_migrations(self): msg = "App 'unmigrated_app_syncdb' does not have migrations." with self.assertRaisesMessage(CommandError, msg): - call_command('migrate', app_label='unmigrated_app_syncdb') + call_command("migrate", app_label="unmigrated_app_syncdb") - @override_settings(MIGRATION_MODULES={'migrations': 'migrations.test_migrations_clashing_prefix'}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_clashing_prefix"} + ) def test_ambiguous_prefix(self): msg = ( "More than one migration matches 'a' in app 'migrations'. Please " "be more specific." ) with self.assertRaisesMessage(CommandError, msg): - call_command('migrate', app_label='migrations', migration_name='a') + call_command("migrate", app_label="migrations", migration_name="a") - @override_settings(MIGRATION_MODULES={'migrations': 'migrations.test_migrations'}) + @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"}) def test_unknown_prefix(self): msg = "Cannot find a migration matching 'nonexistent' from app 'migrations'." with self.assertRaisesMessage(CommandError, msg): - call_command('migrate', app_label='migrations', migration_name='nonexistent') + call_command( + "migrate", app_label="migrations", migration_name="nonexistent" + ) - @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_initial_false"}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_initial_false"} + ) def test_migrate_initial_false(self): """ `Migration.initial = False` skips fake-initial detection. @@ -116,7 +144,9 @@ class MigrateTests(MigrationTestBase): call_command("migrate", "migrations", "zero", fake=True, verbosity=0) # Make sure fake-initial detection does not run with self.assertRaises(DatabaseError): - call_command("migrate", "migrations", "0001", fake_initial=True, verbosity=0) + call_command( + "migrate", "migrations", "0001", fake_initial=True, verbosity=0 + ) call_command("migrate", "migrations", "0001", fake=True, verbosity=0) # Real rollback @@ -128,7 +158,7 @@ class MigrateTests(MigrationTestBase): @override_settings( MIGRATION_MODULES={"migrations": "migrations.test_migrations"}, - DATABASE_ROUTERS=['migrations.routers.TestRouter'], + DATABASE_ROUTERS=["migrations.routers.TestRouter"], ) def test_migrate_fake_initial(self): """ @@ -152,7 +182,9 @@ class MigrateTests(MigrationTestBase): # Fake a roll-back call_command("migrate", "migrations", "zero", fake=True, verbosity=0) - call_command("migrate", "migrations", "zero", fake=True, verbosity=0, database="other") + call_command( + "migrate", "migrations", "zero", fake=True, verbosity=0, database="other" + ) # Make sure the tables still exist self.assertTableExists("migrations_author") self.assertTableExists("migrations_tribble", using="other") @@ -161,97 +193,138 @@ class MigrateTests(MigrationTestBase): call_command("migrate", "migrations", "0001", verbosity=0) # Run initial migration with an explicit --fake-initial out = io.StringIO() - with mock.patch('django.core.management.color.supports_color', lambda *args: False): - call_command("migrate", "migrations", "0001", fake_initial=True, stdout=out, verbosity=1) - call_command("migrate", "migrations", "0001", fake_initial=True, verbosity=0, database="other") - self.assertIn( - "migrations.0001_initial... faked", - out.getvalue().lower() - ) + with mock.patch( + "django.core.management.color.supports_color", lambda *args: False + ): + call_command( + "migrate", + "migrations", + "0001", + fake_initial=True, + stdout=out, + verbosity=1, + ) + call_command( + "migrate", + "migrations", + "0001", + fake_initial=True, + verbosity=0, + database="other", + ) + self.assertIn("migrations.0001_initial... faked", out.getvalue().lower()) try: # Run migrations all the way. - call_command('migrate', verbosity=0) - call_command('migrate', verbosity=0, database="other") - self.assertTableExists('migrations_author') - self.assertTableNotExists('migrations_tribble') - self.assertTableExists('migrations_book') - self.assertTableNotExists('migrations_author', using='other') - self.assertTableNotExists('migrations_tribble', using='other') - self.assertTableNotExists('migrations_book', using='other') + call_command("migrate", verbosity=0) + call_command("migrate", verbosity=0, database="other") + self.assertTableExists("migrations_author") + self.assertTableNotExists("migrations_tribble") + self.assertTableExists("migrations_book") + self.assertTableNotExists("migrations_author", using="other") + self.assertTableNotExists("migrations_tribble", using="other") + self.assertTableNotExists("migrations_book", using="other") # Fake a roll-back. - call_command('migrate', 'migrations', 'zero', fake=True, verbosity=0) - call_command('migrate', 'migrations', 'zero', fake=True, verbosity=0, database='other') - self.assertTableExists('migrations_author') - self.assertTableNotExists('migrations_tribble') - self.assertTableExists('migrations_book') + call_command("migrate", "migrations", "zero", fake=True, verbosity=0) + call_command( + "migrate", + "migrations", + "zero", + fake=True, + verbosity=0, + database="other", + ) + self.assertTableExists("migrations_author") + self.assertTableNotExists("migrations_tribble") + self.assertTableExists("migrations_book") # Run initial migration. with self.assertRaises(DatabaseError): - call_command('migrate', 'migrations', verbosity=0) + call_command("migrate", "migrations", verbosity=0) # Run initial migration with an explicit --fake-initial. with self.assertRaises(DatabaseError): # Fails because "migrations_tribble" does not exist but needs # to in order to make --fake-initial work. - call_command('migrate', 'migrations', fake_initial=True, verbosity=0) + call_command("migrate", "migrations", fake_initial=True, verbosity=0) # Fake an apply. - call_command('migrate', 'migrations', fake=True, verbosity=0) - call_command('migrate', 'migrations', fake=True, verbosity=0, database='other') + call_command("migrate", "migrations", fake=True, verbosity=0) + call_command( + "migrate", "migrations", fake=True, verbosity=0, database="other" + ) finally: # Unmigrate everything. - call_command('migrate', 'migrations', 'zero', verbosity=0) - call_command('migrate', 'migrations', 'zero', verbosity=0, database='other') + call_command("migrate", "migrations", "zero", verbosity=0) + call_command("migrate", "migrations", "zero", verbosity=0, database="other") # Make sure it's all gone for db in self.databases: self.assertTableNotExists("migrations_author", using=db) self.assertTableNotExists("migrations_tribble", using=db) self.assertTableNotExists("migrations_book", using=db) - @skipUnlessDBFeature('ignores_table_name_case') + @skipUnlessDBFeature("ignores_table_name_case") def test_migrate_fake_initial_case_insensitive(self): - with override_settings(MIGRATION_MODULES={ - 'migrations': 'migrations.test_fake_initial_case_insensitive.initial', - }): - call_command('migrate', 'migrations', '0001', verbosity=0) - call_command('migrate', 'migrations', 'zero', fake=True, verbosity=0) + with override_settings( + MIGRATION_MODULES={ + "migrations": "migrations.test_fake_initial_case_insensitive.initial", + } + ): + call_command("migrate", "migrations", "0001", verbosity=0) + call_command("migrate", "migrations", "zero", fake=True, verbosity=0) - with override_settings(MIGRATION_MODULES={ - 'migrations': 'migrations.test_fake_initial_case_insensitive.fake_initial', - }): + with override_settings( + MIGRATION_MODULES={ + "migrations": "migrations.test_fake_initial_case_insensitive.fake_initial", + } + ): out = io.StringIO() call_command( - 'migrate', - 'migrations', - '0001', + "migrate", + "migrations", + "0001", fake_initial=True, stdout=out, verbosity=1, no_color=True, ) self.assertIn( - 'migrations.0001_initial... faked', + "migrations.0001_initial... faked", out.getvalue().lower(), ) - @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_fake_split_initial"}) + @override_settings( + MIGRATION_MODULES={ + "migrations": "migrations.test_migrations_fake_split_initial" + } + ) def test_migrate_fake_split_initial(self): """ Split initial migrations can be faked with --fake-initial. """ try: - call_command('migrate', 'migrations', '0002', verbosity=0) - call_command('migrate', 'migrations', 'zero', fake=True, verbosity=0) + call_command("migrate", "migrations", "0002", verbosity=0) + call_command("migrate", "migrations", "zero", fake=True, verbosity=0) out = io.StringIO() - with mock.patch('django.core.management.color.supports_color', lambda *args: False): - call_command('migrate', 'migrations', '0002', fake_initial=True, stdout=out, verbosity=1) + with mock.patch( + "django.core.management.color.supports_color", lambda *args: False + ): + call_command( + "migrate", + "migrations", + "0002", + fake_initial=True, + stdout=out, + verbosity=1, + ) value = out.getvalue().lower() - self.assertIn('migrations.0001_initial... faked', value) - self.assertIn('migrations.0002_second... faked', value) + self.assertIn("migrations.0001_initial... faked", value) + self.assertIn("migrations.0002_second... faked", value) finally: # Fake an apply. - call_command('migrate', 'migrations', fake=True, verbosity=0) + call_command("migrate", "migrations", fake=True, verbosity=0) # Unmigrate everything. - call_command('migrate', 'migrations', 'zero', verbosity=0) + call_command("migrate", "migrations", "zero", verbosity=0) - @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_conflict"}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_conflict"} + ) def test_migrate_conflict_exit(self): """ migrate exits if it detects a conflict. @@ -265,36 +338,40 @@ class MigrateTests(MigrationTestBase): with self.assertRaisesMessage(CommandError, msg): call_command("migrate", "migrations") - @override_settings(MIGRATION_MODULES={ - 'migrations': 'migrations.test_migrations', - }) + @override_settings( + MIGRATION_MODULES={ + "migrations": "migrations.test_migrations", + } + ) def test_migrate_check(self): with self.assertRaises(SystemExit): - call_command('migrate', 'migrations', '0001', check_unapplied=True) - self.assertTableNotExists('migrations_author') - self.assertTableNotExists('migrations_tribble') - self.assertTableNotExists('migrations_book') + call_command("migrate", "migrations", "0001", check_unapplied=True) + self.assertTableNotExists("migrations_author") + self.assertTableNotExists("migrations_tribble") + self.assertTableNotExists("migrations_book") - @override_settings(MIGRATION_MODULES={ - 'migrations': 'migrations.test_migrations_plan', - }) + @override_settings( + MIGRATION_MODULES={ + "migrations": "migrations.test_migrations_plan", + } + ) def test_migrate_check_plan(self): out = io.StringIO() with self.assertRaises(SystemExit): call_command( - 'migrate', - 'migrations', - '0001', + "migrate", + "migrations", + "0001", check_unapplied=True, plan=True, stdout=out, no_color=True, ) self.assertEqual( - 'Planned operations:\n' - 'migrations.0001_initial\n' - ' Create model Salamander\n' - ' Raw Python operation -> Grow salamander tail.\n', + "Planned operations:\n" + "migrations.0001_initial\n" + " Create model Salamander\n" + " Raw Python operation -> Grow salamander tail.\n", out.getvalue(), ) @@ -305,333 +382,387 @@ class MigrateTests(MigrationTestBase): applied. """ out = io.StringIO() - with mock.patch('django.core.management.color.supports_color', lambda *args: True): - call_command("showmigrations", format='list', stdout=out, verbosity=0, no_color=False) + with mock.patch( + "django.core.management.color.supports_color", lambda *args: True + ): + call_command( + "showmigrations", format="list", stdout=out, verbosity=0, no_color=False + ) self.assertEqual( - '\x1b[1mmigrations\n\x1b[0m [ ] 0001_initial\n [ ] 0002_second\n', - out.getvalue().lower() + "\x1b[1mmigrations\n\x1b[0m [ ] 0001_initial\n [ ] 0002_second\n", + out.getvalue().lower(), ) call_command("migrate", "migrations", "0001", verbosity=0) out = io.StringIO() # Giving the explicit app_label tests for selective `show_list` in the command - call_command("showmigrations", "migrations", format='list', stdout=out, verbosity=0, no_color=True) + call_command( + "showmigrations", + "migrations", + format="list", + stdout=out, + verbosity=0, + no_color=True, + ) self.assertEqual( - 'migrations\n [x] 0001_initial\n [ ] 0002_second\n', - out.getvalue().lower() + "migrations\n [x] 0001_initial\n [ ] 0002_second\n", out.getvalue().lower() ) out = io.StringIO() # Applied datetimes are displayed at verbosity 2+. - call_command('showmigrations', 'migrations', stdout=out, verbosity=2, no_color=True) - migration1 = MigrationRecorder(connection).migration_qs.get(app='migrations', name='0001_initial') + call_command( + "showmigrations", "migrations", stdout=out, verbosity=2, no_color=True + ) + migration1 = MigrationRecorder(connection).migration_qs.get( + app="migrations", name="0001_initial" + ) self.assertEqual( - 'migrations\n' - ' [x] 0001_initial (applied at %s)\n' - ' [ ] 0002_second\n' % migration1.applied.strftime('%Y-%m-%d %H:%M:%S'), - out.getvalue().lower() + "migrations\n" + " [x] 0001_initial (applied at %s)\n" + " [ ] 0002_second\n" % migration1.applied.strftime("%Y-%m-%d %H:%M:%S"), + out.getvalue().lower(), ) # Cleanup by unmigrating everything call_command("migrate", "migrations", "zero", verbosity=0) - @override_settings(MIGRATION_MODULES={'migrations': 'migrations.test_migrations_squashed'}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"} + ) def test_showmigrations_list_squashed(self): out = io.StringIO() - call_command('showmigrations', format='list', stdout=out, verbosity=2, no_color=True) + call_command( + "showmigrations", format="list", stdout=out, verbosity=2, no_color=True + ) self.assertEqual( - 'migrations\n [ ] 0001_squashed_0002 (2 squashed migrations)\n', + "migrations\n [ ] 0001_squashed_0002 (2 squashed migrations)\n", out.getvalue().lower(), ) out = io.StringIO() call_command( - 'migrate', - 'migrations', - '0001_squashed_0002', + "migrate", + "migrations", + "0001_squashed_0002", stdout=out, verbosity=2, no_color=True, ) try: self.assertIn( - 'operations to perform:\n' - ' target specific migration: 0001_squashed_0002, from migrations\n' - 'running pre-migrate handlers for application migrations\n' - 'running migrations:\n' - ' applying migrations.0001_squashed_0002... ok (', + "operations to perform:\n" + " target specific migration: 0001_squashed_0002, from migrations\n" + "running pre-migrate handlers for application migrations\n" + "running migrations:\n" + " applying migrations.0001_squashed_0002... ok (", out.getvalue().lower(), ) out = io.StringIO() - call_command('showmigrations', format='list', stdout=out, verbosity=2, no_color=True) + call_command( + "showmigrations", format="list", stdout=out, verbosity=2, no_color=True + ) self.assertEqual( - 'migrations\n [x] 0001_squashed_0002 (2 squashed migrations)\n', + "migrations\n [x] 0001_squashed_0002 (2 squashed migrations)\n", out.getvalue().lower(), ) finally: # Unmigrate everything. - call_command('migrate', 'migrations', 'zero', verbosity=0) + call_command("migrate", "migrations", "zero", verbosity=0) - @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_run_before"}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_run_before"} + ) def test_showmigrations_plan(self): """ Tests --plan output of showmigrations command """ out = io.StringIO() - call_command("showmigrations", format='plan', stdout=out) + call_command("showmigrations", format="plan", stdout=out) self.assertEqual( "[ ] migrations.0001_initial\n" "[ ] migrations.0003_third\n" "[ ] migrations.0002_second\n", - out.getvalue().lower() + out.getvalue().lower(), ) out = io.StringIO() - call_command("showmigrations", format='plan', stdout=out, verbosity=2) + call_command("showmigrations", format="plan", stdout=out, verbosity=2) self.assertEqual( "[ ] migrations.0001_initial\n" "[ ] migrations.0003_third ... (migrations.0001_initial)\n" "[ ] migrations.0002_second ... (migrations.0001_initial, migrations.0003_third)\n", - out.getvalue().lower() + out.getvalue().lower(), ) call_command("migrate", "migrations", "0003", verbosity=0) out = io.StringIO() - call_command("showmigrations", format='plan', stdout=out) + call_command("showmigrations", format="plan", stdout=out) self.assertEqual( "[x] migrations.0001_initial\n" "[x] migrations.0003_third\n" "[ ] migrations.0002_second\n", - out.getvalue().lower() + out.getvalue().lower(), ) out = io.StringIO() - call_command("showmigrations", format='plan', stdout=out, verbosity=2) + call_command("showmigrations", format="plan", stdout=out, verbosity=2) self.assertEqual( "[x] migrations.0001_initial\n" "[x] migrations.0003_third ... (migrations.0001_initial)\n" "[ ] migrations.0002_second ... (migrations.0001_initial, migrations.0003_third)\n", - out.getvalue().lower() + out.getvalue().lower(), ) # Cleanup by unmigrating everything call_command("migrate", "migrations", "zero", verbosity=0) - @override_settings(MIGRATION_MODULES={'migrations': 'migrations.test_migrations_plan'}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_plan"} + ) def test_migrate_plan(self): """Tests migrate --plan output.""" out = io.StringIO() # Show the plan up to the third migration. - call_command('migrate', 'migrations', '0003', plan=True, stdout=out, no_color=True) + call_command( + "migrate", "migrations", "0003", plan=True, stdout=out, no_color=True + ) self.assertEqual( - 'Planned operations:\n' - 'migrations.0001_initial\n' - ' Create model Salamander\n' - ' Raw Python operation -> Grow salamander tail.\n' - 'migrations.0002_second\n' - ' Create model Book\n' + "Planned operations:\n" + "migrations.0001_initial\n" + " Create model Salamander\n" + " Raw Python operation -> Grow salamander tail.\n" + "migrations.0002_second\n" + " Create model Book\n" " Raw SQL operation -> ['SELECT * FROM migrations_book']\n" - 'migrations.0003_third\n' - ' Create model Author\n' + "migrations.0003_third\n" + " Create model Author\n" " Raw SQL operation -> ['SELECT * FROM migrations_author']\n", - out.getvalue() + out.getvalue(), ) try: # Migrate to the third migration. - call_command('migrate', 'migrations', '0003', verbosity=0) + call_command("migrate", "migrations", "0003", verbosity=0) out = io.StringIO() # Show the plan for when there is nothing to apply. - call_command('migrate', 'migrations', '0003', plan=True, stdout=out, no_color=True) + call_command( + "migrate", "migrations", "0003", plan=True, stdout=out, no_color=True + ) self.assertEqual( - 'Planned operations:\n No planned migration operations.\n', - out.getvalue() + "Planned operations:\n No planned migration operations.\n", + out.getvalue(), ) out = io.StringIO() # Show the plan for reverse migration back to 0001. - call_command('migrate', 'migrations', '0001', plan=True, stdout=out, no_color=True) + call_command( + "migrate", "migrations", "0001", plan=True, stdout=out, no_color=True + ) self.assertEqual( - 'Planned operations:\n' - 'migrations.0003_third\n' - ' Undo Create model Author\n' + "Planned operations:\n" + "migrations.0003_third\n" + " Undo Create model Author\n" " Raw SQL operation -> ['SELECT * FROM migrations_book']\n" - 'migrations.0002_second\n' - ' Undo Create model Book\n' + "migrations.0002_second\n" + " Undo Create model Book\n" " Raw SQL operation -> ['SELECT * FROM migrations_salamand…\n", - out.getvalue() + out.getvalue(), ) out = io.StringIO() # Show the migration plan to fourth, with truncated details. - call_command('migrate', 'migrations', '0004', plan=True, stdout=out, no_color=True) + call_command( + "migrate", "migrations", "0004", plan=True, stdout=out, no_color=True + ) self.assertEqual( - 'Planned operations:\n' - 'migrations.0004_fourth\n' - ' Raw SQL operation -> SELECT * FROM migrations_author WHE…\n', - out.getvalue() + "Planned operations:\n" + "migrations.0004_fourth\n" + " Raw SQL operation -> SELECT * FROM migrations_author WHE…\n", + out.getvalue(), ) # Show the plan when an operation is irreversible. # Migrate to the fourth migration. - call_command('migrate', 'migrations', '0004', verbosity=0) + call_command("migrate", "migrations", "0004", verbosity=0) out = io.StringIO() - call_command('migrate', 'migrations', '0003', plan=True, stdout=out, no_color=True) + call_command( + "migrate", "migrations", "0003", plan=True, stdout=out, no_color=True + ) self.assertEqual( - 'Planned operations:\n' - 'migrations.0004_fourth\n' - ' Raw SQL operation -> IRREVERSIBLE\n', - out.getvalue() + "Planned operations:\n" + "migrations.0004_fourth\n" + " Raw SQL operation -> IRREVERSIBLE\n", + out.getvalue(), ) out = io.StringIO() - call_command('migrate', 'migrations', '0005', plan=True, stdout=out, no_color=True) + call_command( + "migrate", "migrations", "0005", plan=True, stdout=out, no_color=True + ) # Operation is marked as irreversible only in the revert plan. self.assertEqual( - 'Planned operations:\n' - 'migrations.0005_fifth\n' - ' Raw Python operation\n' - ' Raw Python operation\n' - ' Raw Python operation -> Feed salamander.\n', - out.getvalue() + "Planned operations:\n" + "migrations.0005_fifth\n" + " Raw Python operation\n" + " Raw Python operation\n" + " Raw Python operation -> Feed salamander.\n", + out.getvalue(), ) - call_command('migrate', 'migrations', '0005', verbosity=0) + call_command("migrate", "migrations", "0005", verbosity=0) out = io.StringIO() - call_command('migrate', 'migrations', '0004', plan=True, stdout=out, no_color=True) + call_command( + "migrate", "migrations", "0004", plan=True, stdout=out, no_color=True + ) self.assertEqual( - 'Planned operations:\n' - 'migrations.0005_fifth\n' - ' Raw Python operation -> IRREVERSIBLE\n' - ' Raw Python operation -> IRREVERSIBLE\n' - ' Raw Python operation\n', - out.getvalue() + "Planned operations:\n" + "migrations.0005_fifth\n" + " Raw Python operation -> IRREVERSIBLE\n" + " Raw Python operation -> IRREVERSIBLE\n" + " Raw Python operation\n", + out.getvalue(), ) finally: # Cleanup by unmigrating everything: fake the irreversible, then # migrate all to zero. - call_command('migrate', 'migrations', '0003', fake=True, verbosity=0) - call_command('migrate', 'migrations', 'zero', verbosity=0) + call_command("migrate", "migrations", "0003", fake=True, verbosity=0) + call_command("migrate", "migrations", "zero", verbosity=0) - @override_settings(MIGRATION_MODULES={'migrations': 'migrations.test_migrations_empty'}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_empty"} + ) def test_showmigrations_no_migrations(self): out = io.StringIO() - call_command('showmigrations', stdout=out, no_color=True) - self.assertEqual('migrations\n (no migrations)\n', out.getvalue().lower()) + call_command("showmigrations", stdout=out, no_color=True) + self.assertEqual("migrations\n (no migrations)\n", out.getvalue().lower()) - @override_settings(INSTALLED_APPS=['migrations.migrations_test_apps.unmigrated_app']) + @override_settings( + INSTALLED_APPS=["migrations.migrations_test_apps.unmigrated_app"] + ) def test_showmigrations_unmigrated_app(self): out = io.StringIO() - call_command('showmigrations', 'unmigrated_app', stdout=out, no_color=True) + call_command("showmigrations", "unmigrated_app", stdout=out, no_color=True) try: - self.assertEqual('unmigrated_app\n (no migrations)\n', out.getvalue().lower()) + self.assertEqual( + "unmigrated_app\n (no migrations)\n", out.getvalue().lower() + ) finally: # unmigrated_app.SillyModel has a foreign key to # 'migrations.Tribble', but that model is only defined in a # migration, so the global app registry never sees it and the # reference is left dangling. Remove it to avoid problems in # subsequent tests. - apps._pending_operations.pop(('migrations', 'tribble'), None) + apps._pending_operations.pop(("migrations", "tribble"), None) - @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_empty"}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_empty"} + ) def test_showmigrations_plan_no_migrations(self): """ Tests --plan output of showmigrations command without migrations """ out = io.StringIO() - call_command('showmigrations', format='plan', stdout=out, no_color=True) - self.assertEqual('(no migrations)\n', out.getvalue().lower()) + call_command("showmigrations", format="plan", stdout=out, no_color=True) + self.assertEqual("(no migrations)\n", out.getvalue().lower()) out = io.StringIO() - call_command('showmigrations', format='plan', stdout=out, verbosity=2, no_color=True) - self.assertEqual('(no migrations)\n', out.getvalue().lower()) + call_command( + "showmigrations", format="plan", stdout=out, verbosity=2, no_color=True + ) + self.assertEqual("(no migrations)\n", out.getvalue().lower()) - @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed_complex"}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed_complex"} + ) def test_showmigrations_plan_squashed(self): """ Tests --plan output of showmigrations command with squashed migrations. """ out = io.StringIO() - call_command("showmigrations", format='plan', stdout=out) + call_command("showmigrations", format="plan", stdout=out) self.assertEqual( "[ ] migrations.1_auto\n" "[ ] migrations.2_auto\n" "[ ] migrations.3_squashed_5\n" "[ ] migrations.6_auto\n" "[ ] migrations.7_auto\n", - out.getvalue().lower() + out.getvalue().lower(), ) out = io.StringIO() - call_command("showmigrations", format='plan', stdout=out, verbosity=2) + call_command("showmigrations", format="plan", stdout=out, verbosity=2) self.assertEqual( "[ ] migrations.1_auto\n" "[ ] migrations.2_auto ... (migrations.1_auto)\n" "[ ] migrations.3_squashed_5 ... (migrations.2_auto)\n" "[ ] migrations.6_auto ... (migrations.3_squashed_5)\n" "[ ] migrations.7_auto ... (migrations.6_auto)\n", - out.getvalue().lower() + out.getvalue().lower(), ) call_command("migrate", "migrations", "3_squashed_5", verbosity=0) out = io.StringIO() - call_command("showmigrations", format='plan', stdout=out) + call_command("showmigrations", format="plan", stdout=out) self.assertEqual( "[x] migrations.1_auto\n" "[x] migrations.2_auto\n" "[x] migrations.3_squashed_5\n" "[ ] migrations.6_auto\n" "[ ] migrations.7_auto\n", - out.getvalue().lower() + out.getvalue().lower(), ) out = io.StringIO() - call_command("showmigrations", format='plan', stdout=out, verbosity=2) + call_command("showmigrations", format="plan", stdout=out, verbosity=2) self.assertEqual( "[x] migrations.1_auto\n" "[x] migrations.2_auto ... (migrations.1_auto)\n" "[x] migrations.3_squashed_5 ... (migrations.2_auto)\n" "[ ] migrations.6_auto ... (migrations.3_squashed_5)\n" "[ ] migrations.7_auto ... (migrations.6_auto)\n", - out.getvalue().lower() + out.getvalue().lower(), ) - @override_settings(INSTALLED_APPS=[ - 'migrations.migrations_test_apps.mutate_state_b', - 'migrations.migrations_test_apps.alter_fk.author_app', - 'migrations.migrations_test_apps.alter_fk.book_app', - ]) + @override_settings( + INSTALLED_APPS=[ + "migrations.migrations_test_apps.mutate_state_b", + "migrations.migrations_test_apps.alter_fk.author_app", + "migrations.migrations_test_apps.alter_fk.book_app", + ] + ) def test_showmigrations_plan_single_app_label(self): """ `showmigrations --plan app_label` output with a single app_label. """ # Single app with no dependencies on other apps. out = io.StringIO() - call_command('showmigrations', 'mutate_state_b', format='plan', stdout=out) + call_command("showmigrations", "mutate_state_b", format="plan", stdout=out) self.assertEqual( - '[ ] mutate_state_b.0001_initial\n[ ] mutate_state_b.0002_add_field\n', - out.getvalue() + "[ ] mutate_state_b.0001_initial\n[ ] mutate_state_b.0002_add_field\n", + out.getvalue(), ) # Single app with dependencies. out = io.StringIO() - call_command('showmigrations', 'author_app', format='plan', stdout=out) + call_command("showmigrations", "author_app", format="plan", stdout=out) self.assertEqual( - '[ ] author_app.0001_initial\n' - '[ ] book_app.0001_initial\n' - '[ ] author_app.0002_alter_id\n', - out.getvalue() + "[ ] author_app.0001_initial\n" + "[ ] book_app.0001_initial\n" + "[ ] author_app.0002_alter_id\n", + out.getvalue(), ) # Some migrations already applied. - call_command('migrate', 'author_app', '0001', verbosity=0) + call_command("migrate", "author_app", "0001", verbosity=0) out = io.StringIO() - call_command('showmigrations', 'author_app', format='plan', stdout=out) + call_command("showmigrations", "author_app", format="plan", stdout=out) self.assertEqual( - '[X] author_app.0001_initial\n' - '[ ] book_app.0001_initial\n' - '[ ] author_app.0002_alter_id\n', - out.getvalue() + "[X] author_app.0001_initial\n" + "[ ] book_app.0001_initial\n" + "[ ] author_app.0002_alter_id\n", + out.getvalue(), ) # Cleanup by unmigrating author_app. - call_command('migrate', 'author_app', 'zero', verbosity=0) + call_command("migrate", "author_app", "zero", verbosity=0) - @override_settings(INSTALLED_APPS=[ - 'migrations.migrations_test_apps.mutate_state_b', - 'migrations.migrations_test_apps.alter_fk.author_app', - 'migrations.migrations_test_apps.alter_fk.book_app', - ]) + @override_settings( + INSTALLED_APPS=[ + "migrations.migrations_test_apps.mutate_state_b", + "migrations.migrations_test_apps.alter_fk.author_app", + "migrations.migrations_test_apps.alter_fk.book_app", + ] + ) def test_showmigrations_plan_multiple_app_labels(self): """ `showmigrations --plan app_label` output with multiple app_labels. @@ -639,41 +770,49 @@ class MigrateTests(MigrationTestBase): # Multiple apps: author_app depends on book_app; mutate_state_b doesn't # depend on other apps. out = io.StringIO() - call_command('showmigrations', 'mutate_state_b', 'author_app', format='plan', stdout=out) + call_command( + "showmigrations", "mutate_state_b", "author_app", format="plan", stdout=out + ) self.assertEqual( - '[ ] author_app.0001_initial\n' - '[ ] book_app.0001_initial\n' - '[ ] author_app.0002_alter_id\n' - '[ ] mutate_state_b.0001_initial\n' - '[ ] mutate_state_b.0002_add_field\n', - out.getvalue() + "[ ] author_app.0001_initial\n" + "[ ] book_app.0001_initial\n" + "[ ] author_app.0002_alter_id\n" + "[ ] mutate_state_b.0001_initial\n" + "[ ] mutate_state_b.0002_add_field\n", + out.getvalue(), ) # Multiple apps: args order shouldn't matter (the same result is # expected as above). out = io.StringIO() - call_command('showmigrations', 'author_app', 'mutate_state_b', format='plan', stdout=out) + call_command( + "showmigrations", "author_app", "mutate_state_b", format="plan", stdout=out + ) self.assertEqual( - '[ ] author_app.0001_initial\n' - '[ ] book_app.0001_initial\n' - '[ ] author_app.0002_alter_id\n' - '[ ] mutate_state_b.0001_initial\n' - '[ ] mutate_state_b.0002_add_field\n', - out.getvalue() + "[ ] author_app.0001_initial\n" + "[ ] book_app.0001_initial\n" + "[ ] author_app.0002_alter_id\n" + "[ ] mutate_state_b.0001_initial\n" + "[ ] mutate_state_b.0002_add_field\n", + out.getvalue(), ) - @override_settings(INSTALLED_APPS=['migrations.migrations_test_apps.unmigrated_app']) + @override_settings( + INSTALLED_APPS=["migrations.migrations_test_apps.unmigrated_app"] + ) def test_showmigrations_plan_app_label_no_migrations(self): out = io.StringIO() - call_command('showmigrations', 'unmigrated_app', format='plan', stdout=out, no_color=True) + call_command( + "showmigrations", "unmigrated_app", format="plan", stdout=out, no_color=True + ) try: - self.assertEqual('(no migrations)\n', out.getvalue()) + self.assertEqual("(no migrations)\n", out.getvalue()) finally: # unmigrated_app.SillyModel has a foreign key to # 'migrations.Tribble', but that model is only defined in a # migration, so the global app registry never sees it and the # reference is left dangling. Remove it to avoid problems in # subsequent tests. - apps._pending_operations.pop(('migrations', 'tribble'), None) + apps._pending_operations.pop(("migrations", "tribble"), None) @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"}) def test_sqlmigrate_forwards(self): @@ -685,34 +824,39 @@ class MigrateTests(MigrationTestBase): output = out.getvalue().lower() index_tx_start = output.find(connection.ops.start_transaction_sql().lower()) - index_op_desc_author = output.find('-- create model author') - index_create_table = output.find('create table') - index_op_desc_tribble = output.find('-- create model tribble') - index_op_desc_unique_together = output.find('-- alter unique_together') + index_op_desc_author = output.find("-- create model author") + index_create_table = output.find("create table") + index_op_desc_tribble = output.find("-- create model tribble") + index_op_desc_unique_together = output.find("-- alter unique_together") index_tx_end = output.find(connection.ops.end_transaction_sql().lower()) if connection.features.can_rollback_ddl: self.assertGreater(index_tx_start, -1, "Transaction start not found") self.assertGreater( - index_tx_end, index_op_desc_unique_together, - "Transaction end not found or found before operation description (unique_together)" + index_tx_end, + index_op_desc_unique_together, + "Transaction end not found or found before operation description (unique_together)", ) self.assertGreater( - index_op_desc_author, index_tx_start, - "Operation description (author) not found or found before transaction start" + index_op_desc_author, + index_tx_start, + "Operation description (author) not found or found before transaction start", ) self.assertGreater( - index_create_table, index_op_desc_author, - "CREATE TABLE not found or found before operation description (author)" + index_create_table, + index_op_desc_author, + "CREATE TABLE not found or found before operation description (author)", ) self.assertGreater( - index_op_desc_tribble, index_create_table, - "Operation description (tribble) not found or found before CREATE TABLE (author)" + index_op_desc_tribble, + index_create_table, + "Operation description (tribble) not found or found before CREATE TABLE (author)", ) self.assertGreater( - index_op_desc_unique_together, index_op_desc_tribble, - "Operation description (unique_together) not found or found before operation description (tribble)" + index_op_desc_unique_together, + index_op_desc_tribble, + "Operation description (unique_together) not found or found before operation description (tribble)", ) @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"}) @@ -728,40 +872,47 @@ class MigrateTests(MigrationTestBase): output = out.getvalue().lower() index_tx_start = output.find(connection.ops.start_transaction_sql().lower()) - index_op_desc_unique_together = output.find('-- alter unique_together') - index_op_desc_tribble = output.find('-- create model tribble') - index_op_desc_author = output.find('-- create model author') - index_drop_table = output.rfind('drop table') + index_op_desc_unique_together = output.find("-- alter unique_together") + index_op_desc_tribble = output.find("-- create model tribble") + index_op_desc_author = output.find("-- create model author") + index_drop_table = output.rfind("drop table") index_tx_end = output.find(connection.ops.end_transaction_sql().lower()) if connection.features.can_rollback_ddl: self.assertGreater(index_tx_start, -1, "Transaction start not found") self.assertGreater( - index_tx_end, index_op_desc_unique_together, - "Transaction end not found or found before DROP TABLE" + index_tx_end, + index_op_desc_unique_together, + "Transaction end not found or found before DROP TABLE", ) self.assertGreater( - index_op_desc_unique_together, index_tx_start, - "Operation description (unique_together) not found or found before transaction start" + index_op_desc_unique_together, + index_tx_start, + "Operation description (unique_together) not found or found before transaction start", ) self.assertGreater( - index_op_desc_tribble, index_op_desc_unique_together, - "Operation description (tribble) not found or found before operation description (unique_together)" + index_op_desc_tribble, + index_op_desc_unique_together, + "Operation description (tribble) not found or found before operation description (unique_together)", ) self.assertGreater( - index_op_desc_author, index_op_desc_tribble, - "Operation description (author) not found or found before operation description (tribble)" + index_op_desc_author, + index_op_desc_tribble, + "Operation description (author) not found or found before operation description (tribble)", ) self.assertGreater( - index_drop_table, index_op_desc_author, - "DROP TABLE not found or found before operation description (author)" + index_drop_table, + index_op_desc_author, + "DROP TABLE not found or found before operation description (author)", ) # Cleanup by unmigrating everything call_command("migrate", "migrations", "zero", verbosity=0) - @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_non_atomic"}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_non_atomic"} + ) def test_sqlmigrate_for_non_atomic_migration(self): """ Transaction wrappers aren't shown for non-atomic migrations. @@ -774,15 +925,15 @@ class MigrateTests(MigrationTestBase): self.assertNotIn(connection.ops.start_transaction_sql().lower(), queries) self.assertNotIn(connection.ops.end_transaction_sql().lower(), queries) - @override_settings(MIGRATION_MODULES={'migrations': 'migrations.test_migrations'}) + @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"}) def test_sqlmigrate_for_non_transactional_databases(self): """ Transaction wrappers aren't shown for databases that don't support transactional DDL. """ out = io.StringIO() - with mock.patch.object(connection.features, 'can_rollback_ddl', False): - call_command('sqlmigrate', 'migrations', '0001', stdout=out) + with mock.patch.object(connection.features, "can_rollback_ddl", False): + call_command("sqlmigrate", "migrations", "0001", stdout=out) output = out.getvalue().lower() queries = [q.strip() for q in output.splitlines()] start_transaction_sql = connection.ops.start_transaction_sql() @@ -790,37 +941,45 @@ class MigrateTests(MigrationTestBase): self.assertNotIn(start_transaction_sql.lower(), queries) self.assertNotIn(connection.ops.end_transaction_sql().lower(), queries) - @override_settings(MIGRATION_MODULES={'migrations': 'migrations.test_migrations_squashed'}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"} + ) def test_sqlmigrate_ambiguous_prefix_squashed_migrations(self): msg = ( "More than one migration matches '0001' in app 'migrations'. " "Please be more specific." ) with self.assertRaisesMessage(CommandError, msg): - call_command('sqlmigrate', 'migrations', '0001') + call_command("sqlmigrate", "migrations", "0001") - @override_settings(MIGRATION_MODULES={'migrations': 'migrations.test_migrations_squashed'}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"} + ) def test_sqlmigrate_squashed_migration(self): out = io.StringIO() - call_command('sqlmigrate', 'migrations', '0001_squashed_0002', stdout=out) + call_command("sqlmigrate", "migrations", "0001_squashed_0002", stdout=out) output = out.getvalue().lower() - self.assertIn('-- create model author', output) - self.assertIn('-- create model book', output) - self.assertNotIn('-- create model tribble', output) + self.assertIn("-- create model author", output) + self.assertIn("-- create model book", output) + self.assertNotIn("-- create model tribble", output) - @override_settings(MIGRATION_MODULES={'migrations': 'migrations.test_migrations_squashed'}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"} + ) def test_sqlmigrate_replaced_migration(self): out = io.StringIO() - call_command('sqlmigrate', 'migrations', '0001_initial', stdout=out) + call_command("sqlmigrate", "migrations", "0001_initial", stdout=out) output = out.getvalue().lower() - self.assertIn('-- create model author', output) - self.assertIn('-- create model tribble', output) + self.assertIn("-- create model author", output) + self.assertIn("-- create model tribble", output) - @override_settings(MIGRATION_MODULES={'migrations': 'migrations.test_migrations_no_operations'}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_no_operations"} + ) def test_migrations_no_operations(self): err = io.StringIO() - call_command('sqlmigrate', 'migrations', '0001_initial', stderr=err) - self.assertEqual(err.getvalue(), 'No operations found.\n') + call_command("sqlmigrate", "migrations", "0001_initial", stderr=err) + self.assertEqual(err.getvalue(), "No operations found.\n") @override_settings( INSTALLED_APPS=[ @@ -841,58 +1000,76 @@ class MigrateTests(MigrationTestBase): "B" was not included in the ProjectState that is used to detect soft-applied migrations (#22823). """ - call_command('migrate', 'migrated_unapplied_app', verbosity=0) + call_command("migrate", "migrated_unapplied_app", verbosity=0) # unmigrated_app.SillyModel has a foreign key to 'migrations.Tribble', # but that model is only defined in a migration, so the global app # registry never sees it and the reference is left dangling. Remove it # to avoid problems in subsequent tests. - apps._pending_operations.pop(('migrations', 'tribble'), None) + apps._pending_operations.pop(("migrations", "tribble"), None) - @override_settings(INSTALLED_APPS=['migrations.migrations_test_apps.unmigrated_app_syncdb']) + @override_settings( + INSTALLED_APPS=["migrations.migrations_test_apps.unmigrated_app_syncdb"] + ) def test_migrate_syncdb_deferred_sql_executed_with_schemaeditor(self): """ For an app without migrations, editor.execute() is used for executing the syncdb deferred SQL. """ stdout = io.StringIO() - with mock.patch.object(BaseDatabaseSchemaEditor, 'execute') as execute: - call_command('migrate', run_syncdb=True, verbosity=1, stdout=stdout, no_color=True) - create_table_count = len([call for call in execute.mock_calls if 'CREATE TABLE' in str(call)]) + with mock.patch.object(BaseDatabaseSchemaEditor, "execute") as execute: + call_command( + "migrate", run_syncdb=True, verbosity=1, stdout=stdout, no_color=True + ) + create_table_count = len( + [call for call in execute.mock_calls if "CREATE TABLE" in str(call)] + ) self.assertEqual(create_table_count, 2) # There's at least one deferred SQL for creating the foreign key # index. self.assertGreater(len(execute.mock_calls), 2) stdout = stdout.getvalue() - self.assertIn('Synchronize unmigrated apps: unmigrated_app_syncdb', stdout) - self.assertIn('Creating tables...', stdout) - table_name = truncate_name('unmigrated_app_syncdb_classroom', connection.ops.max_name_length()) - self.assertIn('Creating table %s' % table_name, stdout) + self.assertIn("Synchronize unmigrated apps: unmigrated_app_syncdb", stdout) + self.assertIn("Creating tables...", stdout) + table_name = truncate_name( + "unmigrated_app_syncdb_classroom", connection.ops.max_name_length() + ) + self.assertIn("Creating table %s" % table_name, stdout) - @override_settings(MIGRATION_MODULES={'migrations': 'migrations.test_migrations'}) + @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"}) def test_migrate_syncdb_app_with_migrations(self): msg = "Can't use run_syncdb with app 'migrations' as it has migrations." with self.assertRaisesMessage(CommandError, msg): - call_command('migrate', 'migrations', run_syncdb=True, verbosity=0) + call_command("migrate", "migrations", run_syncdb=True, verbosity=0) - @override_settings(INSTALLED_APPS=[ - 'migrations.migrations_test_apps.unmigrated_app_syncdb', - 'migrations.migrations_test_apps.unmigrated_app_simple', - ]) + @override_settings( + INSTALLED_APPS=[ + "migrations.migrations_test_apps.unmigrated_app_syncdb", + "migrations.migrations_test_apps.unmigrated_app_simple", + ] + ) def test_migrate_syncdb_app_label(self): """ Running migrate --run-syncdb with an app_label only creates tables for the specified app. """ stdout = io.StringIO() - with mock.patch.object(BaseDatabaseSchemaEditor, 'execute') as execute: - call_command('migrate', 'unmigrated_app_syncdb', run_syncdb=True, stdout=stdout) - create_table_count = len([call for call in execute.mock_calls if 'CREATE TABLE' in str(call)]) + with mock.patch.object(BaseDatabaseSchemaEditor, "execute") as execute: + call_command( + "migrate", "unmigrated_app_syncdb", run_syncdb=True, stdout=stdout + ) + create_table_count = len( + [call for call in execute.mock_calls if "CREATE TABLE" in str(call)] + ) self.assertEqual(create_table_count, 2) self.assertGreater(len(execute.mock_calls), 2) - self.assertIn('Synchronize unmigrated app: unmigrated_app_syncdb', stdout.getvalue()) + self.assertIn( + "Synchronize unmigrated app: unmigrated_app_syncdb", stdout.getvalue() + ) - @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"} + ) def test_migrate_record_replaced(self): """ Running a single squashed migration should record all of the original @@ -903,8 +1080,8 @@ class MigrateTests(MigrationTestBase): call_command("migrate", "migrations", verbosity=0) call_command("showmigrations", "migrations", stdout=out, no_color=True) self.assertEqual( - 'migrations\n [x] 0001_squashed_0002 (2 squashed migrations)\n', - out.getvalue().lower() + "migrations\n [x] 0001_squashed_0002 (2 squashed migrations)\n", + out.getvalue().lower(), ) applied_migrations = recorder.applied_migrations() self.assertIn(("migrations", "0001_initial"), applied_migrations) @@ -913,7 +1090,9 @@ class MigrateTests(MigrationTestBase): # Rollback changes call_command("migrate", "migrations", "zero", verbosity=0) - @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"} + ) def test_migrate_record_squashed(self): """ Running migrate for a squashed migration should record as run @@ -923,7 +1102,7 @@ class MigrateTests(MigrationTestBase): recorder.record_applied("migrations", "0001_initial") recorder.record_applied("migrations", "0002_second") out = io.StringIO() - call_command('showmigrations', 'migrations', stdout=out, no_color=True) + call_command("showmigrations", "migrations", stdout=out, no_color=True) self.assertEqual( "migrations\n" " [-] 0001_squashed_0002 (2 squashed migrations) " @@ -935,12 +1114,11 @@ class MigrateTests(MigrationTestBase): call_command("migrate", "migrations", verbosity=0) call_command("showmigrations", "migrations", stdout=out, no_color=True) self.assertEqual( - 'migrations\n [x] 0001_squashed_0002 (2 squashed migrations)\n', - out.getvalue().lower() + "migrations\n [x] 0001_squashed_0002 (2 squashed migrations)\n", + out.getvalue().lower(), ) self.assertIn( - ("migrations", "0001_squashed_0002"), - recorder.applied_migrations() + ("migrations", "0001_squashed_0002"), recorder.applied_migrations() ) # No changes were actually applied so there is nothing to rollback @@ -949,43 +1127,45 @@ class MigrateTests(MigrationTestBase): Migrating to a squashed migration specified by name should succeed even if it is partially applied. """ - with self.temporary_migration_module(module='migrations.test_migrations'): + with self.temporary_migration_module(module="migrations.test_migrations"): recorder = MigrationRecorder(connection) try: - call_command('migrate', 'migrations', '0001_initial', verbosity=0) + call_command("migrate", "migrations", "0001_initial", verbosity=0) call_command( - 'squashmigrations', - 'migrations', - '0002', + "squashmigrations", + "migrations", + "0002", interactive=False, verbosity=0, ) call_command( - 'migrate', - 'migrations', - '0001_squashed_0002_second', + "migrate", + "migrations", + "0001_squashed_0002_second", verbosity=0, ) applied_migrations = recorder.applied_migrations() - self.assertIn(('migrations', '0002_second'), applied_migrations) + self.assertIn(("migrations", "0002_second"), applied_migrations) finally: # Unmigrate everything. - call_command('migrate', 'migrations', 'zero', verbosity=0) + call_command("migrate", "migrations", "zero", verbosity=0) - @override_settings(MIGRATION_MODULES={'migrations': 'migrations.test_migrations_squashed'}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"} + ) def test_migrate_backward_to_squashed_migration(self): try: - call_command('migrate', 'migrations', '0001_squashed_0002', verbosity=0) - self.assertTableExists('migrations_author') - self.assertTableExists('migrations_book') - call_command('migrate', 'migrations', '0001_initial', verbosity=0) - self.assertTableExists('migrations_author') - self.assertTableNotExists('migrations_book') + call_command("migrate", "migrations", "0001_squashed_0002", verbosity=0) + self.assertTableExists("migrations_author") + self.assertTableExists("migrations_book") + call_command("migrate", "migrations", "0001_initial", verbosity=0) + self.assertTableExists("migrations_author") + self.assertTableNotExists("migrations_book") finally: # Unmigrate everything. - call_command('migrate', 'migrations', 'zero', verbosity=0) + call_command("migrate", "migrations", "zero", verbosity=0) - @override_settings(MIGRATION_MODULES={'migrations': 'migrations.test_migrations'}) + @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"}) def test_migrate_inconsistent_history(self): """ Running migrate with some migrations applied before their dependencies @@ -999,23 +1179,25 @@ class MigrateTests(MigrationTestBase): applied_migrations = recorder.applied_migrations() self.assertNotIn(("migrations", "0001_initial"), applied_migrations) - @override_settings(INSTALLED_APPS=[ - 'migrations.migrations_test_apps.migrated_unapplied_app', - 'migrations.migrations_test_apps.migrated_app', - ]) + @override_settings( + INSTALLED_APPS=[ + "migrations.migrations_test_apps.migrated_unapplied_app", + "migrations.migrations_test_apps.migrated_app", + ] + ) def test_migrate_not_reflected_changes(self): class NewModel1(models.Model): - class Meta(): - app_label = 'migrated_app' + class Meta: + app_label = "migrated_app" class NewModel2(models.Model): - class Meta(): - app_label = 'migrated_unapplied_app' + class Meta: + app_label = "migrated_unapplied_app" out = io.StringIO() try: - call_command('migrate', verbosity=0) - call_command('migrate', stdout=out, no_color=True) + call_command("migrate", verbosity=0) + call_command("migrate", stdout=out, no_color=True) self.assertEqual( "operations to perform:\n" " apply all migrations: migrated_app, migrated_unapplied_app\n" @@ -1030,12 +1212,14 @@ class MigrateTests(MigrationTestBase): ) finally: # Unmigrate everything. - call_command('migrate', 'migrated_app', 'zero', verbosity=0) - call_command('migrate', 'migrated_unapplied_app', 'zero', verbosity=0) + call_command("migrate", "migrated_app", "zero", verbosity=0) + call_command("migrate", "migrated_unapplied_app", "zero", verbosity=0) - @override_settings(MIGRATION_MODULES={ - 'migrations': 'migrations.test_migrations_squashed_no_replaces', - }) + @override_settings( + MIGRATION_MODULES={ + "migrations": "migrations.test_migrations_squashed_no_replaces", + } + ) def test_migrate_prune(self): """ With prune=True, references to migration files deleted from the @@ -1043,44 +1227,50 @@ class MigrateTests(MigrationTestBase): django_migrations table. """ recorder = MigrationRecorder(connection) - recorder.record_applied('migrations', '0001_initial') - recorder.record_applied('migrations', '0002_second') - recorder.record_applied('migrations', '0001_squashed_0002') + recorder.record_applied("migrations", "0001_initial") + recorder.record_applied("migrations", "0002_second") + recorder.record_applied("migrations", "0001_squashed_0002") out = io.StringIO() try: - call_command('migrate', 'migrations', prune=True, stdout=out, no_color=True) + call_command("migrate", "migrations", prune=True, stdout=out, no_color=True) self.assertEqual( out.getvalue(), - 'Pruning migrations:\n' - ' Pruning migrations.0001_initial OK\n' - ' Pruning migrations.0002_second OK\n', + "Pruning migrations:\n" + " Pruning migrations.0001_initial OK\n" + " Pruning migrations.0002_second OK\n", ) applied_migrations = [ migration for migration in recorder.applied_migrations() - if migration[0] == 'migrations' + if migration[0] == "migrations" ] - self.assertEqual(applied_migrations, [('migrations', '0001_squashed_0002')]) + self.assertEqual(applied_migrations, [("migrations", "0001_squashed_0002")]) finally: - recorder.record_unapplied('migrations', '0001_initial') - recorder.record_unapplied('migrations', '0001_second') - recorder.record_unapplied('migrations', '0001_squashed_0002') + recorder.record_unapplied("migrations", "0001_initial") + recorder.record_unapplied("migrations", "0001_second") + recorder.record_unapplied("migrations", "0001_squashed_0002") - @override_settings(MIGRATION_MODULES={'migrations': 'migrations.test_migrations_squashed'}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"} + ) def test_prune_deleted_squashed_migrations_in_replaces(self): out = io.StringIO() with self.temporary_migration_module( - module='migrations.test_migrations_squashed' + module="migrations.test_migrations_squashed" ) as migration_dir: try: - call_command('migrate', 'migrations', verbosity=0) + call_command("migrate", "migrations", verbosity=0) # Delete the replaced migrations. - os.remove(os.path.join(migration_dir, '0001_initial.py')) - os.remove(os.path.join(migration_dir, '0002_second.py')) + os.remove(os.path.join(migration_dir, "0001_initial.py")) + os.remove(os.path.join(migration_dir, "0002_second.py")) # --prune cannot be used before removing the "replaces" # attribute. call_command( - 'migrate', 'migrations', prune=True, stdout=out, no_color=True, + "migrate", + "migrations", + prune=True, + stdout=out, + no_color=True, ) self.assertEqual( out.getvalue(), @@ -1091,32 +1281,37 @@ class MigrateTests(MigrationTestBase): " migrations.0001_squashed_0002\n" " Re-run 'manage.py migrate' if they are not marked as " "applied, and remove 'replaces' attributes in their " - "Migration classes.\n" + "Migration classes.\n", ) finally: # Unmigrate everything. - call_command('migrate', 'migrations', 'zero', verbosity=0) + call_command("migrate", "migrations", "zero", verbosity=0) @override_settings( - MIGRATION_MODULES={'migrations': 'migrations.test_migrations_squashed'} + MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"} ) def test_prune_no_migrations_to_prune(self): out = io.StringIO() - call_command('migrate', 'migrations', prune=True, stdout=out, no_color=True) + call_command("migrate", "migrations", prune=True, stdout=out, no_color=True) self.assertEqual( out.getvalue(), - 'Pruning migrations:\n No migrations to prune.\n', + "Pruning migrations:\n No migrations to prune.\n", ) out = io.StringIO() call_command( - 'migrate', 'migrations', prune=True, stdout=out, no_color=True, verbosity=0, + "migrate", + "migrations", + prune=True, + stdout=out, + no_color=True, + verbosity=0, ) - self.assertEqual(out.getvalue(), '') + self.assertEqual(out.getvalue(), "") def test_prune_no_app_label(self): - msg = 'Migrations can be pruned only when an app is specified.' + msg = "Migrations can be pruned only when an app is specified." with self.assertRaisesMessage(CommandError, msg): - call_command('migrate', prune=True) + call_command("migrate", prune=True) class MakeMigrationsTests(MigrationTestBase): @@ -1126,17 +1321,17 @@ class MakeMigrationsTests(MigrationTestBase): def setUp(self): super().setUp() - self._old_models = apps.app_configs['migrations'].models.copy() + self._old_models = apps.app_configs["migrations"].models.copy() def tearDown(self): - apps.app_configs['migrations'].models = self._old_models - apps.all_models['migrations'] = self._old_models + apps.app_configs["migrations"].models = self._old_models + apps.all_models["migrations"] = self._old_models apps.clear_cache() super().tearDown() def test_files_content(self): self.assertTableNotExists("migrations_unicodemodel") - apps.register_model('migrations', UnicodeModel) + apps.register_model("migrations", UnicodeModel) with self.temporary_migration_module() as migration_dir: call_command("makemigrations", "migrations", verbosity=0) @@ -1146,65 +1341,71 @@ class MakeMigrationsTests(MigrationTestBase): with open(init_file) as fp: content = fp.read() - self.assertEqual(content, '') + self.assertEqual(content, "") # Check for existing 0001_initial.py file in migration folder initial_file = os.path.join(migration_dir, "0001_initial.py") self.assertTrue(os.path.exists(initial_file)) - with open(initial_file, encoding='utf-8') as fp: + with open(initial_file, encoding="utf-8") as fp: content = fp.read() - self.assertIn('migrations.CreateModel', content) - self.assertIn('initial = True', content) + self.assertIn("migrations.CreateModel", content) + self.assertIn("initial = True", content) - self.assertIn('úñí©óðé µóðéø', content) # Meta.verbose_name - self.assertIn('úñí©óðé µóðéøß', content) # Meta.verbose_name_plural - self.assertIn('ÚÑÍ¢ÓÐÉ', content) # title.verbose_name - self.assertIn('“Ðjáñgó”', content) # title.default + self.assertIn("úñí©óðé µóðéø", content) # Meta.verbose_name + self.assertIn("úñí©óðé µóðéøß", content) # Meta.verbose_name_plural + self.assertIn("ÚÑÍ¢ÓÐÉ", content) # title.verbose_name + self.assertIn("“Ðjáñgó”", content) # title.default def test_makemigrations_order(self): """ makemigrations should recognize number-only migrations (0001.py). """ - module = 'migrations.test_migrations_order' + module = "migrations.test_migrations_order" with self.temporary_migration_module(module=module) as migration_dir: - if hasattr(importlib, 'invalidate_caches'): + if hasattr(importlib, "invalidate_caches"): # importlib caches os.listdir() on some platforms like macOS # (#23850). importlib.invalidate_caches() - call_command('makemigrations', 'migrations', '--empty', '-n', 'a', '-v', '0') - self.assertTrue(os.path.exists(os.path.join(migration_dir, '0002_a.py'))) + call_command( + "makemigrations", "migrations", "--empty", "-n", "a", "-v", "0" + ) + self.assertTrue(os.path.exists(os.path.join(migration_dir, "0002_a.py"))) def test_makemigrations_empty_connections(self): - empty_connections = ConnectionHandler({'default': {}}) - with mock.patch('django.core.management.commands.makemigrations.connections', new=empty_connections): + empty_connections = ConnectionHandler({"default": {}}) + with mock.patch( + "django.core.management.commands.makemigrations.connections", + new=empty_connections, + ): # with no apps out = io.StringIO() - call_command('makemigrations', stdout=out) - self.assertIn('No changes detected', out.getvalue()) + call_command("makemigrations", stdout=out) + self.assertIn("No changes detected", out.getvalue()) # with an app with self.temporary_migration_module() as migration_dir: - call_command('makemigrations', 'migrations', verbosity=0) - init_file = os.path.join(migration_dir, '__init__.py') + call_command("makemigrations", "migrations", verbosity=0) + init_file = os.path.join(migration_dir, "__init__.py") self.assertTrue(os.path.exists(init_file)) - @override_settings(INSTALLED_APPS=['migrations', 'migrations2']) + @override_settings(INSTALLED_APPS=["migrations", "migrations2"]) def test_makemigrations_consistency_checks_respect_routers(self): """ The history consistency checks in makemigrations respect settings.DATABASE_ROUTERS. """ + def patched_has_table(migration_recorder): - if migration_recorder.connection is connections['other']: - raise Exception('Other connection') + if migration_recorder.connection is connections["other"]: + raise Exception("Other connection") else: return mock.DEFAULT - self.assertTableNotExists('migrations_unicodemodel') - apps.register_model('migrations', UnicodeModel) + self.assertTableNotExists("migrations_unicodemodel") + apps.register_model("migrations", UnicodeModel) with mock.patch.object( - MigrationRecorder, 'has_table', - autospec=True, side_effect=patched_has_table) as has_table: + MigrationRecorder, "has_table", autospec=True, side_effect=patched_has_table + ) as has_table: with self.temporary_migration_module() as migration_dir: call_command("makemigrations", "migrations", verbosity=0) initial_file = os.path.join(migration_dir, "0001_initial.py") @@ -1213,23 +1414,29 @@ class MakeMigrationsTests(MigrationTestBase): # Router says not to migrate 'other' so consistency shouldn't # be checked. - with self.settings(DATABASE_ROUTERS=['migrations.routers.TestRouter']): - call_command('makemigrations', 'migrations', verbosity=0) + with self.settings(DATABASE_ROUTERS=["migrations.routers.TestRouter"]): + call_command("makemigrations", "migrations", verbosity=0) self.assertEqual(has_table.call_count, 2) # 'default' again # With a router that doesn't prohibit migrating 'other', # consistency is checked. - with self.settings(DATABASE_ROUTERS=['migrations.routers.DefaultOtherRouter']): - with self.assertRaisesMessage(Exception, 'Other connection'): - call_command('makemigrations', 'migrations', verbosity=0) + with self.settings( + DATABASE_ROUTERS=["migrations.routers.DefaultOtherRouter"] + ): + with self.assertRaisesMessage(Exception, "Other connection"): + call_command("makemigrations", "migrations", verbosity=0) self.assertEqual(has_table.call_count, 4) # 'default' and 'other' # With a router that doesn't allow migrating on any database, # no consistency checks are made. - with self.settings(DATABASE_ROUTERS=['migrations.routers.TestRouter']): - with mock.patch.object(TestRouter, 'allow_migrate', return_value=False) as allow_migrate: - call_command('makemigrations', 'migrations', verbosity=0) - allow_migrate.assert_any_call('other', 'migrations', model_name='UnicodeModel') + with self.settings(DATABASE_ROUTERS=["migrations.routers.TestRouter"]): + with mock.patch.object( + TestRouter, "allow_migrate", return_value=False + ) as allow_migrate: + call_command("makemigrations", "migrations", verbosity=0) + allow_migrate.assert_any_call( + "other", "migrations", model_name="UnicodeModel" + ) # allow_migrate() is called with the correct arguments. self.assertGreater(len(allow_migrate.mock_calls), 0) called_aliases = set() @@ -1238,16 +1445,16 @@ class MakeMigrationsTests(MigrationTestBase): connection_alias, app_name = call_args called_aliases.add(connection_alias) # Raises an error if invalid app_name/model_name occurs. - apps.get_app_config(app_name).get_model(call_kwargs['model_name']) + apps.get_app_config(app_name).get_model(call_kwargs["model_name"]) self.assertEqual(called_aliases, set(connections)) self.assertEqual(has_table.call_count, 4) def test_failing_migration(self): # If a migration fails to serialize, it shouldn't generate an empty file. #21280 - apps.register_model('migrations', UnserializableModel) + apps.register_model("migrations", UnserializableModel) with self.temporary_migration_module() as migration_dir: - with self.assertRaisesMessage(ValueError, 'Cannot serialize'): + with self.assertRaisesMessage(ValueError, "Cannot serialize"): call_command("makemigrations", "migrations", verbosity=0) initial_file = os.path.join(migration_dir, "0001_initial.py") @@ -1257,7 +1464,9 @@ class MakeMigrationsTests(MigrationTestBase): """ makemigrations exits if it detects a conflict. """ - with self.temporary_migration_module(module="migrations.test_migrations_conflict"): + with self.temporary_migration_module( + module="migrations.test_migrations_conflict" + ): with self.assertRaises(CommandError) as context: call_command("makemigrations") self.assertEqual( @@ -1265,7 +1474,7 @@ class MakeMigrationsTests(MigrationTestBase): "Conflicting migrations detected; multiple leaf nodes in the " "migration graph: (0002_conflicting_second, 0002_second in " "migrations).\n" - "To fix them run 'python manage.py makemigrations --merge'" + "To fix them run 'python manage.py makemigrations --merge'", ) def test_makemigrations_merge_no_conflict(self): @@ -1281,7 +1490,7 @@ class MakeMigrationsTests(MigrationTestBase): """ makemigrations exits if no app is specified with 'empty' mode. """ - msg = 'You must supply at least one app label when using --empty.' + msg = "You must supply at least one app label when using --empty." with self.assertRaisesMessage(CommandError, msg): call_command("makemigrations", empty=True) @@ -1296,13 +1505,13 @@ class MakeMigrationsTests(MigrationTestBase): initial_file = os.path.join(migration_dir, "0001_initial.py") self.assertTrue(os.path.exists(initial_file)) - with open(initial_file, encoding='utf-8') as fp: + with open(initial_file, encoding="utf-8") as fp: content = fp.read() # Remove all whitespace to check for empty dependencies and operations - content = content.replace(' ', '') - self.assertIn('dependencies=[\n]', content) - self.assertIn('operations=[\n]', content) + content = content.replace(" ", "") + self.assertIn("dependencies=[\n]", content) + self.assertIn("operations=[\n]", content) @override_settings(MIGRATION_MODULES={"migrations": None}) def test_makemigrations_disabled_migrations_for_app(self): @@ -1330,7 +1539,9 @@ class MakeMigrationsTests(MigrationTestBase): makemigrations exits when there are no changes to an app. """ out = io.StringIO() - with self.temporary_migration_module(module="migrations.test_migrations_no_changes"): + with self.temporary_migration_module( + module="migrations.test_migrations_no_changes" + ): call_command("makemigrations", "migrations", stdout=out) self.assertIn("No changes detected in app 'migrations'", out.getvalue()) @@ -1347,9 +1558,11 @@ class MakeMigrationsTests(MigrationTestBase): def test_makemigrations_no_init(self): """Migration directories without an __init__.py file are allowed.""" out = io.StringIO() - with self.temporary_migration_module(module='migrations.test_migrations_no_init'): - call_command('makemigrations', stdout=out) - self.assertIn('0001_initial.py', out.getvalue()) + with self.temporary_migration_module( + module="migrations.test_migrations_no_init" + ): + call_command("makemigrations", stdout=out) + self.assertIn("0001_initial.py", out.getvalue()) def test_makemigrations_migrations_announce(self): """ @@ -1365,7 +1578,9 @@ class MakeMigrationsTests(MigrationTestBase): makemigrations fails to merge migrations with no common ancestor. """ with self.assertRaises(ValueError) as context: - with self.temporary_migration_module(module="migrations.test_migrations_no_ancestor"): + with self.temporary_migration_module( + module="migrations.test_migrations_no_ancestor" + ): call_command("makemigrations", "migrations", merge=True) exception_message = str(context.exception) self.assertIn("Could not find common ancestor of", exception_message) @@ -1377,18 +1592,20 @@ class MakeMigrationsTests(MigrationTestBase): makemigrations enters and exits interactive mode properly. """ # Monkeypatch interactive questioner to auto reject - with mock.patch('builtins.input', mock.Mock(return_value='N')): - with self.temporary_migration_module(module="migrations.test_migrations_conflict") as migration_dir: + with mock.patch("builtins.input", mock.Mock(return_value="N")): + with self.temporary_migration_module( + module="migrations.test_migrations_conflict" + ) as migration_dir: with captured_stdout(): call_command( - 'makemigrations', - 'migrations', - name='merge', + "makemigrations", + "migrations", + name="merge", merge=True, interactive=True, verbosity=0, ) - merge_file = os.path.join(migration_dir, '0003_merge.py') + merge_file = os.path.join(migration_dir, "0003_merge.py") self.assertFalse(os.path.exists(merge_file)) def test_makemigrations_interactive_accept(self): @@ -1396,37 +1613,58 @@ class MakeMigrationsTests(MigrationTestBase): makemigrations enters interactive mode and merges properly. """ # Monkeypatch interactive questioner to auto accept - with mock.patch('builtins.input', mock.Mock(return_value='y')): + with mock.patch("builtins.input", mock.Mock(return_value="y")): out = io.StringIO() - with self.temporary_migration_module(module="migrations.test_migrations_conflict") as migration_dir: - call_command("makemigrations", "migrations", name="merge", merge=True, interactive=True, stdout=out) - merge_file = os.path.join(migration_dir, '0003_merge.py') + with self.temporary_migration_module( + module="migrations.test_migrations_conflict" + ) as migration_dir: + call_command( + "makemigrations", + "migrations", + name="merge", + merge=True, + interactive=True, + stdout=out, + ) + merge_file = os.path.join(migration_dir, "0003_merge.py") self.assertTrue(os.path.exists(merge_file)) self.assertIn("Created new merge migration", out.getvalue()) def test_makemigrations_default_merge_name(self): out = io.StringIO() with self.temporary_migration_module( - module='migrations.test_migrations_conflict' + module="migrations.test_migrations_conflict" ) as migration_dir: - call_command('makemigrations', 'migrations', merge=True, interactive=False, stdout=out) + call_command( + "makemigrations", + "migrations", + merge=True, + interactive=False, + stdout=out, + ) merge_file = os.path.join( migration_dir, - '0003_merge_0002_conflicting_second_0002_second.py', + "0003_merge_0002_conflicting_second_0002_second.py", ) self.assertIs(os.path.exists(merge_file), True) - self.assertIn('Created new merge migration %s' % merge_file, out.getvalue()) + self.assertIn("Created new merge migration %s" % merge_file, out.getvalue()) - @mock.patch('django.db.migrations.utils.datetime') + @mock.patch("django.db.migrations.utils.datetime") def test_makemigrations_auto_merge_name(self, mock_datetime): mock_datetime.datetime.now.return_value = datetime.datetime(2016, 1, 2, 3, 4) - with mock.patch('builtins.input', mock.Mock(return_value='y')): + with mock.patch("builtins.input", mock.Mock(return_value="y")): out = io.StringIO() with self.temporary_migration_module( - module='migrations.test_migrations_conflict_long_name' + module="migrations.test_migrations_conflict_long_name" ) as migration_dir: - call_command("makemigrations", "migrations", merge=True, interactive=True, stdout=out) - merge_file = os.path.join(migration_dir, '0003_merge_20160102_0304.py') + call_command( + "makemigrations", + "migrations", + merge=True, + interactive=True, + stdout=out, + ) + merge_file = os.path.join(migration_dir, "0003_merge_20160102_0304.py") self.assertTrue(os.path.exists(merge_file)) self.assertIn("Created new merge migration", out.getvalue()) @@ -1435,6 +1673,7 @@ class MakeMigrationsTests(MigrationTestBase): Non-interactive makemigrations fails when a default is missing on a new not-null field. """ + class SillyModel(models.Model): silly_field = models.BooleanField(default=False) silly_int = models.IntegerField() @@ -1443,9 +1682,11 @@ class MakeMigrationsTests(MigrationTestBase): app_label = "migrations" with self.assertRaises(SystemExit): - with self.temporary_migration_module(module="migrations.test_migrations_no_default"): + with self.temporary_migration_module( + module="migrations.test_migrations_no_default" + ): with captured_stdout() as out: - call_command('makemigrations', 'migrations', interactive=False) + call_command("makemigrations", "migrations", interactive=False) self.assertIn( "Field 'silly_int' on model 'sillymodel' not migrated: it is " "impossible to add a non-nullable field without specifying a " @@ -1458,11 +1699,12 @@ class MakeMigrationsTests(MigrationTestBase): makemigrations messages when adding a NOT NULL field in interactive mode. """ + class Author(models.Model): silly_field = models.BooleanField(null=False) class Meta: - app_label = 'migrations' + app_label = "migrations" input_msg = ( "It is impossible to add a non-nullable field 'silly_field' to " @@ -1473,23 +1715,23 @@ class MakeMigrationsTests(MigrationTestBase): "rows with a null value for this column)\n" " 2) Quit and manually define a default value in models.py." ) - with self.temporary_migration_module(module='migrations.test_migrations'): + with self.temporary_migration_module(module="migrations.test_migrations"): # 2 - quit. - with mock.patch('builtins.input', return_value='2'): + with mock.patch("builtins.input", return_value="2"): with captured_stdout() as out, self.assertRaises(SystemExit): - call_command('makemigrations', 'migrations', interactive=True) + call_command("makemigrations", "migrations", interactive=True) self.assertIn(input_msg, out.getvalue()) # 1 - provide a default. - with mock.patch('builtins.input', return_value='1'): + with mock.patch("builtins.input", return_value="1"): with captured_stdout() as out: - call_command('makemigrations', 'migrations', interactive=True) + call_command("makemigrations", "migrations", interactive=True) output = out.getvalue() self.assertIn(input_msg, output) - self.assertIn('Please enter the default value as valid Python.', output) + self.assertIn("Please enter the default value as valid Python.", output) self.assertIn( - 'The datetime and django.utils.timezone modules are ' - 'available, so it is possible to provide e.g. timezone.now as ' - 'a value', + "The datetime and django.utils.timezone modules are " + "available, so it is possible to provide e.g. timezone.now as " + "a value", output, ) self.assertIn("Type 'exit' to exit this prompt", output) @@ -1499,6 +1741,7 @@ class MakeMigrationsTests(MigrationTestBase): Non-interactive makemigrations fails when a default is missing on a field changed to not-null. """ + class Author(models.Model): name = models.CharField(max_length=255) slug = models.SlugField() @@ -1509,7 +1752,7 @@ class MakeMigrationsTests(MigrationTestBase): with self.temporary_migration_module(module="migrations.test_migrations"): with captured_stdout() as out: - call_command('makemigrations', 'migrations', interactive=False) + call_command("makemigrations", "migrations", interactive=False) self.assertIn("Alter field slug on author", out.getvalue()) self.assertIn( "Field 'slug' on model 'author' given a default of NOT PROVIDED " @@ -1522,11 +1765,12 @@ class MakeMigrationsTests(MigrationTestBase): makemigrations messages when changing a NULL field to NOT NULL in interactive mode. """ + class Author(models.Model): slug = models.SlugField(null=False) class Meta: - app_label = 'migrations' + app_label = "migrations" input_msg = ( "It is impossible to change a nullable field 'slug' on author to " @@ -1540,29 +1784,32 @@ class MakeMigrationsTests(MigrationTestBase): "RunSQL operation.\n" " 3) Quit and manually define a default value in models.py." ) - with self.temporary_migration_module(module='migrations.test_migrations'): + with self.temporary_migration_module(module="migrations.test_migrations"): # No message appears if --dry-run. with captured_stdout() as out: call_command( - 'makemigrations', 'migrations', interactive=True, dry_run=True, + "makemigrations", + "migrations", + interactive=True, + dry_run=True, ) self.assertNotIn(input_msg, out.getvalue()) # 3 - quit. - with mock.patch('builtins.input', return_value='3'): + with mock.patch("builtins.input", return_value="3"): with captured_stdout() as out, self.assertRaises(SystemExit): - call_command('makemigrations', 'migrations', interactive=True) + call_command("makemigrations", "migrations", interactive=True) self.assertIn(input_msg, out.getvalue()) # 1 - provide a default. - with mock.patch('builtins.input', return_value='1'): + with mock.patch("builtins.input", return_value="1"): with captured_stdout() as out: - call_command('makemigrations', 'migrations', interactive=True) + call_command("makemigrations", "migrations", interactive=True) output = out.getvalue() self.assertIn(input_msg, output) - self.assertIn('Please enter the default value as valid Python.', output) + self.assertIn("Please enter the default value as valid Python.", output) self.assertIn( - 'The datetime and django.utils.timezone modules are ' - 'available, so it is possible to provide e.g. timezone.now as ' - 'a value', + "The datetime and django.utils.timezone modules are " + "available, so it is possible to provide e.g. timezone.now as " + "a value", output, ) self.assertIn("Type 'exit' to exit this prompt", output) @@ -1572,6 +1819,7 @@ class MakeMigrationsTests(MigrationTestBase): makemigrations adds and removes a possible model rename in non-interactive mode. """ + class RenamedModel(models.Model): silly_field = models.BooleanField(default=False) @@ -1579,7 +1827,9 @@ class MakeMigrationsTests(MigrationTestBase): app_label = "migrations" out = io.StringIO() - with self.temporary_migration_module(module="migrations.test_migrations_no_default"): + with self.temporary_migration_module( + module="migrations.test_migrations_no_default" + ): call_command("makemigrations", "migrations", interactive=False, stdout=out) self.assertIn("Delete model SillyModel", out.getvalue()) self.assertIn("Create model RenamedModel", out.getvalue()) @@ -1589,6 +1839,7 @@ class MakeMigrationsTests(MigrationTestBase): makemigrations adds and removes a possible field rename in non-interactive mode. """ + class SillyModel(models.Model): silly_rename = models.BooleanField(default=False) @@ -1596,41 +1847,43 @@ class MakeMigrationsTests(MigrationTestBase): app_label = "migrations" out = io.StringIO() - with self.temporary_migration_module(module="migrations.test_migrations_no_default"): + with self.temporary_migration_module( + module="migrations.test_migrations_no_default" + ): call_command("makemigrations", "migrations", interactive=False, stdout=out) self.assertIn("Remove field silly_field from sillymodel", out.getvalue()) self.assertIn("Add field silly_rename to sillymodel", out.getvalue()) - @mock.patch('builtins.input', return_value='Y') + @mock.patch("builtins.input", return_value="Y") def test_makemigrations_model_rename_interactive(self, mock_input): class RenamedModel(models.Model): silly_field = models.BooleanField(default=False) class Meta: - app_label = 'migrations' + app_label = "migrations" with self.temporary_migration_module( - module='migrations.test_migrations_no_default', + module="migrations.test_migrations_no_default", ): with captured_stdout() as out: - call_command('makemigrations', 'migrations', interactive=True) - self.assertIn('Rename model SillyModel to RenamedModel', out.getvalue()) + call_command("makemigrations", "migrations", interactive=True) + self.assertIn("Rename model SillyModel to RenamedModel", out.getvalue()) - @mock.patch('builtins.input', return_value='Y') + @mock.patch("builtins.input", return_value="Y") def test_makemigrations_field_rename_interactive(self, mock_input): class SillyModel(models.Model): silly_rename = models.BooleanField(default=False) class Meta: - app_label = 'migrations' + app_label = "migrations" with self.temporary_migration_module( - module='migrations.test_migrations_no_default', + module="migrations.test_migrations_no_default", ): with captured_stdout() as out: - call_command('makemigrations', 'migrations', interactive=True) + call_command("makemigrations", "migrations", interactive=True) self.assertIn( - 'Rename field silly_field on sillymodel to silly_rename', + "Rename field silly_field on sillymodel to silly_rename", out.getvalue(), ) @@ -1639,9 +1892,18 @@ class MakeMigrationsTests(MigrationTestBase): makemigrations properly merges the conflicting migrations with --noinput. """ out = io.StringIO() - with self.temporary_migration_module(module="migrations.test_migrations_conflict") as migration_dir: - call_command("makemigrations", "migrations", name="merge", merge=True, interactive=False, stdout=out) - merge_file = os.path.join(migration_dir, '0003_merge.py') + with self.temporary_migration_module( + module="migrations.test_migrations_conflict" + ) as migration_dir: + call_command( + "makemigrations", + "migrations", + name="merge", + merge=True, + interactive=False, + stdout=out, + ) + merge_file = os.path.join(migration_dir, "0003_merge.py") self.assertTrue(os.path.exists(merge_file)) output = out.getvalue() self.assertIn("Merging migrations", output) @@ -1655,12 +1917,19 @@ class MakeMigrationsTests(MigrationTestBase): conflicts (#24427). """ out = io.StringIO() - with self.temporary_migration_module(module="migrations.test_migrations_conflict") as migration_dir: + with self.temporary_migration_module( + module="migrations.test_migrations_conflict" + ) as migration_dir: call_command( - "makemigrations", "migrations", name="merge", dry_run=True, - merge=True, interactive=False, stdout=out, + "makemigrations", + "migrations", + name="merge", + dry_run=True, + merge=True, + interactive=False, + stdout=out, ) - merge_file = os.path.join(migration_dir, '0003_merge.py') + merge_file = os.path.join(migration_dir, "0003_merge.py") self.assertFalse(os.path.exists(merge_file)) output = out.getvalue() self.assertIn("Merging migrations", output) @@ -1674,12 +1943,20 @@ class MakeMigrationsTests(MigrationTestBase): stdout with `verbosity == 3` (#24427). """ out = io.StringIO() - with self.temporary_migration_module(module="migrations.test_migrations_conflict") as migration_dir: + with self.temporary_migration_module( + module="migrations.test_migrations_conflict" + ) as migration_dir: call_command( - "makemigrations", "migrations", name="merge", dry_run=True, - merge=True, interactive=False, stdout=out, verbosity=3, + "makemigrations", + "migrations", + name="merge", + dry_run=True, + merge=True, + interactive=False, + stdout=out, + verbosity=3, ) - merge_file = os.path.join(migration_dir, '0003_merge.py') + merge_file = os.path.join(migration_dir, "0003_merge.py") self.assertFalse(os.path.exists(merge_file)) output = out.getvalue() self.assertIn("Merging migrations", output) @@ -1700,6 +1977,7 @@ class MakeMigrationsTests(MigrationTestBase): """ `makemigrations --dry-run` should not ask for defaults. """ + class SillyModel(models.Model): silly_field = models.BooleanField(default=False) silly_date = models.DateField() # Added field without a default @@ -1709,7 +1987,9 @@ class MakeMigrationsTests(MigrationTestBase): app_label = "migrations" out = io.StringIO() - with self.temporary_migration_module(module="migrations.test_migrations_no_default"): + with self.temporary_migration_module( + module="migrations.test_migrations_no_default" + ): call_command("makemigrations", "migrations", dry_run=True, stdout=out) # Output the expected changes directly, without asking for defaults self.assertIn("Add field silly_date to sillymodel", out.getvalue()) @@ -1719,6 +1999,7 @@ class MakeMigrationsTests(MigrationTestBase): Allow `makemigrations --dry-run` to output the migrations file to stdout (with verbosity == 3). """ + class SillyModel(models.Model): silly_field = models.BooleanField(default=False) silly_char = models.CharField(default="") @@ -1727,8 +2008,12 @@ class MakeMigrationsTests(MigrationTestBase): app_label = "migrations" out = io.StringIO() - with self.temporary_migration_module(module="migrations.test_migrations_no_default"): - call_command("makemigrations", "migrations", dry_run=True, stdout=out, verbosity=3) + with self.temporary_migration_module( + module="migrations.test_migrations_no_default" + ): + call_command( + "makemigrations", "migrations", dry_run=True, stdout=out, verbosity=3 + ) # Normal --dry-run output self.assertIn("- Add field silly_char to sillymodel", out.getvalue()) @@ -1750,38 +2035,38 @@ class MakeMigrationsTests(MigrationTestBase): out = io.StringIO() err = io.StringIO() with self.temporary_migration_module( - module='migrations.migrations.test_migrations', + module="migrations.migrations.test_migrations", ) as migration_dir: call_command( - 'makemigrations', - 'migrations', + "makemigrations", + "migrations", scriptable=True, stdout=out, stderr=err, ) - initial_file = os.path.join(migration_dir, '0001_initial.py') - self.assertEqual(out.getvalue(), f'{initial_file}\n') - self.assertIn(' - Create model ModelWithCustomBase\n', err.getvalue()) + initial_file = os.path.join(migration_dir, "0001_initial.py") + self.assertEqual(out.getvalue(), f"{initial_file}\n") + self.assertIn(" - Create model ModelWithCustomBase\n", err.getvalue()) - @mock.patch('builtins.input', return_value='Y') + @mock.patch("builtins.input", return_value="Y") def test_makemigrations_scriptable_merge(self, mock_input): out = io.StringIO() err = io.StringIO() with self.temporary_migration_module( - module='migrations.test_migrations_conflict', + module="migrations.test_migrations_conflict", ) as migration_dir: call_command( - 'makemigrations', - 'migrations', + "makemigrations", + "migrations", merge=True, - name='merge', + name="merge", scriptable=True, stdout=out, stderr=err, ) - merge_file = os.path.join(migration_dir, '0003_merge.py') - self.assertEqual(out.getvalue(), f'{merge_file}\n') - self.assertIn(f'Created new merge migration {merge_file}', err.getvalue()) + merge_file = os.path.join(migration_dir, "0003_merge.py") + self.assertEqual(out.getvalue(), f"{merge_file}\n") + self.assertIn(f"Created new merge migration {merge_file}", err.getvalue()) def test_makemigrations_migrations_modules_path_not_exist(self): """ @@ -1789,6 +2074,7 @@ class MakeMigrationsTests(MigrationTestBase): for migration files using MIGRATION_MODULES if the custom path doesn't already exist. """ + class SillyModel(models.Model): silly_field = models.BooleanField(default=False) @@ -1807,15 +2093,15 @@ class MakeMigrationsTests(MigrationTestBase): # Command output indicates the migration is created. self.assertIn(" - Create model SillyModel", out.getvalue()) - @override_settings(MIGRATION_MODULES={'migrations': 'some.nonexistent.path'}) + @override_settings(MIGRATION_MODULES={"migrations": "some.nonexistent.path"}) def test_makemigrations_migrations_modules_nonexistent_toplevel_package(self): msg = ( - 'Could not locate an appropriate location to create migrations ' - 'package some.nonexistent.path. Make sure the toplevel package ' - 'exists and can be imported.' + "Could not locate an appropriate location to create migrations " + "package some.nonexistent.path. Make sure the toplevel package " + "exists and can be imported." ) with self.assertRaisesMessage(ValueError, msg): - call_command('makemigrations', 'migrations', empty=True, verbosity=0) + call_command("makemigrations", "migrations", empty=True, verbosity=0) def test_makemigrations_interactive_by_default(self): """ @@ -1825,10 +2111,14 @@ class MakeMigrationsTests(MigrationTestBase): """ # Monkeypatch interactive questioner to auto reject out = io.StringIO() - with mock.patch('builtins.input', mock.Mock(return_value='N')): - with self.temporary_migration_module(module="migrations.test_migrations_conflict") as migration_dir: - call_command("makemigrations", "migrations", name="merge", merge=True, stdout=out) - merge_file = os.path.join(migration_dir, '0003_merge.py') + with mock.patch("builtins.input", mock.Mock(return_value="N")): + with self.temporary_migration_module( + module="migrations.test_migrations_conflict" + ) as migration_dir: + call_command( + "makemigrations", "migrations", name="merge", merge=True, stdout=out + ) + merge_file = os.path.join(migration_dir, "0003_merge.py") # This will fail if interactive is False by default self.assertFalse(os.path.exists(merge_file)) self.assertNotIn("Created new merge migration", out.getvalue()) @@ -1836,64 +2126,86 @@ class MakeMigrationsTests(MigrationTestBase): @override_settings( INSTALLED_APPS=[ "migrations", - "migrations.migrations_test_apps.unspecified_app_with_conflict"]) + "migrations.migrations_test_apps.unspecified_app_with_conflict", + ] + ) def test_makemigrations_unspecified_app_with_conflict_no_merge(self): """ makemigrations does not raise a CommandError when an unspecified app has conflicting migrations. """ - with self.temporary_migration_module(module="migrations.test_migrations_no_changes"): + with self.temporary_migration_module( + module="migrations.test_migrations_no_changes" + ): call_command("makemigrations", "migrations", merge=False, verbosity=0) @override_settings( INSTALLED_APPS=[ "migrations.migrations_test_apps.migrated_app", - "migrations.migrations_test_apps.unspecified_app_with_conflict"]) + "migrations.migrations_test_apps.unspecified_app_with_conflict", + ] + ) def test_makemigrations_unspecified_app_with_conflict_merge(self): """ makemigrations does not create a merge for an unspecified app even if it has conflicting migrations. """ # Monkeypatch interactive questioner to auto accept - with mock.patch('builtins.input', mock.Mock(return_value='y')): + with mock.patch("builtins.input", mock.Mock(return_value="y")): out = io.StringIO() - with self.temporary_migration_module(app_label="migrated_app") as migration_dir: - call_command("makemigrations", "migrated_app", name="merge", merge=True, interactive=True, stdout=out) - merge_file = os.path.join(migration_dir, '0003_merge.py') + with self.temporary_migration_module( + app_label="migrated_app" + ) as migration_dir: + call_command( + "makemigrations", + "migrated_app", + name="merge", + merge=True, + interactive=True, + stdout=out, + ) + merge_file = os.path.join(migration_dir, "0003_merge.py") self.assertFalse(os.path.exists(merge_file)) self.assertIn("No conflicts detected to merge.", out.getvalue()) @override_settings( INSTALLED_APPS=[ "migrations.migrations_test_apps.migrated_app", - "migrations.migrations_test_apps.conflicting_app_with_dependencies"]) + "migrations.migrations_test_apps.conflicting_app_with_dependencies", + ] + ) def test_makemigrations_merge_dont_output_dependency_operations(self): """ makemigrations --merge does not output any operations from apps that don't belong to a given app. """ # Monkeypatch interactive questioner to auto accept - with mock.patch('builtins.input', mock.Mock(return_value='N')): + with mock.patch("builtins.input", mock.Mock(return_value="N")): out = io.StringIO() - with mock.patch('django.core.management.color.supports_color', lambda *args: False): + with mock.patch( + "django.core.management.color.supports_color", lambda *args: False + ): call_command( - "makemigrations", "conflicting_app_with_dependencies", - merge=True, interactive=True, stdout=out + "makemigrations", + "conflicting_app_with_dependencies", + merge=True, + interactive=True, + stdout=out, ) self.assertEqual( out.getvalue().lower(), - 'merging conflicting_app_with_dependencies\n' - ' branch 0002_conflicting_second\n' - ' - create model something\n' - ' branch 0002_second\n' - ' - delete model tribble\n' - ' - remove field silly_field from author\n' - ' - add field rating to author\n' - ' - create model book\n' - '\n' - 'merging will only work if the operations printed above do not conflict\n' - 'with each other (working on different fields or models)\n' - 'should these migration branches be merged? [y/n] ' + "merging conflicting_app_with_dependencies\n" + " branch 0002_conflicting_second\n" + " - create model something\n" + " branch 0002_second\n" + " - delete model tribble\n" + " - remove field silly_field from author\n" + " - add field rating to author\n" + " - create model book\n" + "\n" + "merging will only work if the operations printed above do not conflict\n" + "with each other (working on different fields or models)\n" + "should these migration branches be merged? [y/n] ", ) def test_makemigrations_with_custom_name(self): @@ -1903,11 +2215,21 @@ class MakeMigrationsTests(MigrationTestBase): with self.temporary_migration_module() as migration_dir: def cmd(migration_count, migration_name, *args): - call_command("makemigrations", "migrations", "--verbosity", "0", "--name", migration_name, *args) - migration_file = os.path.join(migration_dir, "%s_%s.py" % (migration_count, migration_name)) + call_command( + "makemigrations", + "migrations", + "--verbosity", + "0", + "--name", + migration_name, + *args, + ) + migration_file = os.path.join( + migration_dir, "%s_%s.py" % (migration_count, migration_name) + ) # Check for existing migration file in migration folder self.assertTrue(os.path.exists(migration_file)) - with open(migration_file, encoding='utf-8') as fp: + with open(migration_file, encoding="utf-8") as fp: content = fp.read() content = content.replace(" ", "") return content @@ -1919,19 +2241,24 @@ class MakeMigrationsTests(MigrationTestBase): # importlib caches os.listdir() on some platforms like macOS # (#23850). - if hasattr(importlib, 'invalidate_caches'): + if hasattr(importlib, "invalidate_caches"): importlib.invalidate_caches() # generate an empty migration migration_name_0002 = "my_custom_migration" content = cmd("0002", migration_name_0002, "--empty") - self.assertIn("dependencies=[\n('migrations','0001_%s'),\n]" % migration_name_0001, content) + self.assertIn( + "dependencies=[\n('migrations','0001_%s'),\n]" % migration_name_0001, + content, + ) self.assertIn("operations=[\n]", content) def test_makemigrations_with_invalid_custom_name(self): - msg = 'The migration name must be a valid Python identifier.' + msg = "The migration name must be a valid Python identifier." with self.assertRaisesMessage(CommandError, msg): - call_command('makemigrations', 'migrations', '--name', 'invalid name', '--empty') + call_command( + "makemigrations", "migrations", "--name", "invalid name", "--empty" + ) def test_makemigrations_check(self): """ @@ -1942,7 +2269,9 @@ class MakeMigrationsTests(MigrationTestBase): with self.assertRaises(SystemExit): call_command("makemigrations", "--check", "migrations", verbosity=0) - with self.temporary_migration_module(module="migrations.test_migrations_no_changes"): + with self.temporary_migration_module( + module="migrations.test_migrations_no_changes" + ): call_command("makemigrations", "--check", "migrations", verbosity=0) def test_makemigrations_migration_path_output(self): @@ -1952,10 +2281,12 @@ class MakeMigrationsTests(MigrationTestBase): should be shown. """ out = io.StringIO() - apps.register_model('migrations', UnicodeModel) + apps.register_model("migrations", UnicodeModel) with self.temporary_migration_module() as migration_dir: call_command("makemigrations", "migrations", stdout=out) - self.assertIn(os.path.join(migration_dir, '0001_initial.py'), out.getvalue()) + self.assertIn( + os.path.join(migration_dir, "0001_initial.py"), out.getvalue() + ) def test_makemigrations_migration_path_output_valueerror(self): """ @@ -1966,9 +2297,9 @@ class MakeMigrationsTests(MigrationTestBase): """ out = io.StringIO() with self.temporary_migration_module() as migration_dir: - with mock.patch('os.path.relpath', side_effect=ValueError): - call_command('makemigrations', 'migrations', stdout=out) - self.assertIn(os.path.join(migration_dir, '0001_initial.py'), out.getvalue()) + with mock.patch("os.path.relpath", side_effect=ValueError): + call_command("makemigrations", "migrations", stdout=out) + self.assertIn(os.path.join(migration_dir, "0001_initial.py"), out.getvalue()) def test_makemigrations_inconsistent_history(self): """ @@ -1976,7 +2307,7 @@ class MakeMigrationsTests(MigrationTestBase): there are some migrations applied before their dependencies. """ recorder = MigrationRecorder(connection) - recorder.record_applied('migrations', '0002_second') + recorder.record_applied("migrations", "0002_second") msg = "Migration migrations.0002_second is applied before its dependency migrations.0001_initial" with self.temporary_migration_module(module="migrations.test_migrations"): with self.assertRaisesMessage(InconsistentMigrationHistory, msg): @@ -1988,27 +2319,31 @@ class MakeMigrationsTests(MigrationTestBase): "for database connection 'default': could not connect to server" ) with mock.patch( - 'django.db.migrations.loader.MigrationLoader.check_consistent_history', - side_effect=OperationalError('could not connect to server'), + "django.db.migrations.loader.MigrationLoader.check_consistent_history", + side_effect=OperationalError("could not connect to server"), ): with self.temporary_migration_module(): with self.assertWarns(RuntimeWarning) as cm: - call_command('makemigrations', verbosity=0) + call_command("makemigrations", verbosity=0) self.assertEqual(str(cm.warning), msg) - @mock.patch('builtins.input', return_value='1') - @mock.patch('django.db.migrations.questioner.sys.stdin', mock.MagicMock(encoding=sys.getdefaultencoding())) + @mock.patch("builtins.input", return_value="1") + @mock.patch( + "django.db.migrations.questioner.sys.stdin", + mock.MagicMock(encoding=sys.getdefaultencoding()), + ) def test_makemigrations_auto_now_add_interactive(self, *args): """ makemigrations prompts the user when adding auto_now_add to an existing model. """ + class Entry(models.Model): title = models.CharField(max_length=255) creation_date = models.DateTimeField(auto_now_add=True) class Meta: - app_label = 'migrations' + app_label = "migrations" input_msg = ( "It is impossible to add the field 'creation_date' with " @@ -2021,11 +2356,13 @@ class MakeMigrationsTests(MigrationTestBase): ) # Monkeypatch interactive questioner to auto accept prompt_stdout = io.StringIO() - with self.temporary_migration_module(module='migrations.test_auto_now_add'): - call_command('makemigrations', 'migrations', interactive=True, stdout=prompt_stdout) + with self.temporary_migration_module(module="migrations.test_auto_now_add"): + call_command( + "makemigrations", "migrations", interactive=True, stdout=prompt_stdout + ) prompt_output = prompt_stdout.getvalue() self.assertIn(input_msg, prompt_output) - self.assertIn('Please enter the default value as valid Python.', prompt_output) + self.assertIn("Please enter the default value as valid Python.", prompt_output) self.assertIn( "Accept the default 'timezone.now' by pressing 'Enter' or provide " "another value.", @@ -2034,33 +2371,34 @@ class MakeMigrationsTests(MigrationTestBase): self.assertIn("Type 'exit' to exit this prompt", prompt_output) self.assertIn("Add field creation_date to entry", prompt_output) - @mock.patch('builtins.input', return_value='2') + @mock.patch("builtins.input", return_value="2") def test_makemigrations_auto_now_add_interactive_quit(self, mock_input): class Author(models.Model): publishing_date = models.DateField(auto_now_add=True) class Meta: - app_label = 'migrations' + app_label = "migrations" - with self.temporary_migration_module(module='migrations.test_migrations'): + with self.temporary_migration_module(module="migrations.test_migrations"): with captured_stdout(): with self.assertRaises(SystemExit): - call_command('makemigrations', 'migrations', interactive=True) + call_command("makemigrations", "migrations", interactive=True) def test_makemigrations_non_interactive_auto_now_add_addition(self): """ Non-interactive makemigrations fails when a default is missing on a new field when auto_now_add=True. """ + class Entry(models.Model): creation_date = models.DateTimeField(auto_now_add=True) class Meta: - app_label = 'migrations' + app_label = "migrations" - with self.temporary_migration_module(module='migrations.test_auto_now_add'): + with self.temporary_migration_module(module="migrations.test_auto_now_add"): with self.assertRaises(SystemExit), captured_stdout() as out: - call_command('makemigrations', 'migrations', interactive=False) + call_command("makemigrations", "migrations", interactive=False) self.assertIn( "Field 'creation_date' on model 'entry' not migrated: it is " "impossible to add a field with 'auto_now_add=True' without " @@ -2073,66 +2411,69 @@ class MakeMigrationsTests(MigrationTestBase): makemigrations prompts the user when adding a unique field with a callable default. """ + class Book(models.Model): created = models.DateTimeField(unique=True, default=timezone.now) class Meta: - app_label = 'migrations' + app_label = "migrations" version = get_docs_version() input_msg = ( - f'Callable default on unique field book.created will not generate ' - f'unique values upon migrating.\n' - f'Please choose how to proceed:\n' - f' 1) Continue making this migration as the first step in writing ' - f'a manual migration to generate unique values described here: ' - f'https://docs.djangoproject.com/en/{version}/howto/' - f'writing-migrations/#migrations-that-add-unique-fields.\n' - f' 2) Quit and edit field options in models.py.\n' + f"Callable default on unique field book.created will not generate " + f"unique values upon migrating.\n" + f"Please choose how to proceed:\n" + f" 1) Continue making this migration as the first step in writing " + f"a manual migration to generate unique values described here: " + f"https://docs.djangoproject.com/en/{version}/howto/" + f"writing-migrations/#migrations-that-add-unique-fields.\n" + f" 2) Quit and edit field options in models.py.\n" ) - with self.temporary_migration_module(module='migrations.test_migrations'): + with self.temporary_migration_module(module="migrations.test_migrations"): # 2 - quit. - with mock.patch('builtins.input', return_value='2'): + with mock.patch("builtins.input", return_value="2"): with captured_stdout() as out, self.assertRaises(SystemExit): - call_command('makemigrations', 'migrations', interactive=True) + call_command("makemigrations", "migrations", interactive=True) out_value = out.getvalue() self.assertIn(input_msg, out_value) - self.assertNotIn('Add field created to book', out_value) + self.assertNotIn("Add field created to book", out_value) # 1 - continue. - with mock.patch('builtins.input', return_value='1'): + with mock.patch("builtins.input", return_value="1"): with captured_stdout() as out: - call_command('makemigrations', 'migrations', interactive=True) + call_command("makemigrations", "migrations", interactive=True) out_value = out.getvalue() self.assertIn(input_msg, out_value) - self.assertIn('Add field created to book', out_value) + self.assertIn("Add field created to book", out_value) def test_makemigrations_non_interactive_unique_callable_default_addition(self): class Book(models.Model): created = models.DateTimeField(unique=True, default=timezone.now) class Meta: - app_label = 'migrations' + app_label = "migrations" - with self.temporary_migration_module(module='migrations.test_migrations'): + with self.temporary_migration_module(module="migrations.test_migrations"): with captured_stdout() as out: - call_command('makemigrations', 'migrations', interactive=False) + call_command("makemigrations", "migrations", interactive=False) out_value = out.getvalue() - self.assertIn('Add field created to book', out_value) + self.assertIn("Add field created to book", out_value) @override_settings( - MIGRATION_MODULES={'migrations': 'migrations.test_migrations_squashed'}, + MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"}, ) def test_makemigrations_continues_number_sequence_after_squash(self): - with self.temporary_migration_module(module='migrations.test_migrations_squashed'): + with self.temporary_migration_module( + module="migrations.test_migrations_squashed" + ): with captured_stdout() as out: call_command( - 'makemigrations', - 'migrations', + "makemigrations", + "migrations", interactive=False, empty=True, ) out_value = out.getvalue() - self.assertIn('0003_auto', out_value) + self.assertIn("0003_auto", out_value) class SquashMigrationsTests(MigrationTestBase): @@ -2145,31 +2486,48 @@ class SquashMigrationsTests(MigrationTestBase): squashmigrations squashes migrations. """ out = io.StringIO() - with self.temporary_migration_module(module="migrations.test_migrations") as migration_dir: - call_command('squashmigrations', 'migrations', '0002', interactive=False, stdout=out, no_color=True) + with self.temporary_migration_module( + module="migrations.test_migrations" + ) as migration_dir: + call_command( + "squashmigrations", + "migrations", + "0002", + interactive=False, + stdout=out, + no_color=True, + ) - squashed_migration_file = os.path.join(migration_dir, "0001_squashed_0002_second.py") + squashed_migration_file = os.path.join( + migration_dir, "0001_squashed_0002_second.py" + ) self.assertTrue(os.path.exists(squashed_migration_file)) self.assertEqual( out.getvalue(), - 'Will squash the following migrations:\n' - ' - 0001_initial\n' - ' - 0002_second\n' - 'Optimizing...\n' - ' Optimized from 8 operations to 2 operations.\n' - 'Created new squashed migration %s\n' - ' You should commit this migration but leave the old ones in place;\n' - ' the new migration will be used for new installs. Once you are sure\n' - ' all instances of the codebase have applied the migrations you squashed,\n' - ' you can delete them.\n' % squashed_migration_file + "Will squash the following migrations:\n" + " - 0001_initial\n" + " - 0002_second\n" + "Optimizing...\n" + " Optimized from 8 operations to 2 operations.\n" + "Created new squashed migration %s\n" + " You should commit this migration but leave the old ones in place;\n" + " the new migration will be used for new installs. Once you are sure\n" + " all instances of the codebase have applied the migrations you squashed,\n" + " you can delete them.\n" % squashed_migration_file, ) def test_squashmigrations_initial_attribute(self): - with self.temporary_migration_module(module="migrations.test_migrations") as migration_dir: - call_command("squashmigrations", "migrations", "0002", interactive=False, verbosity=0) + with self.temporary_migration_module( + module="migrations.test_migrations" + ) as migration_dir: + call_command( + "squashmigrations", "migrations", "0002", interactive=False, verbosity=0 + ) - squashed_migration_file = os.path.join(migration_dir, "0001_squashed_0002_second.py") - with open(squashed_migration_file, encoding='utf-8') as fp: + squashed_migration_file = os.path.join( + migration_dir, "0001_squashed_0002_second.py" + ) + with open(squashed_migration_file, encoding="utf-8") as fp: content = fp.read() self.assertIn("initial = True", content) @@ -2179,7 +2537,14 @@ class SquashMigrationsTests(MigrationTestBase): """ out = io.StringIO() with self.temporary_migration_module(module="migrations.test_migrations"): - call_command("squashmigrations", "migrations", "0002", interactive=False, verbosity=1, stdout=out) + call_command( + "squashmigrations", + "migrations", + "0002", + interactive=False, + verbosity=1, + stdout=out, + ) self.assertIn("Optimized from 8 operations to 2 operations.", out.getvalue()) def test_ticket_23799_squashmigrations_no_optimize(self): @@ -2188,8 +2553,15 @@ class SquashMigrationsTests(MigrationTestBase): """ out = io.StringIO() with self.temporary_migration_module(module="migrations.test_migrations"): - call_command("squashmigrations", "migrations", "0002", - interactive=False, verbosity=1, no_optimize=True, stdout=out) + call_command( + "squashmigrations", + "migrations", + "0002", + interactive=False, + verbosity=1, + no_optimize=True, + stdout=out, + ) self.assertIn("Skipping optimization", out.getvalue()) def test_squashmigrations_valid_start(self): @@ -2197,12 +2569,23 @@ class SquashMigrationsTests(MigrationTestBase): squashmigrations accepts a starting migration. """ out = io.StringIO() - with self.temporary_migration_module(module="migrations.test_migrations_no_changes") as migration_dir: - call_command("squashmigrations", "migrations", "0002", "0003", - interactive=False, verbosity=1, stdout=out) + with self.temporary_migration_module( + module="migrations.test_migrations_no_changes" + ) as migration_dir: + call_command( + "squashmigrations", + "migrations", + "0002", + "0003", + interactive=False, + verbosity=1, + stdout=out, + ) - squashed_migration_file = os.path.join(migration_dir, "0002_second_squashed_0003_third.py") - with open(squashed_migration_file, encoding='utf-8') as fp: + squashed_migration_file = os.path.join( + migration_dir, "0002_second_squashed_0003_third.py" + ) + with open(squashed_migration_file, encoding="utf-8") as fp: content = fp.read() self.assertIn(" ('migrations', '0001_initial')", content) self.assertNotIn("initial = True", content) @@ -2215,79 +2598,110 @@ class SquashMigrationsTests(MigrationTestBase): """ squashmigrations doesn't accept a starting migration after the ending migration. """ - with self.temporary_migration_module(module="migrations.test_migrations_no_changes"): + with self.temporary_migration_module( + module="migrations.test_migrations_no_changes" + ): msg = ( "The migration 'migrations.0003_third' cannot be found. Maybe " "it comes after the migration 'migrations.0002_second'" ) with self.assertRaisesMessage(CommandError, msg): - call_command("squashmigrations", "migrations", "0003", "0002", interactive=False, verbosity=0) + call_command( + "squashmigrations", + "migrations", + "0003", + "0002", + interactive=False, + verbosity=0, + ) def test_squashed_name_with_start_migration_name(self): """--squashed-name specifies the new migration's name.""" - squashed_name = 'squashed_name' - with self.temporary_migration_module(module='migrations.test_migrations') as migration_dir: + squashed_name = "squashed_name" + with self.temporary_migration_module( + module="migrations.test_migrations" + ) as migration_dir: call_command( - 'squashmigrations', 'migrations', '0001', '0002', - squashed_name=squashed_name, interactive=False, verbosity=0, + "squashmigrations", + "migrations", + "0001", + "0002", + squashed_name=squashed_name, + interactive=False, + verbosity=0, + ) + squashed_migration_file = os.path.join( + migration_dir, "0001_%s.py" % squashed_name ) - squashed_migration_file = os.path.join(migration_dir, '0001_%s.py' % squashed_name) self.assertTrue(os.path.exists(squashed_migration_file)) def test_squashed_name_without_start_migration_name(self): """--squashed-name also works if a start migration is omitted.""" - squashed_name = 'squashed_name' - with self.temporary_migration_module(module="migrations.test_migrations") as migration_dir: + squashed_name = "squashed_name" + with self.temporary_migration_module( + module="migrations.test_migrations" + ) as migration_dir: call_command( - 'squashmigrations', 'migrations', '0001', - squashed_name=squashed_name, interactive=False, verbosity=0, + "squashmigrations", + "migrations", + "0001", + squashed_name=squashed_name, + interactive=False, + verbosity=0, + ) + squashed_migration_file = os.path.join( + migration_dir, "0001_%s.py" % squashed_name ) - squashed_migration_file = os.path.join(migration_dir, '0001_%s.py' % squashed_name) self.assertTrue(os.path.exists(squashed_migration_file)) def test_squashed_name_exists(self): - msg = 'Migration 0001_initial already exists. Use a different name.' - with self.temporary_migration_module(module='migrations.test_migrations'): + msg = "Migration 0001_initial already exists. Use a different name." + with self.temporary_migration_module(module="migrations.test_migrations"): with self.assertRaisesMessage(CommandError, msg): call_command( - 'squashmigrations', 'migrations', '0001', '0002', - squashed_name='initial', interactive=False, verbosity=0, + "squashmigrations", + "migrations", + "0001", + "0002", + squashed_name="initial", + interactive=False, + verbosity=0, ) def test_squashmigrations_manual_porting(self): out = io.StringIO() with self.temporary_migration_module( - module='migrations.test_migrations_manual_porting', + module="migrations.test_migrations_manual_porting", ) as migration_dir: call_command( - 'squashmigrations', - 'migrations', - '0002', + "squashmigrations", + "migrations", + "0002", interactive=False, stdout=out, no_color=True, ) squashed_migration_file = os.path.join( migration_dir, - '0001_squashed_0002_second.py', + "0001_squashed_0002_second.py", ) self.assertTrue(os.path.exists(squashed_migration_file)) self.assertEqual( out.getvalue(), - f'Will squash the following migrations:\n' - f' - 0001_initial\n' - f' - 0002_second\n' - f'Optimizing...\n' - f' No optimizations possible.\n' - f'Created new squashed migration {squashed_migration_file}\n' - f' You should commit this migration but leave the old ones in place;\n' - f' the new migration will be used for new installs. Once you are sure\n' - f' all instances of the codebase have applied the migrations you squashed,\n' - f' you can delete them.\n' - f'Manual porting required\n' - f' Your migrations contained functions that must be manually copied over,\n' - f' as we could not safely copy their implementation.\n' - f' See the comment at the top of the squashed migration for details.\n' + f"Will squash the following migrations:\n" + f" - 0001_initial\n" + f" - 0002_second\n" + f"Optimizing...\n" + f" No optimizations possible.\n" + f"Created new squashed migration {squashed_migration_file}\n" + f" You should commit this migration but leave the old ones in place;\n" + f" the new migration will be used for new installs. Once you are sure\n" + f" all instances of the codebase have applied the migrations you squashed,\n" + f" you can delete them.\n" + f"Manual porting required\n" + f" Your migrations contained functions that must be manually copied over,\n" + f" as we could not safely copy their implementation.\n" + f" See the comment at the top of the squashed migration for details.\n", ) @@ -2298,6 +2712,7 @@ class AppLabelErrorTests(TestCase): app. 'django.contrib.auth' must be in INSTALLED_APPS for some of these tests. """ + nonexistent_app_error = "No installed app with label 'nonexistent_app'." did_you_mean_auth_error = ( "No installed app with label 'django.contrib.auth'. Did you mean 'auth'?" @@ -2306,47 +2721,47 @@ class AppLabelErrorTests(TestCase): def test_makemigrations_nonexistent_app_label(self): err = io.StringIO() with self.assertRaises(SystemExit): - call_command('makemigrations', 'nonexistent_app', stderr=err) + call_command("makemigrations", "nonexistent_app", stderr=err) self.assertIn(self.nonexistent_app_error, err.getvalue()) def test_makemigrations_app_name_specified_as_label(self): err = io.StringIO() with self.assertRaises(SystemExit): - call_command('makemigrations', 'django.contrib.auth', stderr=err) + call_command("makemigrations", "django.contrib.auth", stderr=err) self.assertIn(self.did_you_mean_auth_error, err.getvalue()) def test_migrate_nonexistent_app_label(self): with self.assertRaisesMessage(CommandError, self.nonexistent_app_error): - call_command('migrate', 'nonexistent_app') + call_command("migrate", "nonexistent_app") def test_migrate_app_name_specified_as_label(self): with self.assertRaisesMessage(CommandError, self.did_you_mean_auth_error): - call_command('migrate', 'django.contrib.auth') + call_command("migrate", "django.contrib.auth") def test_showmigrations_nonexistent_app_label(self): err = io.StringIO() with self.assertRaises(SystemExit): - call_command('showmigrations', 'nonexistent_app', stderr=err) + call_command("showmigrations", "nonexistent_app", stderr=err) self.assertIn(self.nonexistent_app_error, err.getvalue()) def test_showmigrations_app_name_specified_as_label(self): err = io.StringIO() with self.assertRaises(SystemExit): - call_command('showmigrations', 'django.contrib.auth', stderr=err) + call_command("showmigrations", "django.contrib.auth", stderr=err) self.assertIn(self.did_you_mean_auth_error, err.getvalue()) def test_sqlmigrate_nonexistent_app_label(self): with self.assertRaisesMessage(CommandError, self.nonexistent_app_error): - call_command('sqlmigrate', 'nonexistent_app', '0002') + call_command("sqlmigrate", "nonexistent_app", "0002") def test_sqlmigrate_app_name_specified_as_label(self): with self.assertRaisesMessage(CommandError, self.did_you_mean_auth_error): - call_command('sqlmigrate', 'django.contrib.auth', '0002') + call_command("sqlmigrate", "django.contrib.auth", "0002") def test_squashmigrations_nonexistent_app_label(self): with self.assertRaisesMessage(CommandError, self.nonexistent_app_error): - call_command('squashmigrations', 'nonexistent_app', '0002') + call_command("squashmigrations", "nonexistent_app", "0002") def test_squashmigrations_app_name_specified_as_label(self): with self.assertRaisesMessage(CommandError, self.did_you_mean_auth_error): - call_command('squashmigrations', 'django.contrib.auth', '0002') + call_command("squashmigrations", "django.contrib.auth", "0002") diff --git a/tests/migrations/test_deprecated_fields.py b/tests/migrations/test_deprecated_fields.py index 2e9808e20b..63975514f6 100644 --- a/tests/migrations/test_deprecated_fields.py +++ b/tests/migrations/test_deprecated_fields.py @@ -8,7 +8,10 @@ class Tests(MigrationTestBase): """ Deprecated model fields should still be usable in historic migrations. """ - @override_settings(MIGRATION_MODULES={"migrations": "migrations.deprecated_field_migrations"}) + + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.deprecated_field_migrations"} + ) def test_migrate(self): # Make sure no tables are created self.assertTableNotExists("migrations_ipaddressfield") diff --git a/tests/migrations/test_exceptions.py b/tests/migrations/test_exceptions.py index 3d839471f9..64d2109d5a 100644 --- a/tests/migrations/test_exceptions.py +++ b/tests/migrations/test_exceptions.py @@ -4,9 +4,8 @@ from django.test import SimpleTestCase class ExceptionTests(SimpleTestCase): def test_node_not_found_error_repr(self): - node = ('some_app_label', 'some_migration_label') - error_repr = repr(NodeNotFoundError('some message', node)) + node = ("some_app_label", "some_migration_label") + error_repr = repr(NodeNotFoundError("some message", node)) self.assertEqual( - error_repr, - "NodeNotFoundError(('some_app_label', 'some_migration_label'))" + error_repr, "NodeNotFoundError(('some_app_label', 'some_migration_label'))" ) diff --git a/tests/migrations/test_executor.py b/tests/migrations/test_executor.py index cab6ac6cb5..6232b44b98 100644 --- a/tests/migrations/test_executor.py +++ b/tests/migrations/test_executor.py @@ -8,14 +8,17 @@ from django.db.migrations.graph import MigrationGraph from django.db.migrations.recorder import MigrationRecorder from django.db.migrations.state import ProjectState from django.test import ( - SimpleTestCase, modify_settings, override_settings, skipUnlessDBFeature, + SimpleTestCase, + modify_settings, + override_settings, + skipUnlessDBFeature, ) from django.test.utils import isolate_lru_cache from .test_base import MigrationTestBase -@modify_settings(INSTALLED_APPS={'append': 'migrations2'}) +@modify_settings(INSTALLED_APPS={"append": "migrations2"}) class ExecutorTests(MigrationTestBase): """ Tests the migration executor (full end-to-end running). @@ -24,7 +27,12 @@ class ExecutorTests(MigrationTestBase): test failures first, as they may be propagating into here. """ - available_apps = ["migrations", "migrations2", "django.contrib.auth", "django.contrib.contenttypes"] + available_apps = [ + "migrations", + "migrations2", + "django.contrib.auth", + "django.contrib.contenttypes", + ] @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"}) def test_run(self): @@ -65,21 +73,28 @@ class ExecutorTests(MigrationTestBase): self.assertTableNotExists("migrations_author") self.assertTableNotExists("migrations_book") - @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"} + ) def test_run_with_squashed(self): """ Tests running a squashed migration from zero (should ignore what it replaces) """ executor = MigrationExecutor(connection) # Check our leaf node is the squashed one - leaves = [key for key in executor.loader.graph.leaf_nodes() if key[0] == "migrations"] + leaves = [ + key for key in executor.loader.graph.leaf_nodes() if key[0] == "migrations" + ] self.assertEqual(leaves, [("migrations", "0001_squashed_0002")]) # Check the plan plan = executor.migration_plan([("migrations", "0001_squashed_0002")]) self.assertEqual( plan, [ - (executor.loader.graph.nodes["migrations", "0001_squashed_0002"], False), + ( + executor.loader.graph.nodes["migrations", "0001_squashed_0002"], + False, + ), ], ) # Were the tables there before? @@ -106,29 +121,31 @@ class ExecutorTests(MigrationTestBase): self.assertTableNotExists("migrations_book") @override_settings( - MIGRATION_MODULES={'migrations': 'migrations.test_migrations_squashed'}, + MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"}, ) def test_migrate_backward_to_squashed_migration(self): executor = MigrationExecutor(connection) try: - self.assertTableNotExists('migrations_author') - self.assertTableNotExists('migrations_book') - executor.migrate([('migrations', '0001_squashed_0002')]) - self.assertTableExists('migrations_author') - self.assertTableExists('migrations_book') + self.assertTableNotExists("migrations_author") + self.assertTableNotExists("migrations_book") + executor.migrate([("migrations", "0001_squashed_0002")]) + self.assertTableExists("migrations_author") + self.assertTableExists("migrations_book") executor.loader.build_graph() # Migrate backward to a squashed migration. - executor.migrate([('migrations', '0001_initial')]) - self.assertTableExists('migrations_author') - self.assertTableNotExists('migrations_book') + executor.migrate([("migrations", "0001_initial")]) + self.assertTableExists("migrations_author") + self.assertTableNotExists("migrations_book") finally: # Unmigrate everything. executor = MigrationExecutor(connection) - executor.migrate([('migrations', None)]) - self.assertTableNotExists('migrations_author') - self.assertTableNotExists('migrations_book') + executor.migrate([("migrations", None)]) + self.assertTableNotExists("migrations_author") + self.assertTableNotExists("migrations_book") - @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_non_atomic"}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_non_atomic"} + ) def test_non_atomic_migration(self): """ Applying a non-atomic migration works as expected. @@ -137,12 +154,16 @@ class ExecutorTests(MigrationTestBase): with self.assertRaisesMessage(RuntimeError, "Abort migration"): executor.migrate([("migrations", "0001_initial")]) self.assertTableExists("migrations_publisher") - migrations_apps = executor.loader.project_state(("migrations", "0001_initial")).apps + migrations_apps = executor.loader.project_state( + ("migrations", "0001_initial") + ).apps Publisher = migrations_apps.get_model("migrations", "Publisher") self.assertTrue(Publisher.objects.exists()) self.assertTableNotExists("migrations_book") - @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_atomic_operation"}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_atomic_operation"} + ) def test_atomic_operation_in_non_atomic_migration(self): """ An atomic operation is properly rolled back inside a non-atomic @@ -151,7 +172,9 @@ class ExecutorTests(MigrationTestBase): executor = MigrationExecutor(connection) with self.assertRaisesMessage(RuntimeError, "Abort migration"): executor.migrate([("migrations", "0001_initial")]) - migrations_apps = executor.loader.project_state(("migrations", "0001_initial")).apps + migrations_apps = executor.loader.project_state( + ("migrations", "0001_initial") + ).apps Editor = migrations_apps.get_model("migrations", "Editor") self.assertFalse(Editor.objects.exists()) # Record previous migration as successful. @@ -163,10 +186,12 @@ class ExecutorTests(MigrationTestBase): executor.migrate([("migrations", None)]) self.assertFalse(Editor.objects.exists()) - @override_settings(MIGRATION_MODULES={ - "migrations": "migrations.test_migrations", - "migrations2": "migrations2.test_migrations_2", - }) + @override_settings( + MIGRATION_MODULES={ + "migrations": "migrations.test_migrations", + "migrations2": "migrations2.test_migrations_2", + } + ) def test_empty_plan(self): """ Re-planning a full migration of a fully-migrated set doesn't @@ -179,10 +204,12 @@ class ExecutorTests(MigrationTestBase): """ # Make the initial plan, check it executor = MigrationExecutor(connection) - plan = executor.migration_plan([ - ("migrations", "0002_second"), - ("migrations2", "0001_initial"), - ]) + plan = executor.migration_plan( + [ + ("migrations", "0002_second"), + ("migrations2", "0001_initial"), + ] + ) self.assertEqual( plan, [ @@ -192,35 +219,40 @@ class ExecutorTests(MigrationTestBase): ], ) # Fake-apply all migrations - executor.migrate([ - ("migrations", "0002_second"), - ("migrations2", "0001_initial") - ], fake=True) + executor.migrate( + [("migrations", "0002_second"), ("migrations2", "0001_initial")], fake=True + ) # Rebuild the graph to reflect the new DB state executor.loader.build_graph() # Now plan a second time and make sure it's empty - plan = executor.migration_plan([ - ("migrations", "0002_second"), - ("migrations2", "0001_initial"), - ]) + plan = executor.migration_plan( + [ + ("migrations", "0002_second"), + ("migrations2", "0001_initial"), + ] + ) self.assertEqual(plan, []) # The resulting state should include applied migrations. - state = executor.migrate([ - ("migrations", "0002_second"), - ("migrations2", "0001_initial"), - ]) - self.assertIn(('migrations', 'book'), state.models) - self.assertIn(('migrations', 'author'), state.models) - self.assertIn(('migrations2', 'otherauthor'), state.models) + state = executor.migrate( + [ + ("migrations", "0002_second"), + ("migrations2", "0001_initial"), + ] + ) + self.assertIn(("migrations", "book"), state.models) + self.assertIn(("migrations", "author"), state.models) + self.assertIn(("migrations2", "otherauthor"), state.models) # Erase all the fake records executor.recorder.record_unapplied("migrations2", "0001_initial") executor.recorder.record_unapplied("migrations", "0002_second") executor.recorder.record_unapplied("migrations", "0001_initial") - @override_settings(MIGRATION_MODULES={ - "migrations": "migrations.test_migrations", - "migrations2": "migrations2.test_migrations_2_no_deps", - }) + @override_settings( + MIGRATION_MODULES={ + "migrations": "migrations.test_migrations", + "migrations2": "migrations2.test_migrations_2_no_deps", + } + ) def test_mixed_plan_not_supported(self): """ Although the MigrationExecutor interfaces allows for mixed migration @@ -240,19 +272,25 @@ class ExecutorTests(MigrationTestBase): executor.migrate(None, plan) # Rebuild the graph to reflect the new DB state executor.loader.build_graph() - self.assertIn(('migrations', '0001_initial'), executor.loader.applied_migrations) - self.assertIn(('migrations', '0002_second'), executor.loader.applied_migrations) - self.assertNotIn(('migrations2', '0001_initial'), executor.loader.applied_migrations) + self.assertIn( + ("migrations", "0001_initial"), executor.loader.applied_migrations + ) + self.assertIn(("migrations", "0002_second"), executor.loader.applied_migrations) + self.assertNotIn( + ("migrations2", "0001_initial"), executor.loader.applied_migrations + ) # Generate mixed plan - plan = executor.migration_plan([ - ("migrations", None), - ("migrations2", "0001_initial"), - ]) + plan = executor.migration_plan( + [ + ("migrations", None), + ("migrations2", "0001_initial"), + ] + ) msg = ( - 'Migration plans with both forwards and backwards migrations are ' - 'not supported. Please split your migration process into separate ' - 'plans of only forwards OR backwards migrations.' + "Migration plans with both forwards and backwards migrations are " + "not supported. Please split your migration process into separate " + "plans of only forwards OR backwards migrations." ) with self.assertRaisesMessage(InvalidMigrationPlan, msg) as cm: executor.migrate(None, plan) @@ -266,10 +304,12 @@ class ExecutorTests(MigrationTestBase): ) # Rebuild the graph to reflect the new DB state executor.loader.build_graph() - executor.migrate([ - ("migrations", None), - ("migrations2", None), - ]) + executor.migrate( + [ + ("migrations", None), + ("migrations2", None), + ] + ) # Are the tables gone? self.assertTableNotExists("migrations_author") self.assertTableNotExists("migrations_book") @@ -284,6 +324,7 @@ class ExecutorTests(MigrationTestBase): def fake_storer(phase, migration=None, fake=None): state["faked"] = fake + executor = MigrationExecutor(connection, progress_callback=fake_storer) # Were the tables there before? self.assertTableNotExists("migrations_author") @@ -347,37 +388,37 @@ class ExecutorTests(MigrationTestBase): """ with isolate_lru_cache(global_apps.get_swappable_settings_name): executor = MigrationExecutor(connection) - self.assertTableNotExists('migrations_author') - self.assertTableNotExists('migrations_tribble') + self.assertTableNotExists("migrations_author") + self.assertTableNotExists("migrations_tribble") # Migrate forwards - executor.migrate([('migrations', '0001_initial')]) - self.assertTableExists('migrations_author') - self.assertTableExists('migrations_tribble') + executor.migrate([("migrations", "0001_initial")]) + self.assertTableExists("migrations_author") + self.assertTableExists("migrations_tribble") # The soft-application detection works. # Change table_names to not return auth_user during this as it # wouldn't be there in a normal run, and ensure migrations.Author # exists in the global app registry temporarily. old_table_names = connection.introspection.table_names connection.introspection.table_names = lambda c: [ - x for x in old_table_names(c) if x != 'auth_user' + x for x in old_table_names(c) if x != "auth_user" ] migrations_apps = executor.loader.project_state( - ('migrations', '0001_initial'), + ("migrations", "0001_initial"), ).apps - global_apps.get_app_config('migrations').models['author'] = ( - migrations_apps.get_model('migrations', 'author') - ) + global_apps.get_app_config("migrations").models[ + "author" + ] = migrations_apps.get_model("migrations", "author") try: - migration = executor.loader.get_migration('auth', '0001_initial') + migration = executor.loader.get_migration("auth", "0001_initial") self.assertIs(executor.detect_soft_applied(None, migration)[0], True) finally: connection.introspection.table_names = old_table_names - del global_apps.get_app_config('migrations').models['author'] + del global_apps.get_app_config("migrations").models["author"] # Migrate back to clean up the database. executor.loader.build_graph() - executor.migrate([('migrations', None)]) - self.assertTableNotExists('migrations_author') - self.assertTableNotExists('migrations_tribble') + executor.migrate([("migrations", None)]) + self.assertTableNotExists("migrations_author") + self.assertTableNotExists("migrations_tribble") @override_settings( MIGRATION_MODULES={ @@ -442,7 +483,7 @@ class ExecutorTests(MigrationTestBase): INSTALLED_APPS=[ "migrations.migrations_test_apps.lookuperror_a", "migrations.migrations_test_apps.lookuperror_b", - "migrations.migrations_test_apps.lookuperror_c" + "migrations.migrations_test_apps.lookuperror_c", ] ) def test_unrelated_model_lookups_forwards(self): @@ -463,10 +504,12 @@ class ExecutorTests(MigrationTestBase): # Migrate forwards -- This led to a lookup LookupErrors because # lookuperror_b.B2 is already applied - executor.migrate([ - ("lookuperror_a", "0004_a4"), - ("lookuperror_c", "0003_c3"), - ]) + executor.migrate( + [ + ("lookuperror_a", "0004_a4"), + ("lookuperror_c", "0003_c3"), + ] + ) self.assertTableExists("lookuperror_a_a4") self.assertTableExists("lookuperror_c_c3") @@ -474,11 +517,13 @@ class ExecutorTests(MigrationTestBase): executor.loader.build_graph() finally: # Cleanup - executor.migrate([ - ("lookuperror_a", None), - ("lookuperror_b", None), - ("lookuperror_c", None), - ]) + executor.migrate( + [ + ("lookuperror_a", None), + ("lookuperror_b", None), + ("lookuperror_c", None), + ] + ) self.assertTableNotExists("lookuperror_a_a1") self.assertTableNotExists("lookuperror_b_b1") self.assertTableNotExists("lookuperror_c_c1") @@ -487,7 +532,7 @@ class ExecutorTests(MigrationTestBase): INSTALLED_APPS=[ "migrations.migrations_test_apps.lookuperror_a", "migrations.migrations_test_apps.lookuperror_b", - "migrations.migrations_test_apps.lookuperror_c" + "migrations.migrations_test_apps.lookuperror_c", ] ) def test_unrelated_model_lookups_backwards(self): @@ -501,11 +546,13 @@ class ExecutorTests(MigrationTestBase): self.assertTableNotExists("lookuperror_a_a1") self.assertTableNotExists("lookuperror_b_b1") self.assertTableNotExists("lookuperror_c_c1") - executor.migrate([ - ("lookuperror_a", "0004_a4"), - ("lookuperror_b", "0003_b3"), - ("lookuperror_c", "0003_c3"), - ]) + executor.migrate( + [ + ("lookuperror_a", "0004_a4"), + ("lookuperror_b", "0003_b3"), + ("lookuperror_c", "0003_c3"), + ] + ) self.assertTableExists("lookuperror_b_b3") self.assertTableExists("lookuperror_a_a4") self.assertTableExists("lookuperror_c_c3") @@ -520,18 +567,15 @@ class ExecutorTests(MigrationTestBase): executor.loader.build_graph() finally: # Cleanup - executor.migrate([ - ("lookuperror_b", None), - ("lookuperror_c", None) - ]) + executor.migrate([("lookuperror_b", None), ("lookuperror_c", None)]) self.assertTableNotExists("lookuperror_a_a1") self.assertTableNotExists("lookuperror_b_b1") self.assertTableNotExists("lookuperror_c_c1") @override_settings( INSTALLED_APPS=[ - 'migrations.migrations_test_apps.mutate_state_a', - 'migrations.migrations_test_apps.mutate_state_b', + "migrations.migrations_test_apps.mutate_state_a", + "migrations.migrations_test_apps.mutate_state_b", ] ) def test_unrelated_applied_migrations_mutate_state(self): @@ -540,24 +584,32 @@ class ExecutorTests(MigrationTestBase): state in both directions. """ executor = MigrationExecutor(connection) - executor.migrate([ - ('mutate_state_b', '0002_add_field'), - ]) + executor.migrate( + [ + ("mutate_state_b", "0002_add_field"), + ] + ) # Migrate forward. executor.loader.build_graph() - state = executor.migrate([ - ('mutate_state_a', '0001_initial'), - ]) - self.assertIn('added', state.models['mutate_state_b', 'b'].fields) + state = executor.migrate( + [ + ("mutate_state_a", "0001_initial"), + ] + ) + self.assertIn("added", state.models["mutate_state_b", "b"].fields) executor.loader.build_graph() # Migrate backward. - state = executor.migrate([ - ('mutate_state_a', None), - ]) - self.assertIn('added', state.models['mutate_state_b', 'b'].fields) - executor.migrate([ - ('mutate_state_b', None), - ]) + state = executor.migrate( + [ + ("mutate_state_a", None), + ] + ) + self.assertIn("added", state.models["mutate_state_b", "b"].fields) + executor.migrate( + [ + ("mutate_state_b", None), + ] + ) @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"}) def test_process_callback(self): @@ -573,17 +625,21 @@ class ExecutorTests(MigrationTestBase): # Were the tables there before? self.assertTableNotExists("migrations_author") self.assertTableNotExists("migrations_tribble") - executor.migrate([ - ("migrations", "0001_initial"), - ("migrations", "0002_second"), - ]) + executor.migrate( + [ + ("migrations", "0001_initial"), + ("migrations", "0002_second"), + ] + ) # Rebuild the graph to reflect the new DB state executor.loader.build_graph() - executor.migrate([ - ("migrations", None), - ("migrations", None), - ]) + executor.migrate( + [ + ("migrations", None), + ("migrations", None), + ] + ) self.assertTableNotExists("migrations_author") self.assertTableNotExists("migrations_tribble") @@ -591,16 +647,16 @@ class ExecutorTests(MigrationTestBase): expected = [ ("render_start",), ("render_success",), - ("apply_start", migrations['migrations', '0001_initial'], False), - ("apply_success", migrations['migrations', '0001_initial'], False), - ("apply_start", migrations['migrations', '0002_second'], False), - ("apply_success", migrations['migrations', '0002_second'], False), + ("apply_start", migrations["migrations", "0001_initial"], False), + ("apply_success", migrations["migrations", "0001_initial"], False), + ("apply_start", migrations["migrations", "0002_second"], False), + ("apply_success", migrations["migrations", "0002_second"], False), ("render_start",), ("render_success",), - ("unapply_start", migrations['migrations', '0002_second'], False), - ("unapply_success", migrations['migrations', '0002_second'], False), - ("unapply_start", migrations['migrations', '0001_initial'], False), - ("unapply_success", migrations['migrations', '0001_initial'], False), + ("unapply_start", migrations["migrations", "0002_second"], False), + ("unapply_success", migrations["migrations", "0002_second"], False), + ("unapply_start", migrations["migrations", "0001_initial"], False), + ("unapply_success", migrations["migrations", "0001_initial"], False), ] self.assertEqual(call_args_list, expected) @@ -616,10 +672,12 @@ class ExecutorTests(MigrationTestBase): self.assertTableNotExists("author_app_author") self.assertTableNotExists("book_app_book") # Apply initial migrations - executor.migrate([ - ("author_app", "0001_initial"), - ("book_app", "0001_initial"), - ]) + executor.migrate( + [ + ("author_app", "0001_initial"), + ("book_app", "0001_initial"), + ] + ) self.assertTableExists("author_app_author") self.assertTableExists("book_app_book") # Rebuild the graph to reflect the new DB state @@ -640,7 +698,9 @@ class ExecutorTests(MigrationTestBase): self.assertTableNotExists("book_app_book") executor.migrate([("author_app", None)], fake=True) - @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"} + ) def test_apply_all_replaced_marks_replacement_as_applied(self): """ Applying all replaced migrations marks replacement as applied (#24628). @@ -663,7 +723,9 @@ class ExecutorTests(MigrationTestBase): recorder.applied_migrations(), ) - @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"} + ) def test_migrate_marks_replacement_applied_even_if_it_did_nothing(self): """ A new squash migration will be marked as applied even if all its @@ -684,59 +746,69 @@ class ExecutorTests(MigrationTestBase): recorder.applied_migrations(), ) - @override_settings(MIGRATION_MODULES={'migrations': 'migrations.test_migrations_squashed'}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"} + ) def test_migrate_marks_replacement_unapplied(self): executor = MigrationExecutor(connection) - executor.migrate([('migrations', '0001_squashed_0002')]) + executor.migrate([("migrations", "0001_squashed_0002")]) try: self.assertIn( - ('migrations', '0001_squashed_0002'), + ("migrations", "0001_squashed_0002"), executor.recorder.applied_migrations(), ) finally: executor.loader.build_graph() - executor.migrate([('migrations', None)]) + executor.migrate([("migrations", None)]) self.assertNotIn( - ('migrations', '0001_squashed_0002'), + ("migrations", "0001_squashed_0002"), executor.recorder.applied_migrations(), ) # When the feature is False, the operation and the record won't be # performed in a transaction and the test will systematically pass. - @skipUnlessDBFeature('can_rollback_ddl') + @skipUnlessDBFeature("can_rollback_ddl") def test_migrations_applied_and_recorded_atomically(self): """Migrations are applied and recorded atomically.""" + class Migration(migrations.Migration): operations = [ - migrations.CreateModel('model', [ - ('id', models.AutoField(primary_key=True)), - ]), + migrations.CreateModel( + "model", + [ + ("id", models.AutoField(primary_key=True)), + ], + ), ] executor = MigrationExecutor(connection) - with mock.patch('django.db.migrations.executor.MigrationExecutor.record_migration') as record_migration: - record_migration.side_effect = RuntimeError('Recording migration failed.') - with self.assertRaisesMessage(RuntimeError, 'Recording migration failed.'): + with mock.patch( + "django.db.migrations.executor.MigrationExecutor.record_migration" + ) as record_migration: + record_migration.side_effect = RuntimeError("Recording migration failed.") + with self.assertRaisesMessage(RuntimeError, "Recording migration failed."): executor.apply_migration( ProjectState(), - Migration('0001_initial', 'record_migration'), + Migration("0001_initial", "record_migration"), ) - executor.migrate([('migrations', '0001_initial')]) + executor.migrate([("migrations", "0001_initial")]) # The migration isn't recorded as applied since it failed. migration_recorder = MigrationRecorder(connection) self.assertIs( migration_recorder.migration_qs.filter( - app='record_migration', name='0001_initial', + app="record_migration", + name="0001_initial", ).exists(), False, ) - self.assertTableNotExists('record_migration_model') + self.assertTableNotExists("record_migration_model") def test_migrations_not_applied_on_deferred_sql_failure(self): """Migrations are not recorded if deferred SQL application fails.""" + class DeferredSQL: def __str__(self): - raise DatabaseError('Failed to apply deferred SQL') + raise DatabaseError("Failed to apply deferred SQL") class Migration(migrations.Migration): atomic = False @@ -745,21 +817,22 @@ class ExecutorTests(MigrationTestBase): schema_editor.deferred_sql.append(DeferredSQL()) executor = MigrationExecutor(connection) - with self.assertRaisesMessage(DatabaseError, 'Failed to apply deferred SQL'): + with self.assertRaisesMessage(DatabaseError, "Failed to apply deferred SQL"): executor.apply_migration( ProjectState(), - Migration('0001_initial', 'deferred_sql'), + Migration("0001_initial", "deferred_sql"), ) # The migration isn't recorded as applied since it failed. migration_recorder = MigrationRecorder(connection) self.assertIs( migration_recorder.migration_qs.filter( - app='deferred_sql', name='0001_initial', + app="deferred_sql", + name="0001_initial", ).exists(), False, ) - @mock.patch.object(MigrationRecorder, 'has_table', return_value=False) + @mock.patch.object(MigrationRecorder, "has_table", return_value=False) def test_migrate_skips_schema_creation(self, mocked_has_table): """ The django_migrations table is not created if there are no migrations @@ -780,15 +853,17 @@ class FakeLoader: class FakeMigration: """Really all we need is any object with a debug-useful repr.""" + def __init__(self, name): self.name = name def __repr__(self): - return 'M<%s>' % self.name + return "M<%s>" % self.name class ExecutorUnitTests(SimpleTestCase): """(More) isolated unit tests for executor methods.""" + def test_minimize_rollbacks(self): """ Minimize unnecessary rollbacks in connected apps. @@ -799,12 +874,12 @@ class ExecutorUnitTests(SimpleTestCase): to be rolled back since we're not rolling back appA 0001), we migrate to just before appA-0002. """ - a1_impl = FakeMigration('a1') - a1 = ('a', '1') - a2_impl = FakeMigration('a2') - a2 = ('a', '2') - b1_impl = FakeMigration('b1') - b1 = ('b', '1') + a1_impl = FakeMigration("a1") + a1 = ("a", "1") + a2_impl = FakeMigration("a2") + a2 = ("a", "2") + b1_impl = FakeMigration("b1") + b1 = ("b", "1") graph = MigrationGraph() graph.add_node(a1, a1_impl) graph.add_node(a2, a2_impl) @@ -813,11 +888,14 @@ class ExecutorUnitTests(SimpleTestCase): graph.add_dependency(None, a2, a1) executor = MigrationExecutor(None) - executor.loader = FakeLoader(graph, { - a1: a1_impl, - b1: b1_impl, - a2: a2_impl, - }) + executor.loader = FakeLoader( + graph, + { + a1: a1_impl, + b1: b1_impl, + a2: a2_impl, + }, + ) plan = executor.migration_plan({a1}) @@ -832,18 +910,18 @@ class ExecutorUnitTests(SimpleTestCase): \ \ b: \- 1 <--- 2 """ - a1_impl = FakeMigration('a1') - a1 = ('a', '1') - a2_impl = FakeMigration('a2') - a2 = ('a', '2') - a3_impl = FakeMigration('a3') - a3 = ('a', '3') - a4_impl = FakeMigration('a4') - a4 = ('a', '4') - b1_impl = FakeMigration('b1') - b1 = ('b', '1') - b2_impl = FakeMigration('b2') - b2 = ('b', '2') + a1_impl = FakeMigration("a1") + a1 = ("a", "1") + a2_impl = FakeMigration("a2") + a2 = ("a", "2") + a3_impl = FakeMigration("a3") + a3 = ("a", "3") + a4_impl = FakeMigration("a4") + a4 = ("a", "4") + b1_impl = FakeMigration("b1") + b1 = ("b", "1") + b2_impl = FakeMigration("b2") + b2 = ("b", "2") graph = MigrationGraph() graph.add_node(a1, a1_impl) graph.add_node(a2, a2_impl) @@ -860,14 +938,17 @@ class ExecutorUnitTests(SimpleTestCase): graph.add_dependency(None, b2, a2) executor = MigrationExecutor(None) - executor.loader = FakeLoader(graph, { - a1: a1_impl, - b1: b1_impl, - a2: a2_impl, - b2: b2_impl, - a3: a3_impl, - a4: a4_impl, - }) + executor.loader = FakeLoader( + graph, + { + a1: a1_impl, + b1: b1_impl, + a2: a2_impl, + b2: b2_impl, + a3: a3_impl, + a4: a4_impl, + }, + ) plan = executor.migration_plan({a1}) @@ -886,14 +967,14 @@ class ExecutorUnitTests(SimpleTestCase): If a1 is applied already and a2 is not, and we're asked to migrate to a1, don't apply or unapply b1 or c1, regardless of their current state. """ - a1_impl = FakeMigration('a1') - a1 = ('a', '1') - a2_impl = FakeMigration('a2') - a2 = ('a', '2') - b1_impl = FakeMigration('b1') - b1 = ('b', '1') - c1_impl = FakeMigration('c1') - c1 = ('c', '1') + a1_impl = FakeMigration("a1") + a1 = ("a", "1") + a2_impl = FakeMigration("a2") + a2 = ("a", "2") + b1_impl = FakeMigration("b1") + b1 = ("b", "1") + c1_impl = FakeMigration("c1") + c1 = ("c", "1") graph = MigrationGraph() graph.add_node(a1, a1_impl) graph.add_node(a2, a2_impl) @@ -904,10 +985,13 @@ class ExecutorUnitTests(SimpleTestCase): graph.add_dependency(None, c1, a1) executor = MigrationExecutor(None) - executor.loader = FakeLoader(graph, { - a1: a1_impl, - b1: b1_impl, - }) + executor.loader = FakeLoader( + graph, + { + a1: a1_impl, + b1: b1_impl, + }, + ) plan = executor.migration_plan({a1}) diff --git a/tests/migrations/test_fake_initial_case_insensitive/fake_initial/0001_initial.py b/tests/migrations/test_fake_initial_case_insensitive/fake_initial/0001_initial.py index dc492b3486..6fd6a0d435 100644 --- a/tests/migrations/test_fake_initial_case_insensitive/fake_initial/0001_initial.py +++ b/tests/migrations/test_fake_initial_case_insensitive/fake_initial/0001_initial.py @@ -6,23 +6,25 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - 'fakeinitialmodel', + "fakeinitialmodel", [ - ('id', models.AutoField(primary_key=True)), - ('field', models.CharField(max_length=20)), + ("id", models.AutoField(primary_key=True)), + ("field", models.CharField(max_length=20)), ], options={ - 'db_table': 'migrations_mIxEd_cAsE_mOdEl', + "db_table": "migrations_mIxEd_cAsE_mOdEl", }, ), migrations.AddField( - model_name='fakeinitialmodel', - name='field_mixed_case', - field=models.CharField(max_length=20, db_column='fIeLd_mIxEd_cAsE'), + model_name="fakeinitialmodel", + name="field_mixed_case", + field=models.CharField(max_length=20, db_column="fIeLd_mIxEd_cAsE"), ), migrations.AddField( - model_name='fakeinitialmodel', - name='fake_initial_model', - field=models.ManyToManyField(to='migrations.fakeinitialmodel', db_table='m2m_mIxEd_cAsE'), + model_name="fakeinitialmodel", + name="fake_initial_model", + field=models.ManyToManyField( + to="migrations.fakeinitialmodel", db_table="m2m_mIxEd_cAsE" + ), ), ] diff --git a/tests/migrations/test_fake_initial_case_insensitive/initial/0001_initial.py b/tests/migrations/test_fake_initial_case_insensitive/initial/0001_initial.py index 339d57d21c..e3c1fc8d18 100644 --- a/tests/migrations/test_fake_initial_case_insensitive/initial/0001_initial.py +++ b/tests/migrations/test_fake_initial_case_insensitive/initial/0001_initial.py @@ -6,18 +6,23 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name='fakeinitialmodel', + name="fakeinitialmodel", fields=[ - ('id', models.AutoField(primary_key=True)), - ('field', models.CharField(max_length=20)), - ('field_mixed_case', models.CharField(max_length=20, db_column='FiEld_MiXeD_CaSe')), + ("id", models.AutoField(primary_key=True)), + ("field", models.CharField(max_length=20)), ( - 'fake_initial_mode', - models.ManyToManyField('migrations.FakeInitialModel', db_table='m2m_MiXeD_CaSe'), + "field_mixed_case", + models.CharField(max_length=20, db_column="FiEld_MiXeD_CaSe"), + ), + ( + "fake_initial_mode", + models.ManyToManyField( + "migrations.FakeInitialModel", db_table="m2m_MiXeD_CaSe" + ), ), ], options={ - 'db_table': 'migrations_MiXeD_CaSe_MoDel', + "db_table": "migrations_MiXeD_CaSe_MoDel", }, ), ] diff --git a/tests/migrations/test_graph.py b/tests/migrations/test_graph.py index 10a5696f57..f62b44180a 100644 --- a/tests/migrations/test_graph.py +++ b/tests/migrations/test_graph.py @@ -1,6 +1,4 @@ -from django.db.migrations.exceptions import ( - CircularDependencyError, NodeNotFoundError, -) +from django.db.migrations.exceptions import CircularDependencyError, NodeNotFoundError from django.db.migrations.graph import DummyNode, MigrationGraph, Node from django.test import SimpleTestCase @@ -34,7 +32,7 @@ class GraphTests(SimpleTestCase): # Test root migration case self.assertEqual( graph.forwards_plan(("app_a", "0001")), - [('app_a', '0001')], + [("app_a", "0001")], ) # Test branch B only self.assertEqual( @@ -45,23 +43,27 @@ class GraphTests(SimpleTestCase): self.assertEqual( graph.forwards_plan(("app_a", "0004")), [ - ('app_b', '0001'), ('app_b', '0002'), ('app_a', '0001'), - ('app_a', '0002'), ('app_a', '0003'), ('app_a', '0004'), + ("app_b", "0001"), + ("app_b", "0002"), + ("app_a", "0001"), + ("app_a", "0002"), + ("app_a", "0003"), + ("app_a", "0004"), ], ) # Test reverse to b:0002 self.assertEqual( graph.backwards_plan(("app_b", "0002")), - [('app_a', '0004'), ('app_a', '0003'), ('app_b', '0002')], + [("app_a", "0004"), ("app_a", "0003"), ("app_b", "0002")], ) # Test roots and leaves self.assertEqual( graph.root_nodes(), - [('app_a', '0001'), ('app_b', '0001')], + [("app_a", "0001"), ("app_b", "0001")], ) self.assertEqual( graph.leaf_nodes(), - [('app_a', '0004'), ('app_b', '0002')], + [("app_a", "0004"), ("app_b", "0002")], ) def test_complex_graph(self): @@ -96,33 +98,48 @@ class GraphTests(SimpleTestCase): # Test branch C only self.assertEqual( graph.forwards_plan(("app_c", "0002")), - [('app_b', '0001'), ('app_c', '0001'), ('app_a', '0001'), ('app_a', '0002'), ('app_c', '0002')], + [ + ("app_b", "0001"), + ("app_c", "0001"), + ("app_a", "0001"), + ("app_a", "0002"), + ("app_c", "0002"), + ], ) # Test whole graph self.assertEqual( graph.forwards_plan(("app_a", "0004")), [ - ('app_b', '0001'), ('app_c', '0001'), ('app_a', '0001'), - ('app_a', '0002'), ('app_c', '0002'), ('app_b', '0002'), - ('app_a', '0003'), ('app_a', '0004'), + ("app_b", "0001"), + ("app_c", "0001"), + ("app_a", "0001"), + ("app_a", "0002"), + ("app_c", "0002"), + ("app_b", "0002"), + ("app_a", "0003"), + ("app_a", "0004"), ], ) # Test reverse to b:0001 self.assertEqual( graph.backwards_plan(("app_b", "0001")), [ - ('app_a', '0004'), ('app_c', '0002'), ('app_c', '0001'), - ('app_a', '0003'), ('app_b', '0002'), ('app_b', '0001'), + ("app_a", "0004"), + ("app_c", "0002"), + ("app_c", "0001"), + ("app_a", "0003"), + ("app_b", "0002"), + ("app_b", "0001"), ], ) # Test roots and leaves self.assertEqual( graph.root_nodes(), - [('app_a', '0001'), ('app_b', '0001'), ('app_c', '0001')], + [("app_a", "0001"), ("app_b", "0001"), ("app_c", "0001")], ) self.assertEqual( graph.leaf_nodes(), - [('app_a', '0004'), ('app_b', '0002'), ('app_c', '0002')], + [("app_a", "0004"), ("app_b", "0002"), ("app_c", "0002")], ) def test_circular_graph(self): @@ -147,12 +164,12 @@ class GraphTests(SimpleTestCase): def test_circular_graph_2(self): graph = MigrationGraph() - graph.add_node(('A', '0001'), None) - graph.add_node(('C', '0001'), None) - graph.add_node(('B', '0001'), None) - graph.add_dependency('A.0001', ('A', '0001'), ('B', '0001')) - graph.add_dependency('B.0001', ('B', '0001'), ('A', '0001')) - graph.add_dependency('C.0001', ('C', '0001'), ('B', '0001')) + graph.add_node(("A", "0001"), None) + graph.add_node(("C", "0001"), None) + graph.add_node(("B", "0001"), None) + graph.add_dependency("A.0001", ("A", "0001"), ("B", "0001")) + graph.add_dependency("B.0001", ("B", "0001"), ("A", "0001")) + graph.add_dependency("C.0001", ("C", "0001"), ("B", "0001")) with self.assertRaises(CircularDependencyError): graph.ensure_not_cyclic() @@ -184,20 +201,18 @@ class GraphTests(SimpleTestCase): n = 50 graph = MigrationGraph() for i in range(1, n + 1): - graph.add_node(('app_a', str(i)), None) - graph.add_node(('app_b', str(i)), None) - graph.add_node(('app_c', str(i)), None) + graph.add_node(("app_a", str(i)), None) + graph.add_node(("app_b", str(i)), None) + graph.add_node(("app_c", str(i)), None) for i in range(1, n): - graph.add_dependency(None, ('app_b', str(i)), ('app_a', str(i))) - graph.add_dependency(None, ('app_c', str(i)), ('app_a', str(i))) - graph.add_dependency(None, ('app_a', str(i + 1)), ('app_b', str(i))) - graph.add_dependency(None, ('app_a', str(i + 1)), ('app_c', str(i))) - plan = graph.forwards_plan(('app_a', str(n))) + graph.add_dependency(None, ("app_b", str(i)), ("app_a", str(i))) + graph.add_dependency(None, ("app_c", str(i)), ("app_a", str(i))) + graph.add_dependency(None, ("app_a", str(i + 1)), ("app_b", str(i))) + graph.add_dependency(None, ("app_a", str(i + 1)), ("app_c", str(i))) + plan = graph.forwards_plan(("app_a", str(n))) expected = [ - (app, str(i)) - for i in range(1, n) - for app in ['app_a', 'app_c', 'app_b'] - ] + [('app_a', str(n))] + (app, str(i)) for i in range(1, n) for app in ["app_a", "app_c", "app_b"] + ] + [("app_a", str(n))] self.assertEqual(plan, expected) def test_plan_invalid_node(self): @@ -243,7 +258,9 @@ class GraphTests(SimpleTestCase): def test_validate_consistency_missing_parent(self): graph = MigrationGraph() graph.add_node(("app_a", "0001"), None) - graph.add_dependency("app_a.0001", ("app_a", "0001"), ("app_b", "0002"), skip_validation=True) + graph.add_dependency( + "app_a.0001", ("app_a", "0001"), ("app_b", "0002"), skip_validation=True + ) msg = "Migration app_a.0001 dependencies reference nonexistent parent node ('app_b', '0002')" with self.assertRaisesMessage(NodeNotFoundError, msg): graph.validate_consistency() @@ -251,7 +268,9 @@ class GraphTests(SimpleTestCase): def test_validate_consistency_missing_child(self): graph = MigrationGraph() graph.add_node(("app_b", "0002"), None) - graph.add_dependency("app_b.0002", ("app_a", "0001"), ("app_b", "0002"), skip_validation=True) + graph.add_dependency( + "app_b.0002", ("app_a", "0001"), ("app_b", "0002"), skip_validation=True + ) msg = "Migration app_b.0002 dependencies reference nonexistent child node ('app_a', '0001')" with self.assertRaisesMessage(NodeNotFoundError, msg): graph.validate_consistency() @@ -260,7 +279,9 @@ class GraphTests(SimpleTestCase): graph = MigrationGraph() graph.add_node(("app_a", "0001"), None) graph.add_node(("app_b", "0002"), None) - graph.add_dependency("app_a.0001", ("app_a", "0001"), ("app_b", "0002"), skip_validation=True) + graph.add_dependency( + "app_a.0001", ("app_a", "0001"), ("app_b", "0002"), skip_validation=True + ) graph.validate_consistency() def test_validate_consistency_dummy(self): @@ -271,9 +292,7 @@ class GraphTests(SimpleTestCase): msg = "app_a.0001 (req'd by app_b.0002) is missing!" graph = MigrationGraph() graph.add_dummy_node( - key=("app_a", "0001"), - origin="app_b.0002", - error_message=msg + key=("app_a", "0001"), origin="app_b.0002", error_message=msg ) with self.assertRaisesMessage(NodeNotFoundError, msg): graph.validate_consistency() @@ -284,14 +303,24 @@ class GraphTests(SimpleTestCase): """ # Add some dummy nodes to be replaced. graph = MigrationGraph() - graph.add_dummy_node(key=("app_a", "0001"), origin="app_a.0002", error_message="BAD!") - graph.add_dummy_node(key=("app_a", "0002"), origin="app_b.0001", error_message="BAD!") - graph.add_dependency("app_a.0002", ("app_a", "0002"), ("app_a", "0001"), skip_validation=True) + graph.add_dummy_node( + key=("app_a", "0001"), origin="app_a.0002", error_message="BAD!" + ) + graph.add_dummy_node( + key=("app_a", "0002"), origin="app_b.0001", error_message="BAD!" + ) + graph.add_dependency( + "app_a.0002", ("app_a", "0002"), ("app_a", "0001"), skip_validation=True + ) # Add some normal parent and child nodes to test dependency remapping. graph.add_node(("app_c", "0001"), None) graph.add_node(("app_b", "0001"), None) - graph.add_dependency("app_a.0001", ("app_a", "0001"), ("app_c", "0001"), skip_validation=True) - graph.add_dependency("app_b.0001", ("app_b", "0001"), ("app_a", "0002"), skip_validation=True) + graph.add_dependency( + "app_a.0001", ("app_a", "0001"), ("app_c", "0001"), skip_validation=True + ) + graph.add_dependency( + "app_b.0001", ("app_b", "0001"), ("app_a", "0002"), skip_validation=True + ) # Try replacing before replacement node exists. msg = ( "Unable to find replacement node ('app_a', '0001_squashed_0002'). It was either" @@ -300,7 +329,7 @@ class GraphTests(SimpleTestCase): with self.assertRaisesMessage(NodeNotFoundError, msg): graph.remove_replaced_nodes( replacement=("app_a", "0001_squashed_0002"), - replaced=[("app_a", "0001"), ("app_a", "0002")] + replaced=[("app_a", "0001"), ("app_a", "0002")], ) graph.add_node(("app_a", "0001_squashed_0002"), None) # Ensure `validate_consistency()` still raises an error at this stage. @@ -309,7 +338,7 @@ class GraphTests(SimpleTestCase): # Remove the dummy nodes. graph.remove_replaced_nodes( replacement=("app_a", "0001_squashed_0002"), - replaced=[("app_a", "0001"), ("app_a", "0002")] + replaced=[("app_a", "0001"), ("app_a", "0002")], ) # Ensure graph is now consistent and dependencies have been remapped graph.validate_consistency() @@ -339,16 +368,18 @@ class GraphTests(SimpleTestCase): with self.assertRaisesMessage(NodeNotFoundError, msg): graph.remove_replacement_node( replacement=("app_a", "0001_squashed_0002"), - replaced=[("app_a", "0001"), ("app_a", "0002")] + replaced=[("app_a", "0001"), ("app_a", "0002")], ) graph.add_node(("app_a", "0001_squashed_0002"), None) # Add a child node to test dependency remapping. graph.add_node(("app_b", "0001"), None) - graph.add_dependency("app_b.0001", ("app_b", "0001"), ("app_a", "0001_squashed_0002")) + graph.add_dependency( + "app_b.0001", ("app_b", "0001"), ("app_a", "0001_squashed_0002") + ) # Remove the replacement node. graph.remove_replacement_node( replacement=("app_a", "0001_squashed_0002"), - replaced=[("app_a", "0001"), ("app_a", "0002")] + replaced=[("app_a", "0001"), ("app_a", "0002")], ) # Ensure graph is consistent and child dependency has been remapped graph.validate_consistency() @@ -380,10 +411,16 @@ class GraphTests(SimpleTestCase): graph.add_node(("app_b", "0002"), None) graph.add_node(("app_c", "0001_squashed_0002"), None) - graph.add_dependency("app_b.0001", ("app_b", "0001"), ("app_c", "0001_squashed_0002")) + graph.add_dependency( + "app_b.0001", ("app_b", "0001"), ("app_c", "0001_squashed_0002") + ) graph.add_dependency("app_b.0002", ("app_b", "0002"), ("app_a", "0001")) graph.add_dependency("app_b.0002", ("app_b", "0002"), ("app_b", "0001")) - graph.add_dependency("app_c.0001_squashed_0002", ("app_c", "0001_squashed_0002"), ("app_b", "0002")) + graph.add_dependency( + "app_c.0001_squashed_0002", + ("app_c", "0001_squashed_0002"), + ("app_b", "0002"), + ) with self.assertRaises(CircularDependencyError): graph.ensure_not_cyclic() @@ -407,13 +444,13 @@ class GraphTests(SimpleTestCase): class NodeTests(SimpleTestCase): def test_node_repr(self): - node = Node(('app_a', '0001')) + node = Node(("app_a", "0001")) self.assertEqual(repr(node), "<Node: ('app_a', '0001')>") def test_dummynode_repr(self): node = DummyNode( - key=('app_a', '0001'), - origin='app_a.0001', - error_message='x is missing', + key=("app_a", "0001"), + origin="app_a.0001", + error_message="x is missing", ) self.assertEqual(repr(node), "<DummyNode: ('app_a', '0001')>") diff --git a/tests/migrations/test_loader.py b/tests/migrations/test_loader.py index 03a98506e3..de70c4d981 100644 --- a/tests/migrations/test_loader.py +++ b/tests/migrations/test_loader.py @@ -4,7 +4,9 @@ from importlib import import_module from django.db import connection, connections from django.db.migrations.exceptions import ( - AmbiguityError, InconsistentMigrationHistory, NodeNotFoundError, + AmbiguityError, + InconsistentMigrationHistory, + NodeNotFoundError, ) from django.db.migrations.loader import MigrationLoader from django.db.migrations.recorder import MigrationRecorder @@ -17,7 +19,8 @@ class RecorderTests(TestCase): """ Tests recording migrations as applied or not. """ - databases = {'default', 'other'} + + databases = {"default", "other"} def test_apply(self): """ @@ -34,7 +37,7 @@ class RecorderTests(TestCase): {("myapp", "0432_ponies")}, ) # That should not affect records of another database - recorder_other = MigrationRecorder(connections['other']) + recorder_other = MigrationRecorder(connections["other"]) self.assertEqual( {(x, y) for (x, y) in recorder_other.applied_migrations() if x == "myapp"}, set(), @@ -51,6 +54,7 @@ class LoaderTests(TestCase): Tests the disk and database loader, and running through migrations in memory. """ + def setUp(self): self.applied_records = [] @@ -66,7 +70,7 @@ class LoaderTests(TestCase): self.applied_records.append((recorder, app, name)) @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"}) - @modify_settings(INSTALLED_APPS={'append': 'basic'}) + @modify_settings(INSTALLED_APPS={"append": "basic"}) def test_load(self): """ Makes sure the loader can load the migrations for the test apps, @@ -87,33 +91,40 @@ class LoaderTests(TestCase): author_state = project_state.models["migrations", "author"] self.assertEqual( - list(author_state.fields), - ["id", "name", "slug", "age", "rating"] + list(author_state.fields), ["id", "name", "slug", "age", "rating"] ) book_state = project_state.models["migrations", "book"] - self.assertEqual(list(book_state.fields), ['id', 'author']) + self.assertEqual(list(book_state.fields), ["id", "author"]) # Ensure we've included unmigrated apps in there too self.assertIn("basic", project_state.real_apps) - @override_settings(MIGRATION_MODULES={ - 'migrations': 'migrations.test_migrations', - 'migrations2': 'migrations2.test_migrations_2', - }) - @modify_settings(INSTALLED_APPS={'append': 'migrations2'}) + @override_settings( + MIGRATION_MODULES={ + "migrations": "migrations.test_migrations", + "migrations2": "migrations2.test_migrations_2", + } + ) + @modify_settings(INSTALLED_APPS={"append": "migrations2"}) def test_plan_handles_repeated_migrations(self): """ _generate_plan() doesn't readd migrations already in the plan (#29180). """ migration_loader = MigrationLoader(connection) - nodes = [('migrations', '0002_second'), ('migrations2', '0001_initial')] + nodes = [("migrations", "0002_second"), ("migrations2", "0001_initial")] self.assertEqual( migration_loader.graph._generate_plan(nodes, at_end=True), - [('migrations', '0001_initial'), ('migrations', '0002_second'), ('migrations2', '0001_initial')] + [ + ("migrations", "0001_initial"), + ("migrations", "0002_second"), + ("migrations2", "0001_initial"), + ], ) - @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_unmigdep"}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_unmigdep"} + ) def test_load_unmigrated_dependency(self): """ Makes sure the loader can load migrations with a dependency on an unmigrated app. @@ -123,19 +134,23 @@ class LoaderTests(TestCase): self.assertEqual( migration_loader.graph.forwards_plan(("migrations", "0001_initial")), [ - ('contenttypes', '0001_initial'), - ('auth', '0001_initial'), + ("contenttypes", "0001_initial"), + ("auth", "0001_initial"), ("migrations", "0001_initial"), ], ) # Now render it out! project_state = migration_loader.project_state(("migrations", "0001_initial")) - self.assertEqual(len([m for a, m in project_state.models if a == "migrations"]), 1) + self.assertEqual( + len([m for a, m in project_state.models if a == "migrations"]), 1 + ) book_state = project_state.models["migrations", "book"] - self.assertEqual(list(book_state.fields), ['id', 'user']) + self.assertEqual(list(book_state.fields), ["id", "user"]) - @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_run_before"}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_run_before"} + ) def test_run_before(self): """ Makes sure the loader uses Migration.run_before. @@ -151,11 +166,13 @@ class LoaderTests(TestCase): ], ) - @override_settings(MIGRATION_MODULES={ - "migrations": "migrations.test_migrations_first", - "migrations2": "migrations2.test_migrations_2_first", - }) - @modify_settings(INSTALLED_APPS={'append': 'migrations2'}) + @override_settings( + MIGRATION_MODULES={ + "migrations": "migrations.test_migrations_first", + "migrations2": "migrations2.test_migrations_2_first", + } + ) + @modify_settings(INSTALLED_APPS={"append": "migrations2"}) def test_first(self): """ Makes sure the '__first__' migrations build correctly. @@ -187,39 +204,47 @@ class LoaderTests(TestCase): migration_loader.get_migration_by_prefix("migrations", "blarg") def test_load_import_error(self): - with override_settings(MIGRATION_MODULES={"migrations": "import_error_package"}): + with override_settings( + MIGRATION_MODULES={"migrations": "import_error_package"} + ): with self.assertRaises(ImportError): MigrationLoader(connection) def test_load_module_file(self): - with override_settings(MIGRATION_MODULES={"migrations": "migrations.faulty_migrations.file"}): + with override_settings( + MIGRATION_MODULES={"migrations": "migrations.faulty_migrations.file"} + ): loader = MigrationLoader(connection) self.assertIn( - "migrations", loader.unmigrated_apps, - "App with migrations module file not in unmigrated apps." + "migrations", + loader.unmigrated_apps, + "App with migrations module file not in unmigrated apps.", ) def test_load_empty_dir(self): - with override_settings(MIGRATION_MODULES={"migrations": "migrations.faulty_migrations.namespace"}): + with override_settings( + MIGRATION_MODULES={"migrations": "migrations.faulty_migrations.namespace"} + ): loader = MigrationLoader(connection) self.assertIn( - "migrations", loader.unmigrated_apps, - "App missing __init__.py in migrations module not in unmigrated apps." + "migrations", + loader.unmigrated_apps, + "App missing __init__.py in migrations module not in unmigrated apps.", ) @override_settings( - INSTALLED_APPS=['migrations.migrations_test_apps.migrated_app'], + INSTALLED_APPS=["migrations.migrations_test_apps.migrated_app"], ) def test_marked_as_migrated(self): """ Undefined MIGRATION_MODULES implies default migration module. """ migration_loader = MigrationLoader(connection) - self.assertEqual(migration_loader.migrated_apps, {'migrated_app'}) + self.assertEqual(migration_loader.migrated_apps, {"migrated_app"}) self.assertEqual(migration_loader.unmigrated_apps, set()) @override_settings( - INSTALLED_APPS=['migrations.migrations_test_apps.migrated_app'], + INSTALLED_APPS=["migrations.migrations_test_apps.migrated_app"], MIGRATION_MODULES={"migrated_app": None}, ) def test_marked_as_unmigrated(self): @@ -228,11 +253,11 @@ class LoaderTests(TestCase): """ migration_loader = MigrationLoader(connection) self.assertEqual(migration_loader.migrated_apps, set()) - self.assertEqual(migration_loader.unmigrated_apps, {'migrated_app'}) + self.assertEqual(migration_loader.unmigrated_apps, {"migrated_app"}) @override_settings( - INSTALLED_APPS=['migrations.migrations_test_apps.migrated_app'], - MIGRATION_MODULES={'migrated_app': 'missing-module'}, + INSTALLED_APPS=["migrations.migrations_test_apps.migrated_app"], + MIGRATION_MODULES={"migrated_app": "missing-module"}, ) def test_explicit_missing_module(self): """ @@ -240,13 +265,15 @@ class LoaderTests(TestCase): raised during the importation attempt should be propagated unless `ignore_no_migrations=True`. """ - with self.assertRaisesMessage(ImportError, 'missing-module'): + with self.assertRaisesMessage(ImportError, "missing-module"): migration_loader = MigrationLoader(connection) migration_loader = MigrationLoader(connection, ignore_no_migrations=True) self.assertEqual(migration_loader.migrated_apps, set()) - self.assertEqual(migration_loader.unmigrated_apps, {'migrated_app'}) + self.assertEqual(migration_loader.unmigrated_apps, {"migrated_app"}) - @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"} + ) def test_loading_squashed(self): "Tests loading a squashed migration" migration_loader = MigrationLoader(connection) @@ -258,14 +285,16 @@ class LoaderTests(TestCase): 1, ) # However, fake-apply one migration and it should now use the old two - self.record_applied(recorder, 'migrations', '0001_initial') + self.record_applied(recorder, "migrations", "0001_initial") migration_loader.build_graph() self.assertEqual( len([x for x in migration_loader.graph.nodes if x[0] == "migrations"]), 2, ) - @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed_complex"}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed_complex"} + ) def test_loading_squashed_complex(self): "Tests loading a complex set of squashed migrations" @@ -274,7 +303,7 @@ class LoaderTests(TestCase): self.addCleanup(recorder.flush) def num_nodes(): - plan = set(loader.graph.forwards_plan(('migrations', '7_auto'))) + plan = set(loader.graph.forwards_plan(("migrations", "7_auto"))) return len(plan - loader.applied_migrations.keys()) # Empty database: use squashed migration @@ -282,83 +311,99 @@ class LoaderTests(TestCase): self.assertEqual(num_nodes(), 5) # Starting at 1 or 2 should use the squashed migration too - self.record_applied(recorder, 'migrations', '1_auto') + self.record_applied(recorder, "migrations", "1_auto") loader.build_graph() self.assertEqual(num_nodes(), 4) - self.record_applied(recorder, 'migrations', '2_auto') + self.record_applied(recorder, "migrations", "2_auto") loader.build_graph() self.assertEqual(num_nodes(), 3) # However, starting at 3 to 5 cannot use the squashed migration - self.record_applied(recorder, 'migrations', '3_auto') + self.record_applied(recorder, "migrations", "3_auto") loader.build_graph() self.assertEqual(num_nodes(), 4) - self.record_applied(recorder, 'migrations', '4_auto') + self.record_applied(recorder, "migrations", "4_auto") loader.build_graph() self.assertEqual(num_nodes(), 3) # Starting at 5 to 7 we are past the squashed migrations. - self.record_applied(recorder, 'migrations', '5_auto') + self.record_applied(recorder, "migrations", "5_auto") loader.build_graph() self.assertEqual(num_nodes(), 2) - self.record_applied(recorder, 'migrations', '6_auto') + self.record_applied(recorder, "migrations", "6_auto") loader.build_graph() self.assertEqual(num_nodes(), 1) - self.record_applied(recorder, 'migrations', '7_auto') + self.record_applied(recorder, "migrations", "7_auto") loader.build_graph() self.assertEqual(num_nodes(), 0) - @override_settings(MIGRATION_MODULES={ - "app1": "migrations.test_migrations_squashed_complex_multi_apps.app1", - "app2": "migrations.test_migrations_squashed_complex_multi_apps.app2", - }) - @modify_settings(INSTALLED_APPS={'append': [ - "migrations.test_migrations_squashed_complex_multi_apps.app1", - "migrations.test_migrations_squashed_complex_multi_apps.app2", - ]}) + @override_settings( + MIGRATION_MODULES={ + "app1": "migrations.test_migrations_squashed_complex_multi_apps.app1", + "app2": "migrations.test_migrations_squashed_complex_multi_apps.app2", + } + ) + @modify_settings( + INSTALLED_APPS={ + "append": [ + "migrations.test_migrations_squashed_complex_multi_apps.app1", + "migrations.test_migrations_squashed_complex_multi_apps.app2", + ] + } + ) def test_loading_squashed_complex_multi_apps(self): loader = MigrationLoader(connection) loader.build_graph() - plan = set(loader.graph.forwards_plan(('app1', '4_auto'))) + plan = set(loader.graph.forwards_plan(("app1", "4_auto"))) expected_plan = { - ('app1', '1_auto'), - ('app2', '1_squashed_2'), - ('app1', '2_squashed_3'), - ('app1', '4_auto'), + ("app1", "1_auto"), + ("app2", "1_squashed_2"), + ("app1", "2_squashed_3"), + ("app1", "4_auto"), } self.assertEqual(plan, expected_plan) - @override_settings(MIGRATION_MODULES={ - "app1": "migrations.test_migrations_squashed_complex_multi_apps.app1", - "app2": "migrations.test_migrations_squashed_complex_multi_apps.app2", - }) - @modify_settings(INSTALLED_APPS={'append': [ - "migrations.test_migrations_squashed_complex_multi_apps.app1", - "migrations.test_migrations_squashed_complex_multi_apps.app2", - ]}) + @override_settings( + MIGRATION_MODULES={ + "app1": "migrations.test_migrations_squashed_complex_multi_apps.app1", + "app2": "migrations.test_migrations_squashed_complex_multi_apps.app2", + } + ) + @modify_settings( + INSTALLED_APPS={ + "append": [ + "migrations.test_migrations_squashed_complex_multi_apps.app1", + "migrations.test_migrations_squashed_complex_multi_apps.app2", + ] + } + ) def test_loading_squashed_complex_multi_apps_partially_applied(self): loader = MigrationLoader(connection) recorder = MigrationRecorder(connection) - self.record_applied(recorder, 'app1', '1_auto') - self.record_applied(recorder, 'app1', '2_auto') + self.record_applied(recorder, "app1", "1_auto") + self.record_applied(recorder, "app1", "2_auto") loader.build_graph() - plan = set(loader.graph.forwards_plan(('app1', '4_auto'))) + plan = set(loader.graph.forwards_plan(("app1", "4_auto"))) plan = plan - loader.applied_migrations.keys() expected_plan = { - ('app2', '1_squashed_2'), - ('app1', '3_auto'), - ('app1', '4_auto'), + ("app2", "1_squashed_2"), + ("app1", "3_auto"), + ("app1", "4_auto"), } self.assertEqual(plan, expected_plan) - @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed_erroneous"}) + @override_settings( + MIGRATION_MODULES={ + "migrations": "migrations.test_migrations_squashed_erroneous" + } + ) def test_loading_squashed_erroneous(self): "Tests loading a complex but erroneous set of squashed migrations" @@ -367,7 +412,7 @@ class LoaderTests(TestCase): self.addCleanup(recorder.flush) def num_nodes(): - plan = set(loader.graph.forwards_plan(('migrations', '7_auto'))) + plan = set(loader.graph.forwards_plan(("migrations", "7_auto"))) return len(plan - loader.applied_migrations.keys()) # Empty database: use squashed migration @@ -375,50 +420,52 @@ class LoaderTests(TestCase): self.assertEqual(num_nodes(), 5) # Starting at 1 or 2 should use the squashed migration too - self.record_applied(recorder, 'migrations', '1_auto') + self.record_applied(recorder, "migrations", "1_auto") loader.build_graph() self.assertEqual(num_nodes(), 4) - self.record_applied(recorder, 'migrations', '2_auto') + self.record_applied(recorder, "migrations", "2_auto") loader.build_graph() self.assertEqual(num_nodes(), 3) # However, starting at 3 or 4, nonexistent migrations would be needed. - msg = ("Migration migrations.6_auto depends on nonexistent node ('migrations', '5_auto'). " - "Django tried to replace migration migrations.5_auto with any of " - "[migrations.3_squashed_5] but wasn't able to because some of the replaced " - "migrations are already applied.") + msg = ( + "Migration migrations.6_auto depends on nonexistent node ('migrations', '5_auto'). " + "Django tried to replace migration migrations.5_auto with any of " + "[migrations.3_squashed_5] but wasn't able to because some of the replaced " + "migrations are already applied." + ) - self.record_applied(recorder, 'migrations', '3_auto') + self.record_applied(recorder, "migrations", "3_auto") with self.assertRaisesMessage(NodeNotFoundError, msg): loader.build_graph() - self.record_applied(recorder, 'migrations', '4_auto') + self.record_applied(recorder, "migrations", "4_auto") with self.assertRaisesMessage(NodeNotFoundError, msg): loader.build_graph() # Starting at 5 to 7 we are passed the squashed migrations - self.record_applied(recorder, 'migrations', '5_auto') + self.record_applied(recorder, "migrations", "5_auto") loader.build_graph() self.assertEqual(num_nodes(), 2) - self.record_applied(recorder, 'migrations', '6_auto') + self.record_applied(recorder, "migrations", "6_auto") loader.build_graph() self.assertEqual(num_nodes(), 1) - self.record_applied(recorder, 'migrations', '7_auto') + self.record_applied(recorder, "migrations", "7_auto") loader.build_graph() self.assertEqual(num_nodes(), 0) @override_settings( - MIGRATION_MODULES={'migrations': 'migrations.test_migrations'}, - INSTALLED_APPS=['migrations'], + MIGRATION_MODULES={"migrations": "migrations.test_migrations"}, + INSTALLED_APPS=["migrations"], ) def test_check_consistent_history(self): loader = MigrationLoader(connection=None) loader.check_consistent_history(connection) recorder = MigrationRecorder(connection) - self.record_applied(recorder, 'migrations', '0002_second') + self.record_applied(recorder, "migrations", "0002_second") msg = ( "Migration migrations.0002_second is applied before its dependency " "migrations.0001_initial on database 'default'." @@ -427,8 +474,8 @@ class LoaderTests(TestCase): loader.check_consistent_history(connection) @override_settings( - MIGRATION_MODULES={'migrations': 'migrations.test_migrations_squashed_extra'}, - INSTALLED_APPS=['migrations'], + MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed_extra"}, + INSTALLED_APPS=["migrations"], ) def test_check_consistent_history_squashed(self): """ @@ -437,20 +484,26 @@ class LoaderTests(TestCase): """ loader = MigrationLoader(connection=None) recorder = MigrationRecorder(connection) - self.record_applied(recorder, 'migrations', '0001_initial') - self.record_applied(recorder, 'migrations', '0002_second') + self.record_applied(recorder, "migrations", "0001_initial") + self.record_applied(recorder, "migrations", "0002_second") loader.check_consistent_history(connection) - self.record_applied(recorder, 'migrations', '0003_third') + self.record_applied(recorder, "migrations", "0003_third") loader.check_consistent_history(connection) - @override_settings(MIGRATION_MODULES={ - "app1": "migrations.test_migrations_squashed_ref_squashed.app1", - "app2": "migrations.test_migrations_squashed_ref_squashed.app2", - }) - @modify_settings(INSTALLED_APPS={'append': [ - "migrations.test_migrations_squashed_ref_squashed.app1", - "migrations.test_migrations_squashed_ref_squashed.app2", - ]}) + @override_settings( + MIGRATION_MODULES={ + "app1": "migrations.test_migrations_squashed_ref_squashed.app1", + "app2": "migrations.test_migrations_squashed_ref_squashed.app2", + } + ) + @modify_settings( + INSTALLED_APPS={ + "append": [ + "migrations.test_migrations_squashed_ref_squashed.app1", + "migrations.test_migrations_squashed_ref_squashed.app2", + ] + } + ) def test_loading_squashed_ref_squashed(self): "Tests loading a squashed migration with a new migration referencing it" r""" @@ -475,13 +528,13 @@ class LoaderTests(TestCase): # Load with nothing applied: both migrations squashed. loader.build_graph() - plan = set(loader.graph.forwards_plan(('app1', '4_auto'))) + plan = set(loader.graph.forwards_plan(("app1", "4_auto"))) plan = plan - loader.applied_migrations.keys() expected_plan = { - ('app1', '1_auto'), - ('app2', '1_squashed_2'), - ('app1', '2_squashed_3'), - ('app1', '4_auto'), + ("app1", "1_auto"), + ("app2", "1_squashed_2"), + ("app1", "2_squashed_3"), + ("app1", "4_auto"), } self.assertEqual(plan, expected_plan) @@ -490,72 +543,80 @@ class LoaderTests(TestCase): loader.build_graph() msg = "Node ('app1', '3_auto') not a valid node" with self.assertRaisesMessage(NodeNotFoundError, msg): - loader.graph.forwards_plan(('app1', '3_auto')) + loader.graph.forwards_plan(("app1", "3_auto")) # Possible if loader.replace_migrations is False. loader.replace_migrations = False loader.build_graph() - plan = set(loader.graph.forwards_plan(('app1', '3_auto'))) + plan = set(loader.graph.forwards_plan(("app1", "3_auto"))) plan = plan - loader.applied_migrations.keys() expected_plan = { - ('app1', '1_auto'), - ('app2', '1_auto'), - ('app2', '2_auto'), - ('app1', '2_auto'), - ('app1', '3_auto'), + ("app1", "1_auto"), + ("app2", "1_auto"), + ("app2", "2_auto"), + ("app1", "2_auto"), + ("app1", "3_auto"), } self.assertEqual(plan, expected_plan) loader.replace_migrations = True # Fake-apply a few from app1: unsquashes migration in app1. - self.record_applied(recorder, 'app1', '1_auto') - self.record_applied(recorder, 'app1', '2_auto') + self.record_applied(recorder, "app1", "1_auto") + self.record_applied(recorder, "app1", "2_auto") loader.build_graph() - plan = set(loader.graph.forwards_plan(('app1', '4_auto'))) + plan = set(loader.graph.forwards_plan(("app1", "4_auto"))) plan = plan - loader.applied_migrations.keys() expected_plan = { - ('app2', '1_squashed_2'), - ('app1', '3_auto'), - ('app1', '4_auto'), + ("app2", "1_squashed_2"), + ("app1", "3_auto"), + ("app1", "4_auto"), } self.assertEqual(plan, expected_plan) # Fake-apply one from app2: unsquashes migration in app2 too. - self.record_applied(recorder, 'app2', '1_auto') + self.record_applied(recorder, "app2", "1_auto") loader.build_graph() - plan = set(loader.graph.forwards_plan(('app1', '4_auto'))) + plan = set(loader.graph.forwards_plan(("app1", "4_auto"))) plan = plan - loader.applied_migrations.keys() expected_plan = { - ('app2', '2_auto'), - ('app1', '3_auto'), - ('app1', '4_auto'), + ("app2", "2_auto"), + ("app1", "3_auto"), + ("app1", "4_auto"), } self.assertEqual(plan, expected_plan) - @override_settings(MIGRATION_MODULES={'migrations': 'migrations.test_migrations_private'}) + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_private"} + ) def test_ignore_files(self): """Files prefixed with underscore, tilde, or dot aren't loaded.""" loader = MigrationLoader(connection) loader.load_disk() - migrations = [name for app, name in loader.disk_migrations if app == 'migrations'] - self.assertEqual(migrations, ['0001_initial']) + migrations = [ + name for app, name in loader.disk_migrations if app == "migrations" + ] + self.assertEqual(migrations, ["0001_initial"]) @override_settings( - MIGRATION_MODULES={'migrations': 'migrations.test_migrations_namespace_package'}, + MIGRATION_MODULES={ + "migrations": "migrations.test_migrations_namespace_package" + }, ) def test_loading_namespace_package(self): """Migration directories without an __init__.py file are ignored.""" loader = MigrationLoader(connection) loader.load_disk() - migrations = [name for app, name in loader.disk_migrations if app == 'migrations'] + migrations = [ + name for app, name in loader.disk_migrations if app == "migrations" + ] self.assertEqual(migrations, []) - @override_settings(MIGRATION_MODULES={'migrations': 'migrations.test_migrations'}) + @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"}) def test_loading_package_without__file__(self): """ To support frozen environments, MigrationLoader loads migrations from regular packages with no __file__ attribute. """ - test_module = import_module('migrations.test_migrations') + test_module = import_module("migrations.test_migrations") loader = MigrationLoader(connection) # __file__ == __spec__.origin or the latter is None and former is # undefined. @@ -568,11 +629,9 @@ class LoaderTests(TestCase): test_module.__spec__.has_location = False loader.load_disk() migrations = [ - name - for app, name in loader.disk_migrations - if app == 'migrations' + name for app, name in loader.disk_migrations if app == "migrations" ] - self.assertCountEqual(migrations, ['0001_initial', '0002_second']) + self.assertCountEqual(migrations, ["0001_initial", "0002_second"]) finally: test_module.__file__ = module_file test_module.__spec__.origin = module_origin @@ -580,30 +639,33 @@ class LoaderTests(TestCase): class PycLoaderTests(MigrationTestBase): - def test_valid(self): """ To support frozen environments, MigrationLoader loads .pyc migrations. """ - with self.temporary_migration_module(module='migrations.test_migrations') as migration_dir: + with self.temporary_migration_module( + module="migrations.test_migrations" + ) as migration_dir: # Compile .py files to .pyc files and delete .py files. compileall.compile_dir(migration_dir, force=True, quiet=1, legacy=True) for name in os.listdir(migration_dir): - if name.endswith('.py'): + if name.endswith(".py"): os.remove(os.path.join(migration_dir, name)) loader = MigrationLoader(connection) - self.assertIn(('migrations', '0001_initial'), loader.disk_migrations) + self.assertIn(("migrations", "0001_initial"), loader.disk_migrations) def test_invalid(self): """ MigrationLoader reraises ImportErrors caused by "bad magic number" pyc files with a more helpful message. """ - with self.temporary_migration_module(module='migrations.test_migrations_bad_pyc') as migration_dir: + with self.temporary_migration_module( + module="migrations.test_migrations_bad_pyc" + ) as migration_dir: # The -tpl suffix is to avoid the pyc exclusion in MANIFEST.in. os.rename( - os.path.join(migration_dir, '0001_initial.pyc-tpl'), - os.path.join(migration_dir, '0001_initial.pyc'), + os.path.join(migration_dir, "0001_initial.pyc-tpl"), + os.path.join(migration_dir, "0001_initial.pyc"), ) msg = ( r"Couldn't import '\w+.migrations.0001_initial' as it appears " diff --git a/tests/migrations/test_migrations/0001_initial.py b/tests/migrations/test_migrations/0001_initial.py index 259568e8d4..72cf48c7aa 100644 --- a/tests/migrations/test_migrations/0001_initial.py +++ b/tests/migrations/test_migrations/0001_initial.py @@ -24,12 +24,12 @@ class Migration(migrations.Migration): ], ), migrations.AddField( - model_name='tribble', - name='bool', + model_name="tribble", + name="bool", field=models.BooleanField(default=False), ), migrations.AlterUniqueTogether( - name='author', - unique_together={('name', 'slug')}, + name="author", + unique_together={("name", "slug")}, ), ] diff --git a/tests/migrations/test_migrations/0002_second.py b/tests/migrations/test_migrations/0002_second.py index 71c300cead..90a1b13b0b 100644 --- a/tests/migrations/test_migrations/0002_second.py +++ b/tests/migrations/test_migrations/0002_second.py @@ -8,19 +8,17 @@ class Migration(migrations.Migration): ] operations = [ - migrations.DeleteModel("Tribble"), - migrations.RemoveField("Author", "silly_field"), - migrations.AddField("Author", "rating", models.IntegerField(default=0)), - migrations.CreateModel( "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), + ( + "author", + models.ForeignKey("migrations.Author", models.SET_NULL, null=True), + ), ], - ) - + ), ] diff --git a/tests/migrations/test_migrations_atomic_operation/0001_initial.py b/tests/migrations/test_migrations_atomic_operation/0001_initial.py index 47ae3df5e9..b3c05c774d 100644 --- a/tests/migrations/test_migrations_atomic_operation/0001_initial.py +++ b/tests/migrations/test_migrations_atomic_operation/0001_initial.py @@ -3,9 +3,9 @@ from django.db import migrations, models def raise_error(apps, schema_editor): # Test atomic operation in non-atomic migration is wrapped in transaction - Editor = apps.get_model('migrations', 'Editor') - Editor.objects.create(name='Test Editor') - raise RuntimeError('Abort migration') + Editor = apps.get_model("migrations", "Editor") + Editor.objects.create(name="Test Editor") + raise RuntimeError("Abort migration") class Migration(migrations.Migration): diff --git a/tests/migrations/test_migrations_backwards_deps_1/0002_second.py b/tests/migrations/test_migrations_backwards_deps_1/0002_second.py index 6eb831e061..324f3d1b4c 100644 --- a/tests/migrations/test_migrations_backwards_deps_1/0002_second.py +++ b/tests/migrations/test_migrations_backwards_deps_1/0002_second.py @@ -2,5 +2,5 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [('migrations', '0001_initial')] + dependencies = [("migrations", "0001_initial")] operations = [] diff --git a/tests/migrations/test_migrations_clashing_prefix/ab.py b/tests/migrations/test_migrations_clashing_prefix/ab.py index 54f8924bac..539e347b0c 100644 --- a/tests/migrations/test_migrations_clashing_prefix/ab.py +++ b/tests/migrations/test_migrations_clashing_prefix/ab.py @@ -2,4 +2,4 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [('migrations', 'a')] + dependencies = [("migrations", "a")] diff --git a/tests/migrations/test_migrations_conflict/0001_initial.py b/tests/migrations/test_migrations_conflict/0001_initial.py index 344bebdfe3..59ad944f67 100644 --- a/tests/migrations/test_migrations_conflict/0001_initial.py +++ b/tests/migrations/test_migrations_conflict/0001_initial.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): operations = [ - migrations.CreateModel( "Author", [ @@ -15,13 +14,11 @@ class Migration(migrations.Migration): ("silly_field", models.BooleanField(default=False)), ], ), - migrations.CreateModel( "Tribble", [ ("id", models.AutoField(primary_key=True)), ("fluffy", models.BooleanField(default=True)), ], - ) - + ), ] diff --git a/tests/migrations/test_migrations_conflict/0002_conflicting_second.py b/tests/migrations/test_migrations_conflict/0002_conflicting_second.py index 15ea1f063a..d542d12dd5 100644 --- a/tests/migrations/test_migrations_conflict/0002_conflicting_second.py +++ b/tests/migrations/test_migrations_conflict/0002_conflicting_second.py @@ -6,12 +6,10 @@ class Migration(migrations.Migration): dependencies = [("migrations", "0001_initial")] operations = [ - migrations.CreateModel( "Something", [ ("id", models.AutoField(primary_key=True)), ], ) - ] diff --git a/tests/migrations/test_migrations_conflict/0002_second.py b/tests/migrations/test_migrations_conflict/0002_second.py index 60a6999ee4..9b4c3264d6 100644 --- a/tests/migrations/test_migrations_conflict/0002_second.py +++ b/tests/migrations/test_migrations_conflict/0002_second.py @@ -6,19 +6,17 @@ class Migration(migrations.Migration): dependencies = [("migrations", "0001_initial")] operations = [ - migrations.DeleteModel("Tribble"), - migrations.RemoveField("Author", "silly_field"), - migrations.AddField("Author", "rating", models.IntegerField(default=0)), - migrations.CreateModel( "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), + ( + "author", + models.ForeignKey("migrations.Author", models.SET_NULL, null=True), + ), ], - ) - + ), ] diff --git a/tests/migrations/test_migrations_conflict_long_name/0001_initial.py b/tests/migrations/test_migrations_conflict_long_name/0001_initial.py index e3faa21b3d..8adce29cbd 100644 --- a/tests/migrations/test_migrations_conflict_long_name/0001_initial.py +++ b/tests/migrations/test_migrations_conflict_long_name/0001_initial.py @@ -6,9 +6,9 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - 'Author', + "Author", [ - ('id', models.AutoField(primary_key=True)), + ("id", models.AutoField(primary_key=True)), ], ), ] diff --git a/tests/migrations/test_migrations_conflict_long_name/0002_conflicting_second_migration_with_long_name.py b/tests/migrations/test_migrations_conflict_long_name/0002_conflicting_second_migration_with_long_name.py index 747bd7a675..ddac8d8fe5 100644 --- a/tests/migrations/test_migrations_conflict_long_name/0002_conflicting_second_migration_with_long_name.py +++ b/tests/migrations/test_migrations_conflict_long_name/0002_conflicting_second_migration_with_long_name.py @@ -2,13 +2,13 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [('migrations', '0001_initial')] + dependencies = [("migrations", "0001_initial")] operations = [ migrations.CreateModel( - 'SomethingElse', + "SomethingElse", [ - ('id', models.AutoField(primary_key=True)), + ("id", models.AutoField(primary_key=True)), ], ), ] diff --git a/tests/migrations/test_migrations_conflict_long_name/0002_second.py b/tests/migrations/test_migrations_conflict_long_name/0002_second.py index 468dd06938..cc355d3bc0 100644 --- a/tests/migrations/test_migrations_conflict_long_name/0002_second.py +++ b/tests/migrations/test_migrations_conflict_long_name/0002_second.py @@ -2,13 +2,13 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [('migrations', '0001_initial')] + dependencies = [("migrations", "0001_initial")] operations = [ migrations.CreateModel( - 'Something', + "Something", [ - ('id', models.AutoField(primary_key=True)), + ("id", models.AutoField(primary_key=True)), ], ), ] diff --git a/tests/migrations/test_migrations_custom_user/0001_initial.py b/tests/migrations/test_migrations_custom_user/0001_initial.py index 250aa9f51b..e562436df7 100644 --- a/tests/migrations/test_migrations_custom_user/0001_initial.py +++ b/tests/migrations/test_migrations_custom_user/0001_initial.py @@ -8,7 +8,6 @@ class Migration(migrations.Migration): ] operations = [ - migrations.CreateModel( "Author", [ @@ -16,13 +15,16 @@ class Migration(migrations.Migration): ("name", models.CharField(max_length=255)), ], ), - migrations.CreateModel( "Tribble", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE, to_field="id")), + ( + "author", + models.ForeignKey( + settings.AUTH_USER_MODEL, models.CASCADE, to_field="id" + ), + ), ], - ) - + ), ] diff --git a/tests/migrations/test_migrations_fake_split_initial/0001_initial.py b/tests/migrations/test_migrations_fake_split_initial/0001_initial.py index ef17e329ce..f96d1b57cd 100644 --- a/tests/migrations/test_migrations_fake_split_initial/0001_initial.py +++ b/tests/migrations/test_migrations_fake_split_initial/0001_initial.py @@ -24,7 +24,7 @@ class Migration(migrations.Migration): ], ), migrations.AlterUniqueTogether( - name='author', - unique_together={('name', 'slug')}, + name="author", + unique_together={("name", "slug")}, ), ] diff --git a/tests/migrations/test_migrations_fake_split_initial/0002_second.py b/tests/migrations/test_migrations_fake_split_initial/0002_second.py index 6e9b28efb4..ba8e9660d1 100644 --- a/tests/migrations/test_migrations_fake_split_initial/0002_second.py +++ b/tests/migrations/test_migrations_fake_split_initial/0002_second.py @@ -15,7 +15,10 @@ class Migration(migrations.Migration): "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), + ( + "author", + models.ForeignKey("migrations.Author", models.SET_NULL, null=True), + ), ], ), ] diff --git a/tests/migrations/test_migrations_first/second.py b/tests/migrations/test_migrations_first/second.py index e4cf995dcc..96550a7b0c 100644 --- a/tests/migrations/test_migrations_first/second.py +++ b/tests/migrations/test_migrations_first/second.py @@ -9,19 +9,17 @@ class Migration(migrations.Migration): ] operations = [ - migrations.DeleteModel("Tribble"), - migrations.RemoveField("Author", "silly_field"), - migrations.AddField("Author", "rating", models.IntegerField(default=0)), - migrations.CreateModel( "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), + ( + "author", + models.ForeignKey("migrations.Author", models.SET_NULL, null=True), + ), ], - ) - + ), ] diff --git a/tests/migrations/test_migrations_first/thefirst.py b/tests/migrations/test_migrations_first/thefirst.py index 344bebdfe3..59ad944f67 100644 --- a/tests/migrations/test_migrations_first/thefirst.py +++ b/tests/migrations/test_migrations_first/thefirst.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): operations = [ - migrations.CreateModel( "Author", [ @@ -15,13 +14,11 @@ class Migration(migrations.Migration): ("silly_field", models.BooleanField(default=False)), ], ), - migrations.CreateModel( "Tribble", [ ("id", models.AutoField(primary_key=True)), ("fluffy", models.BooleanField(default=True)), ], - ) - + ), ] diff --git a/tests/migrations/test_migrations_initial_false/0001_not_initial.py b/tests/migrations/test_migrations_initial_false/0001_not_initial.py index 388c3b61e4..dbf58e4428 100644 --- a/tests/migrations/test_migrations_initial_false/0001_not_initial.py +++ b/tests/migrations/test_migrations_initial_false/0001_not_initial.py @@ -24,7 +24,7 @@ class Migration(migrations.Migration): ], ), migrations.AlterUniqueTogether( - name='author', - unique_together={('name', 'slug')}, + name="author", + unique_together={("name", "slug")}, ), ] diff --git a/tests/migrations/test_migrations_manual_porting/0001_initial.py b/tests/migrations/test_migrations_manual_porting/0001_initial.py index c3e03d6f07..8f827dcdca 100644 --- a/tests/migrations/test_migrations_manual_porting/0001_initial.py +++ b/tests/migrations/test_migrations_manual_porting/0001_initial.py @@ -6,10 +6,10 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - 'SomeModel', + "SomeModel", [ - ('id', models.AutoField(primary_key=True)), - ('name', models.CharField(max_length=255)), + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=255)), ], ), ] diff --git a/tests/migrations/test_migrations_manual_porting/0002_second.py b/tests/migrations/test_migrations_manual_porting/0002_second.py index 78ab9eebeb..b83c13f84d 100644 --- a/tests/migrations/test_migrations_manual_porting/0002_second.py +++ b/tests/migrations/test_migrations_manual_porting/0002_second.py @@ -7,7 +7,7 @@ def forwards(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ('migrations', '0001_initial'), + ("migrations", "0001_initial"), ] operations = [ diff --git a/tests/migrations/test_migrations_no_ancestor/0001_initial.py b/tests/migrations/test_migrations_no_ancestor/0001_initial.py index 344bebdfe3..59ad944f67 100644 --- a/tests/migrations/test_migrations_no_ancestor/0001_initial.py +++ b/tests/migrations/test_migrations_no_ancestor/0001_initial.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): operations = [ - migrations.CreateModel( "Author", [ @@ -15,13 +14,11 @@ class Migration(migrations.Migration): ("silly_field", models.BooleanField(default=False)), ], ), - migrations.CreateModel( "Tribble", [ ("id", models.AutoField(primary_key=True)), ("fluffy", models.BooleanField(default=True)), ], - ) - + ), ] diff --git a/tests/migrations/test_migrations_no_ancestor/0002_conflicting_second.py b/tests/migrations/test_migrations_no_ancestor/0002_conflicting_second.py index 71625a7116..fe1e0d3686 100644 --- a/tests/migrations/test_migrations_no_ancestor/0002_conflicting_second.py +++ b/tests/migrations/test_migrations_no_ancestor/0002_conflicting_second.py @@ -3,23 +3,20 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ] + dependencies = [] operations = [ - migrations.DeleteModel("Tribble"), - migrations.RemoveField("Author", "silly_field"), - migrations.AddField("Author", "rating", models.IntegerField(default=0)), - migrations.CreateModel( "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), + ( + "author", + models.ForeignKey("migrations.Author", models.SET_NULL, null=True), + ), ], - ) - + ), ] diff --git a/tests/migrations/test_migrations_no_ancestor/0002_second.py b/tests/migrations/test_migrations_no_ancestor/0002_second.py index 71c300cead..90a1b13b0b 100644 --- a/tests/migrations/test_migrations_no_ancestor/0002_second.py +++ b/tests/migrations/test_migrations_no_ancestor/0002_second.py @@ -8,19 +8,17 @@ class Migration(migrations.Migration): ] operations = [ - migrations.DeleteModel("Tribble"), - migrations.RemoveField("Author", "silly_field"), - migrations.AddField("Author", "rating", models.IntegerField(default=0)), - migrations.CreateModel( "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), + ( + "author", + models.ForeignKey("migrations.Author", models.SET_NULL, null=True), + ), ], - ) - + ), ] diff --git a/tests/migrations/test_migrations_no_changes/0001_initial.py b/tests/migrations/test_migrations_no_changes/0001_initial.py index 344bebdfe3..59ad944f67 100644 --- a/tests/migrations/test_migrations_no_changes/0001_initial.py +++ b/tests/migrations/test_migrations_no_changes/0001_initial.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): operations = [ - migrations.CreateModel( "Author", [ @@ -15,13 +14,11 @@ class Migration(migrations.Migration): ("silly_field", models.BooleanField(default=False)), ], ), - migrations.CreateModel( "Tribble", [ ("id", models.AutoField(primary_key=True)), ("fluffy", models.BooleanField(default=True)), ], - ) - + ), ] diff --git a/tests/migrations/test_migrations_no_changes/0002_second.py b/tests/migrations/test_migrations_no_changes/0002_second.py index 71c300cead..90a1b13b0b 100644 --- a/tests/migrations/test_migrations_no_changes/0002_second.py +++ b/tests/migrations/test_migrations_no_changes/0002_second.py @@ -8,19 +8,17 @@ class Migration(migrations.Migration): ] operations = [ - migrations.DeleteModel("Tribble"), - migrations.RemoveField("Author", "silly_field"), - migrations.AddField("Author", "rating", models.IntegerField(default=0)), - migrations.CreateModel( "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), + ( + "author", + models.ForeignKey("migrations.Author", models.SET_NULL, null=True), + ), ], - ) - + ), ] diff --git a/tests/migrations/test_migrations_no_changes/0003_third.py b/tests/migrations/test_migrations_no_changes/0003_third.py index 89b3bc030c..8802926437 100644 --- a/tests/migrations/test_migrations_no_changes/0003_third.py +++ b/tests/migrations/test_migrations_no_changes/0003_third.py @@ -4,30 +4,46 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('migrations', '0002_second'), + ("migrations", "0002_second"), ] operations = [ migrations.CreateModel( - name='ModelWithCustomBase', + name="ModelWithCustomBase", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), ], options={}, bases=(models.Model,), ), migrations.CreateModel( - name='UnmigratedModel', + name="UnmigratedModel", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), ], options={}, bases=(models.Model,), ), migrations.DeleteModel( - name='Author', + name="Author", ), migrations.DeleteModel( - name='Book', + name="Book", ), ] diff --git a/tests/migrations/test_migrations_no_default/0001_initial.py b/tests/migrations/test_migrations_no_default/0001_initial.py index e9176c4958..b247e49271 100644 --- a/tests/migrations/test_migrations_no_default/0001_initial.py +++ b/tests/migrations/test_migrations_no_default/0001_initial.py @@ -3,18 +3,24 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='SillyModel', + name="SillyModel", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('silly_field', models.BooleanField(default=False)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("silly_field", models.BooleanField(default=False)), ], - options={ - }, + options={}, bases=(models.Model,), ), ] diff --git a/tests/migrations/test_migrations_non_atomic/0001_initial.py b/tests/migrations/test_migrations_non_atomic/0001_initial.py index f1aa1ae371..c8379e8e07 100644 --- a/tests/migrations/test_migrations_non_atomic/0001_initial.py +++ b/tests/migrations/test_migrations_non_atomic/0001_initial.py @@ -3,9 +3,9 @@ from django.db import migrations, models def raise_error(apps, schema_editor): # Test operation in non-atomic migration is not wrapped in transaction - Publisher = apps.get_model('migrations', 'Publisher') - Publisher.objects.create(name='Test Publisher') - raise RuntimeError('Abort migration') + Publisher = apps.get_model("migrations", "Publisher") + Publisher.objects.create(name="Test Publisher") + raise RuntimeError("Abort migration") class Migration(migrations.Migration): @@ -23,7 +23,12 @@ class Migration(migrations.Migration): "Book", [ ("title", models.CharField(primary_key=True, max_length=255)), - ("publisher", models.ForeignKey("migrations.Publisher", models.SET_NULL, null=True)), + ( + "publisher", + models.ForeignKey( + "migrations.Publisher", models.SET_NULL, null=True + ), + ), ], ), ] diff --git a/tests/migrations/test_migrations_order/0001.py b/tests/migrations/test_migrations_order/0001.py index 2ef88e957d..ee34de77e4 100644 --- a/tests/migrations/test_migrations_order/0001.py +++ b/tests/migrations/test_migrations_order/0001.py @@ -5,5 +5,4 @@ class Migration(migrations.Migration): initial = True - operations = [ - ] + operations = [] diff --git a/tests/migrations/test_migrations_plan/0001_initial.py b/tests/migrations/test_migrations_plan/0001_initial.py index 0a4001d52a..4e4338c89b 100644 --- a/tests/migrations/test_migrations_plan/0001_initial.py +++ b/tests/migrations/test_migrations_plan/0001_initial.py @@ -17,11 +17,11 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - 'Salamander', + "Salamander", [ - ('id', models.AutoField(primary_key=True)), - ('tail', models.IntegerField(default=0)), - ('silly_field', models.BooleanField(default=False)), + ("id", models.AutoField(primary_key=True)), + ("tail", models.IntegerField(default=0)), + ("silly_field", models.BooleanField(default=False)), ], ), migrations.RunPython(grow_tail, shrink_tail), diff --git a/tests/migrations/test_migrations_plan/0002_second.py b/tests/migrations/test_migrations_plan/0002_second.py index 2fc9ea6933..12902ceec8 100644 --- a/tests/migrations/test_migrations_plan/0002_second.py +++ b/tests/migrations/test_migrations_plan/0002_second.py @@ -4,17 +4,17 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('migrations', '0001_initial'), + ("migrations", "0001_initial"), ] operations = [ - migrations.CreateModel( - 'Book', + "Book", [ - ('id', models.AutoField(primary_key=True)), + ("id", models.AutoField(primary_key=True)), ], ), - migrations.RunSQL(['SELECT * FROM migrations_book'], ['SELECT * FROM migrations_salamander']) - + migrations.RunSQL( + ["SELECT * FROM migrations_book"], ["SELECT * FROM migrations_salamander"] + ), ] diff --git a/tests/migrations/test_migrations_plan/0003_third.py b/tests/migrations/test_migrations_plan/0003_third.py index 6d17e217ec..1507fddb4c 100644 --- a/tests/migrations/test_migrations_plan/0003_third.py +++ b/tests/migrations/test_migrations_plan/0003_third.py @@ -4,16 +4,17 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('migrations', '0002_second'), + ("migrations", "0002_second"), ] operations = [ - migrations.CreateModel( - 'Author', + "Author", [ - ('id', models.AutoField(primary_key=True)), + ("id", models.AutoField(primary_key=True)), ], ), - migrations.RunSQL(['SELECT * FROM migrations_author'], ['SELECT * FROM migrations_book']) + migrations.RunSQL( + ["SELECT * FROM migrations_author"], ["SELECT * FROM migrations_book"] + ), ] diff --git a/tests/migrations/test_migrations_plan/0004_fourth.py b/tests/migrations/test_migrations_plan/0004_fourth.py index d3e1a54b4d..311e56c4b8 100644 --- a/tests/migrations/test_migrations_plan/0004_fourth.py +++ b/tests/migrations/test_migrations_plan/0004_fourth.py @@ -7,6 +7,4 @@ class Migration(migrations.Migration): ("migrations", "0003_third"), ] - operations = [ - migrations.RunSQL('SELECT * FROM migrations_author WHERE id = 1') - ] + operations = [migrations.RunSQL("SELECT * FROM migrations_author WHERE id = 1")] diff --git a/tests/migrations/test_migrations_plan/0005_fifth.py b/tests/migrations/test_migrations_plan/0005_fifth.py index 3c569ffded..0fe4a29cdb 100644 --- a/tests/migrations/test_migrations_plan/0005_fifth.py +++ b/tests/migrations/test_migrations_plan/0005_fifth.py @@ -12,7 +12,7 @@ def feed(x, y): class Migration(migrations.Migration): dependencies = [ - ('migrations', '0004_fourth'), + ("migrations", "0004_fourth"), ] operations = [ diff --git a/tests/migrations/test_migrations_run_before/0001_initial.py b/tests/migrations/test_migrations_run_before/0001_initial.py index 186c7fbec9..085f3347e8 100644 --- a/tests/migrations/test_migrations_run_before/0001_initial.py +++ b/tests/migrations/test_migrations_run_before/0001_initial.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): operations = [ - migrations.CreateModel( "Salamander", [ @@ -13,5 +12,4 @@ class Migration(migrations.Migration): ("silly_field", models.BooleanField(default=False)), ], ), - ] diff --git a/tests/migrations/test_migrations_run_before/0002_second.py b/tests/migrations/test_migrations_run_before/0002_second.py index 2be86bb439..9e2784ae6c 100644 --- a/tests/migrations/test_migrations_run_before/0002_second.py +++ b/tests/migrations/test_migrations_run_before/0002_second.py @@ -8,13 +8,14 @@ class Migration(migrations.Migration): ] operations = [ - migrations.CreateModel( "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), + ( + "author", + models.ForeignKey("migrations.Author", models.SET_NULL, null=True), + ), ], ) - ] diff --git a/tests/migrations/test_migrations_run_before/0003_third.py b/tests/migrations/test_migrations_run_before/0003_third.py index d24d28ca1c..ea6b2f3877 100644 --- a/tests/migrations/test_migrations_run_before/0003_third.py +++ b/tests/migrations/test_migrations_run_before/0003_third.py @@ -15,7 +15,6 @@ class Migration(migrations.Migration): ] operations = [ - migrations.CreateModel( "Author", [ @@ -25,5 +24,4 @@ class Migration(migrations.Migration): ("age", models.IntegerField(default=0)), ], ) - ] diff --git a/tests/migrations/test_migrations_squashed/0001_initial.py b/tests/migrations/test_migrations_squashed/0001_initial.py index 344bebdfe3..59ad944f67 100644 --- a/tests/migrations/test_migrations_squashed/0001_initial.py +++ b/tests/migrations/test_migrations_squashed/0001_initial.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): operations = [ - migrations.CreateModel( "Author", [ @@ -15,13 +14,11 @@ class Migration(migrations.Migration): ("silly_field", models.BooleanField(default=False)), ], ), - migrations.CreateModel( "Tribble", [ ("id", models.AutoField(primary_key=True)), ("fluffy", models.BooleanField(default=True)), ], - ) - + ), ] diff --git a/tests/migrations/test_migrations_squashed/0001_squashed_0002.py b/tests/migrations/test_migrations_squashed/0001_squashed_0002.py index 1ba7f45e41..4ac4530b02 100644 --- a/tests/migrations/test_migrations_squashed/0001_squashed_0002.py +++ b/tests/migrations/test_migrations_squashed/0001_squashed_0002.py @@ -9,7 +9,6 @@ class Migration(migrations.Migration): ] operations = [ - migrations.CreateModel( "Author", [ @@ -20,13 +19,14 @@ class Migration(migrations.Migration): ("rating", models.IntegerField(default=0)), ], ), - migrations.CreateModel( "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), + ( + "author", + models.ForeignKey("migrations.Author", models.SET_NULL, null=True), + ), ], ), - ] diff --git a/tests/migrations/test_migrations_squashed/0002_second.py b/tests/migrations/test_migrations_squashed/0002_second.py index 60a6999ee4..9b4c3264d6 100644 --- a/tests/migrations/test_migrations_squashed/0002_second.py +++ b/tests/migrations/test_migrations_squashed/0002_second.py @@ -6,19 +6,17 @@ class Migration(migrations.Migration): dependencies = [("migrations", "0001_initial")] operations = [ - migrations.DeleteModel("Tribble"), - migrations.RemoveField("Author", "silly_field"), - migrations.AddField("Author", "rating", models.IntegerField(default=0)), - migrations.CreateModel( "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), + ( + "author", + models.ForeignKey("migrations.Author", models.SET_NULL, null=True), + ), ], - ) - + ), ] diff --git a/tests/migrations/test_migrations_squashed_complex/1_auto.py b/tests/migrations/test_migrations_squashed_complex/1_auto.py index 46fc1242c9..56f45b2a62 100644 --- a/tests/migrations/test_migrations_squashed_complex/1_auto.py +++ b/tests/migrations/test_migrations_squashed_complex/1_auto.py @@ -3,6 +3,4 @@ from django.db import migrations class Migration(migrations.Migration): - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_complex/2_auto.py b/tests/migrations/test_migrations_squashed_complex/2_auto.py index 1964bf8167..379000e317 100644 --- a/tests/migrations/test_migrations_squashed_complex/2_auto.py +++ b/tests/migrations/test_migrations_squashed_complex/2_auto.py @@ -5,6 +5,4 @@ class Migration(migrations.Migration): dependencies = [("migrations", "1_auto")] - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_complex/3_auto.py b/tests/migrations/test_migrations_squashed_complex/3_auto.py index 994ddf3619..e90bf593f9 100644 --- a/tests/migrations/test_migrations_squashed_complex/3_auto.py +++ b/tests/migrations/test_migrations_squashed_complex/3_auto.py @@ -5,6 +5,4 @@ class Migration(migrations.Migration): dependencies = [("migrations", "2_auto")] - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_complex/3_squashed_5.py b/tests/migrations/test_migrations_squashed_complex/3_squashed_5.py index e8f1eb527e..f750d23b28 100644 --- a/tests/migrations/test_migrations_squashed_complex/3_squashed_5.py +++ b/tests/migrations/test_migrations_squashed_complex/3_squashed_5.py @@ -11,6 +11,4 @@ class Migration(migrations.Migration): dependencies = [("migrations", "2_auto")] - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_complex/4_auto.py b/tests/migrations/test_migrations_squashed_complex/4_auto.py index e7d0f09b55..7bbe7b9614 100644 --- a/tests/migrations/test_migrations_squashed_complex/4_auto.py +++ b/tests/migrations/test_migrations_squashed_complex/4_auto.py @@ -5,6 +5,4 @@ class Migration(migrations.Migration): dependencies = [("migrations", "3_auto")] - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_complex/5_auto.py b/tests/migrations/test_migrations_squashed_complex/5_auto.py index e7e25d9a71..df5c2edf32 100644 --- a/tests/migrations/test_migrations_squashed_complex/5_auto.py +++ b/tests/migrations/test_migrations_squashed_complex/5_auto.py @@ -5,6 +5,4 @@ class Migration(migrations.Migration): dependencies = [("migrations", "4_auto")] - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_complex/6_auto.py b/tests/migrations/test_migrations_squashed_complex/6_auto.py index 4438bb4196..0ce6bbbb45 100644 --- a/tests/migrations/test_migrations_squashed_complex/6_auto.py +++ b/tests/migrations/test_migrations_squashed_complex/6_auto.py @@ -5,6 +5,4 @@ class Migration(migrations.Migration): dependencies = [("migrations", "5_auto")] - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_complex/7_auto.py b/tests/migrations/test_migrations_squashed_complex/7_auto.py index f231edfed1..04d9ea4d55 100644 --- a/tests/migrations/test_migrations_squashed_complex/7_auto.py +++ b/tests/migrations/test_migrations_squashed_complex/7_auto.py @@ -5,6 +5,4 @@ class Migration(migrations.Migration): dependencies = [("migrations", "6_auto")] - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/1_auto.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/1_auto.py index 46fc1242c9..56f45b2a62 100644 --- a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/1_auto.py +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/1_auto.py @@ -3,6 +3,4 @@ from django.db import migrations class Migration(migrations.Migration): - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_auto.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_auto.py index 83d6e0bedc..7c01a498d2 100644 --- a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_auto.py +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_auto.py @@ -5,6 +5,4 @@ class Migration(migrations.Migration): dependencies = [("app1", "1_auto")] - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_squashed_3.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_squashed_3.py index 838f68f99f..b9c26b89d3 100644 --- a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_squashed_3.py +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_squashed_3.py @@ -10,6 +10,4 @@ class Migration(migrations.Migration): dependencies = [("app1", "1_auto"), ("app2", "2_auto")] - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/3_auto.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/3_auto.py index 8abccb5bed..4ea2506733 100644 --- a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/3_auto.py +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/3_auto.py @@ -5,6 +5,4 @@ class Migration(migrations.Migration): dependencies = [("app1", "2_auto"), ("app2", "2_auto")] - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/4_auto.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/4_auto.py index 3b44a1d0ab..7752e23ea0 100644 --- a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/4_auto.py +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/4_auto.py @@ -5,6 +5,4 @@ class Migration(migrations.Migration): dependencies = [("app1", "3_auto")] - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_auto.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_auto.py index 83d6e0bedc..7c01a498d2 100644 --- a/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_auto.py +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_auto.py @@ -5,6 +5,4 @@ class Migration(migrations.Migration): dependencies = [("app1", "1_auto")] - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_squashed_2.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_squashed_2.py index e12b5754ad..0c182504db 100644 --- a/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_squashed_2.py +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_squashed_2.py @@ -10,6 +10,4 @@ class Migration(migrations.Migration): dependencies = [("app1", "1_auto")] - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/2_auto.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/2_auto.py index 6726beb9d5..b87378ab49 100644 --- a/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/2_auto.py +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/2_auto.py @@ -5,6 +5,4 @@ class Migration(migrations.Migration): dependencies = [("app2", "1_auto")] - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_erroneous/1_auto.py b/tests/migrations/test_migrations_squashed_erroneous/1_auto.py index 46fc1242c9..56f45b2a62 100644 --- a/tests/migrations/test_migrations_squashed_erroneous/1_auto.py +++ b/tests/migrations/test_migrations_squashed_erroneous/1_auto.py @@ -3,6 +3,4 @@ from django.db import migrations class Migration(migrations.Migration): - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_erroneous/2_auto.py b/tests/migrations/test_migrations_squashed_erroneous/2_auto.py index 1964bf8167..379000e317 100644 --- a/tests/migrations/test_migrations_squashed_erroneous/2_auto.py +++ b/tests/migrations/test_migrations_squashed_erroneous/2_auto.py @@ -5,6 +5,4 @@ class Migration(migrations.Migration): dependencies = [("migrations", "1_auto")] - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_erroneous/3_squashed_5.py b/tests/migrations/test_migrations_squashed_erroneous/3_squashed_5.py index e8f1eb527e..f750d23b28 100644 --- a/tests/migrations/test_migrations_squashed_erroneous/3_squashed_5.py +++ b/tests/migrations/test_migrations_squashed_erroneous/3_squashed_5.py @@ -11,6 +11,4 @@ class Migration(migrations.Migration): dependencies = [("migrations", "2_auto")] - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_erroneous/6_auto.py b/tests/migrations/test_migrations_squashed_erroneous/6_auto.py index 4438bb4196..0ce6bbbb45 100644 --- a/tests/migrations/test_migrations_squashed_erroneous/6_auto.py +++ b/tests/migrations/test_migrations_squashed_erroneous/6_auto.py @@ -5,6 +5,4 @@ class Migration(migrations.Migration): dependencies = [("migrations", "5_auto")] - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_erroneous/7_auto.py b/tests/migrations/test_migrations_squashed_erroneous/7_auto.py index f231edfed1..04d9ea4d55 100644 --- a/tests/migrations/test_migrations_squashed_erroneous/7_auto.py +++ b/tests/migrations/test_migrations_squashed_erroneous/7_auto.py @@ -5,6 +5,4 @@ class Migration(migrations.Migration): dependencies = [("migrations", "6_auto")] - operations = [ - migrations.RunPython(migrations.RunPython.noop) - ] + operations = [migrations.RunPython(migrations.RunPython.noop)] diff --git a/tests/migrations/test_migrations_squashed_no_replaces/0001_squashed_0002.py b/tests/migrations/test_migrations_squashed_no_replaces/0001_squashed_0002.py index b261b859a1..72eb931d32 100644 --- a/tests/migrations/test_migrations_squashed_no_replaces/0001_squashed_0002.py +++ b/tests/migrations/test_migrations_squashed_no_replaces/0001_squashed_0002.py @@ -15,7 +15,10 @@ class Migration(migrations.Migration): "Book", [ ("id", models.AutoField(primary_key=True)), - ("author", models.ForeignKey("migrations.Author", models.SET_NULL, null=True)), + ( + "author", + models.ForeignKey("migrations.Author", models.SET_NULL, null=True), + ), ], ), ] diff --git a/tests/migrations/test_migrations_unmigdep/0001_initial.py b/tests/migrations/test_migrations_unmigdep/0001_initial.py index 91b58c3dad..1cb4f8b06e 100644 --- a/tests/migrations/test_migrations_unmigdep/0001_initial.py +++ b/tests/migrations/test_migrations_unmigdep/0001_initial.py @@ -8,7 +8,6 @@ class Migration(migrations.Migration): ] operations = [ - migrations.CreateModel( "Book", [ @@ -16,5 +15,4 @@ class Migration(migrations.Migration): ("user", models.ForeignKey("auth.User", models.SET_NULL, null=True)), ], ) - ] diff --git a/tests/migrations/test_multidb.py b/tests/migrations/test_multidb.py index d8986deb81..7bf5d51454 100644 --- a/tests/migrations/test_multidb.py +++ b/tests/migrations/test_multidb.py @@ -9,6 +9,7 @@ class AgnosticRouter: """ A router that doesn't have an opinion regarding migrating. """ + def allow_migrate(self, db, app_label, **hints): return None @@ -17,6 +18,7 @@ class MigrateNothingRouter: """ A router that doesn't allow migrating. """ + def allow_migrate(self, db, app_label, **hints): return False @@ -25,6 +27,7 @@ class MigrateEverythingRouter: """ A router that always allows migrating. """ + def allow_migrate(self, db, app_label, **hints): return True @@ -33,12 +36,13 @@ class MigrateWhenFooRouter: """ A router that allows migrating depending on a hint. """ + def allow_migrate(self, db, app_label, **hints): - return hints.get('foo', False) + return hints.get("foo", False) class MultiDBOperationTests(OperationTestBase): - databases = {'default', 'other'} + databases = {"default", "other"} def _test_create_model(self, app_label, should_run): """ @@ -92,9 +96,13 @@ class MultiDBOperationTests(OperationTestBase): """ with override_settings(DATABASE_ROUTERS=[AgnosticRouter(), AgnosticRouter()]): self._test_create_model("test_mltdb_crmo4", should_run=True) - with override_settings(DATABASE_ROUTERS=[MigrateNothingRouter(), MigrateEverythingRouter()]): + with override_settings( + DATABASE_ROUTERS=[MigrateNothingRouter(), MigrateEverythingRouter()] + ): self._test_create_model("test_mltdb_crmo4", should_run=False) - with override_settings(DATABASE_ROUTERS=[MigrateEverythingRouter(), MigrateNothingRouter()]): + with override_settings( + DATABASE_ROUTERS=[MigrateEverythingRouter(), MigrateNothingRouter()] + ): self._test_create_model("test_mltdb_crmo4", should_run=True) def _test_run_sql(self, app_label, should_run, hints=None): @@ -104,7 +112,9 @@ class MultiDBOperationTests(OperationTestBase): sql = """ INSERT INTO {0}_pony (pink, weight) VALUES (1, 3.55); INSERT INTO {0}_pony (pink, weight) VALUES (3, 5.0); - """.format(app_label) + """.format( + app_label + ) operation = migrations.RunSQL(sql, hints=hints or {}) # Test the state alteration does nothing @@ -112,7 +122,9 @@ class MultiDBOperationTests(OperationTestBase): operation.state_forwards(app_label, new_state) self.assertEqual(new_state, project_state) # Test the database alteration - self.assertEqual(project_state.apps.get_model(app_label, "Pony").objects.count(), 0) + self.assertEqual( + project_state.apps.get_model(app_label, "Pony").objects.count(), 0 + ) with connection.schema_editor() as editor: operation.database_forwards(app_label, editor, project_state, new_state) Pony = project_state.apps.get_model(app_label, "Pony") @@ -131,7 +143,7 @@ class MultiDBOperationTests(OperationTestBase): @override_settings(DATABASE_ROUTERS=[MigrateWhenFooRouter()]) def test_run_sql_migrate_foo_router_with_hints(self): - self._test_run_sql('test_mltdb_runsql3', should_run=True, hints={'foo': True}) + self._test_run_sql("test_mltdb_runsql3", should_run=True, hints={"foo": True}) def _test_run_python(self, app_label, should_run, hints=None): with override_settings(DATABASE_ROUTERS=[MigrateEverythingRouter()]): @@ -149,7 +161,9 @@ class MultiDBOperationTests(OperationTestBase): operation.state_forwards(app_label, new_state) self.assertEqual(new_state, project_state) # Test the database alteration - self.assertEqual(project_state.apps.get_model(app_label, "Pony").objects.count(), 0) + self.assertEqual( + project_state.apps.get_model(app_label, "Pony").objects.count(), 0 + ) with connection.schema_editor() as editor: operation.database_forwards(app_label, editor, project_state, new_state) Pony = project_state.apps.get_model(app_label, "Pony") @@ -168,4 +182,6 @@ class MultiDBOperationTests(OperationTestBase): @override_settings(DATABASE_ROUTERS=[MigrateWhenFooRouter()]) def test_run_python_migrate_foo_router_with_hints(self): - self._test_run_python('test_mltdb_runpython3', should_run=True, hints={'foo': True}) + self._test_run_python( + "test_mltdb_runpython3", should_run=True, hints={"foo": True} + ) diff --git a/tests/migrations/test_operations.py b/tests/migrations/test_operations.py index 7de4dd5d8b..52a798e22d 100644 --- a/tests/migrations/test_operations.py +++ b/tests/migrations/test_operations.py @@ -1,7 +1,5 @@ from django.core.exceptions import FieldDoesNotExist -from django.db import ( - IntegrityError, connection, migrations, models, transaction, -) +from django.db import IntegrityError, connection, migrations, models, transaction from django.db.migrations.migration import Migration from django.db.migrations.operations.fields import FieldOperation from django.db.migrations.state import ModelState, ProjectState @@ -38,7 +36,7 @@ class OperationTests(OperationTestBase): ], ) self.assertEqual(operation.describe(), "Create model Pony") - self.assertEqual(operation.migration_name_fragment, 'pony') + self.assertEqual(operation.migration_name_fragment, "pony") # Test the state alteration project_state = ProjectState() new_state = project_state.clone() @@ -60,12 +58,16 @@ class OperationTests(OperationTestBase): self.assertEqual(definition[1], []) self.assertEqual(sorted(definition[2]), ["fields", "name"]) # And default manager not in set - operation = migrations.CreateModel("Foo", fields=[], managers=[("objects", models.Manager())]) + operation = migrations.CreateModel( + "Foo", fields=[], managers=[("objects", models.Manager())] + ) definition = operation.deconstruct() - self.assertNotIn('managers', definition[2]) + self.assertNotIn("managers", definition[2]) def test_create_model_with_duplicate_field_name(self): - with self.assertRaisesMessage(ValueError, 'Found duplicate value pink in CreateModel fields argument.'): + with self.assertRaisesMessage( + ValueError, "Found duplicate value pink in CreateModel fields argument." + ): migrations.CreateModel( "Pony", [ @@ -76,55 +78,79 @@ class OperationTests(OperationTestBase): ) def test_create_model_with_duplicate_base(self): - message = 'Found duplicate value test_crmo.pony in CreateModel bases argument.' + message = "Found duplicate value test_crmo.pony in CreateModel bases argument." with self.assertRaisesMessage(ValueError, message): migrations.CreateModel( "Pony", fields=[], - bases=("test_crmo.Pony", "test_crmo.Pony",), + bases=( + "test_crmo.Pony", + "test_crmo.Pony", + ), ) with self.assertRaisesMessage(ValueError, message): migrations.CreateModel( "Pony", fields=[], - bases=("test_crmo.Pony", "test_crmo.pony",), + bases=( + "test_crmo.Pony", + "test_crmo.pony", + ), ) - message = 'Found duplicate value migrations.unicodemodel in CreateModel bases argument.' + message = "Found duplicate value migrations.unicodemodel in CreateModel bases argument." with self.assertRaisesMessage(ValueError, message): migrations.CreateModel( "Pony", fields=[], - bases=(UnicodeModel, UnicodeModel,), + bases=( + UnicodeModel, + UnicodeModel, + ), ) with self.assertRaisesMessage(ValueError, message): migrations.CreateModel( "Pony", fields=[], - bases=(UnicodeModel, 'migrations.unicodemodel',), + bases=( + UnicodeModel, + "migrations.unicodemodel", + ), ) with self.assertRaisesMessage(ValueError, message): migrations.CreateModel( "Pony", fields=[], - bases=(UnicodeModel, 'migrations.UnicodeModel',), + bases=( + UnicodeModel, + "migrations.UnicodeModel", + ), ) message = "Found duplicate value <class 'django.db.models.base.Model'> in CreateModel bases argument." with self.assertRaisesMessage(ValueError, message): migrations.CreateModel( "Pony", fields=[], - bases=(models.Model, models.Model,), + bases=( + models.Model, + models.Model, + ), ) message = "Found duplicate value <class 'migrations.test_operations.Mixin'> in CreateModel bases argument." with self.assertRaisesMessage(ValueError, message): migrations.CreateModel( "Pony", fields=[], - bases=(Mixin, Mixin,), + bases=( + Mixin, + Mixin, + ), ) def test_create_model_with_duplicate_manager_name(self): - with self.assertRaisesMessage(ValueError, 'Found duplicate value objects in CreateModel managers argument.'): + with self.assertRaisesMessage( + ValueError, + "Found duplicate value objects in CreateModel managers argument.", + ): migrations.CreateModel( "Pony", fields=[], @@ -167,13 +193,19 @@ class OperationTests(OperationTestBase): with connection.schema_editor() as editor: new_state = project_state.clone() operation1.state_forwards("test_crmoua", new_state) - operation1.database_forwards("test_crmoua", editor, project_state, new_state) + operation1.database_forwards( + "test_crmoua", editor, project_state, new_state + ) project_state, new_state = new_state, new_state.clone() operation2.state_forwards("test_crmoua", new_state) - operation2.database_forwards("test_crmoua", editor, project_state, new_state) + operation2.database_forwards( + "test_crmoua", editor, project_state, new_state + ) project_state, new_state = new_state, new_state.clone() operation3.state_forwards("test_crmoua", new_state) - operation3.database_forwards("test_crmoua", editor, project_state, new_state) + operation3.database_forwards( + "test_crmoua", editor, project_state, new_state + ) self.assertTableExists("test_crmoua_pony") self.assertTableExists("test_crmoua_rider") @@ -187,8 +219,8 @@ class OperationTests(OperationTestBase): "Stable", [ ("id", models.AutoField(primary_key=True)), - ("ponies", models.ManyToManyField("Pony", related_name="stables")) - ] + ("ponies", models.ManyToManyField("Pony", related_name="stables")), + ], ) # Test the state alteration new_state = project_state.clone() @@ -212,7 +244,9 @@ class OperationTests(OperationTestBase): stable.ponies.all().delete() # And test reversal with connection.schema_editor() as editor: - operation.database_backwards("test_crmomm", editor, new_state, project_state) + operation.database_backwards( + "test_crmomm", editor, new_state, project_state + ) self.assertTableNotExists("test_crmomm_stable") self.assertTableNotExists("test_crmomm_stable_ponies") @@ -225,14 +259,17 @@ class OperationTests(OperationTestBase): operation = migrations.CreateModel( "ShetlandPony", [ - ('pony_ptr', models.OneToOneField( - 'test_crmoih.Pony', - models.CASCADE, - auto_created=True, - primary_key=True, - to_field='id', - serialize=False, - )), + ( + "pony_ptr", + models.OneToOneField( + "test_crmoih.Pony", + models.CASCADE, + auto_created=True, + primary_key=True, + to_field="id", + serialize=False, + ), + ), ("cuteness", models.IntegerField(default=1)), ], ) @@ -246,7 +283,9 @@ class OperationTests(OperationTestBase): self.assertTableExists("test_crmoih_shetlandpony") # And test reversal with connection.schema_editor() as editor: - operation.database_backwards("test_crmoih", editor, new_state, project_state) + operation.database_backwards( + "test_crmoih", editor, new_state, project_state + ) self.assertTableNotExists("test_crmoih_shetlandpony") def test_create_proxy_model(self): @@ -274,7 +313,9 @@ class OperationTests(OperationTestBase): self.assertTableExists("test_crprmo_pony") # And test reversal with connection.schema_editor() as editor: - operation.database_backwards("test_crprmo", editor, new_state, project_state) + operation.database_backwards( + "test_crprmo", editor, new_state, project_state + ) self.assertTableNotExists("test_crprmo_proxypony") self.assertTableExists("test_crprmo_pony") # And deconstruction @@ -308,28 +349,34 @@ class OperationTests(OperationTestBase): self.assertTableExists("test_crummo_pony") # And test reversal with connection.schema_editor() as editor: - operation.database_backwards("test_crummo", editor, new_state, project_state) + operation.database_backwards( + "test_crummo", editor, new_state, project_state + ) self.assertTableNotExists("test_crummo_unmanagedpony") self.assertTableExists("test_crummo_pony") - @skipUnlessDBFeature('supports_table_check_constraints') + @skipUnlessDBFeature("supports_table_check_constraints") def test_create_model_with_constraint(self): where = models.Q(pink__gt=2) - check_constraint = models.CheckConstraint(check=where, name='test_constraint_pony_pink_gt_2') + check_constraint = models.CheckConstraint( + check=where, name="test_constraint_pony_pink_gt_2" + ) operation = migrations.CreateModel( "Pony", [ ("id", models.AutoField(primary_key=True)), ("pink", models.IntegerField(default=3)), ], - options={'constraints': [check_constraint]}, + options={"constraints": [check_constraint]}, ) # Test the state alteration project_state = ProjectState() new_state = project_state.clone() operation.state_forwards("test_crmo", new_state) - self.assertEqual(len(new_state.models['test_crmo', 'pony'].options['constraints']), 1) + self.assertEqual( + len(new_state.models["test_crmo", "pony"].options["constraints"]), 1 + ) # Test database alteration self.assertTableNotExists("test_crmo_pony") @@ -349,35 +396,37 @@ class OperationTests(OperationTestBase): definition = operation.deconstruct() self.assertEqual(definition[0], "CreateModel") self.assertEqual(definition[1], []) - self.assertEqual(definition[2]['options']['constraints'], [check_constraint]) + self.assertEqual(definition[2]["options"]["constraints"], [check_constraint]) def test_create_model_with_partial_unique_constraint(self): partial_unique_constraint = models.UniqueConstraint( - fields=['pink'], + fields=["pink"], condition=models.Q(weight__gt=5), - name='test_constraint_pony_pink_for_weight_gt_5_uniq', + name="test_constraint_pony_pink_for_weight_gt_5_uniq", ) operation = migrations.CreateModel( - 'Pony', + "Pony", [ - ('id', models.AutoField(primary_key=True)), - ('pink', models.IntegerField(default=3)), - ('weight', models.FloatField()), + ("id", models.AutoField(primary_key=True)), + ("pink", models.IntegerField(default=3)), + ("weight", models.FloatField()), ], - options={'constraints': [partial_unique_constraint]}, + options={"constraints": [partial_unique_constraint]}, ) # Test the state alteration project_state = ProjectState() new_state = project_state.clone() - operation.state_forwards('test_crmo', new_state) - self.assertEqual(len(new_state.models['test_crmo', 'pony'].options['constraints']), 1) + operation.state_forwards("test_crmo", new_state) + self.assertEqual( + len(new_state.models["test_crmo", "pony"].options["constraints"]), 1 + ) # Test database alteration - self.assertTableNotExists('test_crmo_pony') + self.assertTableNotExists("test_crmo_pony") with connection.schema_editor() as editor: - operation.database_forwards('test_crmo', editor, project_state, new_state) - self.assertTableExists('test_crmo_pony') + operation.database_forwards("test_crmo", editor, project_state, new_state) + self.assertTableExists("test_crmo_pony") # Test constraint works - Pony = new_state.apps.get_model('test_crmo', 'Pony') + Pony = new_state.apps.get_model("test_crmo", "Pony") Pony.objects.create(pink=1, weight=4.0) Pony.objects.create(pink=1, weight=4.0) Pony.objects.create(pink=1, weight=6.0) @@ -388,38 +437,42 @@ class OperationTests(OperationTestBase): Pony.objects.create(pink=1, weight=7.0) # Test reversal with connection.schema_editor() as editor: - operation.database_backwards('test_crmo', editor, new_state, project_state) - self.assertTableNotExists('test_crmo_pony') + operation.database_backwards("test_crmo", editor, new_state, project_state) + self.assertTableNotExists("test_crmo_pony") # Test deconstruction definition = operation.deconstruct() - self.assertEqual(definition[0], 'CreateModel') + self.assertEqual(definition[0], "CreateModel") self.assertEqual(definition[1], []) - self.assertEqual(definition[2]['options']['constraints'], [partial_unique_constraint]) + self.assertEqual( + definition[2]["options"]["constraints"], [partial_unique_constraint] + ) def test_create_model_with_deferred_unique_constraint(self): deferred_unique_constraint = models.UniqueConstraint( - fields=['pink'], - name='deferrable_pink_constraint', + fields=["pink"], + name="deferrable_pink_constraint", deferrable=models.Deferrable.DEFERRED, ) operation = migrations.CreateModel( - 'Pony', + "Pony", [ - ('id', models.AutoField(primary_key=True)), - ('pink', models.IntegerField(default=3)), + ("id", models.AutoField(primary_key=True)), + ("pink", models.IntegerField(default=3)), ], - options={'constraints': [deferred_unique_constraint]}, + options={"constraints": [deferred_unique_constraint]}, ) project_state = ProjectState() new_state = project_state.clone() - operation.state_forwards('test_crmo', new_state) - self.assertEqual(len(new_state.models['test_crmo', 'pony'].options['constraints']), 1) - self.assertTableNotExists('test_crmo_pony') + operation.state_forwards("test_crmo", new_state) + self.assertEqual( + len(new_state.models["test_crmo", "pony"].options["constraints"]), 1 + ) + self.assertTableNotExists("test_crmo_pony") # Create table. with connection.schema_editor() as editor: - operation.database_forwards('test_crmo', editor, project_state, new_state) - self.assertTableExists('test_crmo_pony') - Pony = new_state.apps.get_model('test_crmo', 'Pony') + operation.database_forwards("test_crmo", editor, project_state, new_state) + self.assertTableExists("test_crmo_pony") + Pony = new_state.apps.get_model("test_crmo", "Pony") Pony.objects.create(pink=1) if connection.features.supports_deferrable_unique_constraints: # Unique constraint is deferred. @@ -430,8 +483,10 @@ class OperationTests(OperationTestBase): # Constraint behavior can be changed with SET CONSTRAINTS. with self.assertRaises(IntegrityError): with transaction.atomic(), connection.cursor() as cursor: - quoted_name = connection.ops.quote_name(deferred_unique_constraint.name) - cursor.execute('SET CONSTRAINTS %s IMMEDIATE' % quoted_name) + quoted_name = connection.ops.quote_name( + deferred_unique_constraint.name + ) + cursor.execute("SET CONSTRAINTS %s IMMEDIATE" % quoted_name) obj = Pony.objects.create(pink=1) obj.pink = 3 obj.save() @@ -439,56 +494,58 @@ class OperationTests(OperationTestBase): Pony.objects.create(pink=1) # Reversal. with connection.schema_editor() as editor: - operation.database_backwards('test_crmo', editor, new_state, project_state) - self.assertTableNotExists('test_crmo_pony') + operation.database_backwards("test_crmo", editor, new_state, project_state) + self.assertTableNotExists("test_crmo_pony") # Deconstruction. definition = operation.deconstruct() - self.assertEqual(definition[0], 'CreateModel') + self.assertEqual(definition[0], "CreateModel") self.assertEqual(definition[1], []) self.assertEqual( - definition[2]['options']['constraints'], + definition[2]["options"]["constraints"], [deferred_unique_constraint], ) - @skipUnlessDBFeature('supports_covering_indexes') + @skipUnlessDBFeature("supports_covering_indexes") def test_create_model_with_covering_unique_constraint(self): covering_unique_constraint = models.UniqueConstraint( - fields=['pink'], - include=['weight'], - name='test_constraint_pony_pink_covering_weight', + fields=["pink"], + include=["weight"], + name="test_constraint_pony_pink_covering_weight", ) operation = migrations.CreateModel( - 'Pony', + "Pony", [ - ('id', models.AutoField(primary_key=True)), - ('pink', models.IntegerField(default=3)), - ('weight', models.FloatField()), + ("id", models.AutoField(primary_key=True)), + ("pink", models.IntegerField(default=3)), + ("weight", models.FloatField()), ], - options={'constraints': [covering_unique_constraint]}, + options={"constraints": [covering_unique_constraint]}, ) project_state = ProjectState() new_state = project_state.clone() - operation.state_forwards('test_crmo', new_state) - self.assertEqual(len(new_state.models['test_crmo', 'pony'].options['constraints']), 1) - self.assertTableNotExists('test_crmo_pony') + operation.state_forwards("test_crmo", new_state) + self.assertEqual( + len(new_state.models["test_crmo", "pony"].options["constraints"]), 1 + ) + self.assertTableNotExists("test_crmo_pony") # Create table. with connection.schema_editor() as editor: - operation.database_forwards('test_crmo', editor, project_state, new_state) - self.assertTableExists('test_crmo_pony') - Pony = new_state.apps.get_model('test_crmo', 'Pony') + operation.database_forwards("test_crmo", editor, project_state, new_state) + self.assertTableExists("test_crmo_pony") + Pony = new_state.apps.get_model("test_crmo", "Pony") Pony.objects.create(pink=1, weight=4.0) with self.assertRaises(IntegrityError): Pony.objects.create(pink=1, weight=7.0) # Reversal. with connection.schema_editor() as editor: - operation.database_backwards('test_crmo', editor, new_state, project_state) - self.assertTableNotExists('test_crmo_pony') + operation.database_backwards("test_crmo", editor, new_state, project_state) + self.assertTableNotExists("test_crmo_pony") # Deconstruction. definition = operation.deconstruct() - self.assertEqual(definition[0], 'CreateModel') + self.assertEqual(definition[0], "CreateModel") self.assertEqual(definition[1], []) self.assertEqual( - definition[2]['options']['constraints'], + definition[2]["options"]["constraints"], [covering_unique_constraint], ) @@ -507,7 +564,7 @@ class OperationTests(OperationTestBase): ("food_qs", FoodQuerySet.as_manager()), ("food_mgr", FoodManager("a", "b")), ("food_mgr_kwargs", FoodManager("x", "y", 3, 4)), - ] + ], ) self.assertEqual(operation.describe(), "Create model Food") new_state = project_state.clone() @@ -531,7 +588,7 @@ class OperationTests(OperationTestBase): # Test the state alteration operation = migrations.DeleteModel("Pony") self.assertEqual(operation.describe(), "Delete model Pony") - self.assertEqual(operation.migration_name_fragment, 'delete_pony') + self.assertEqual(operation.migration_name_fragment, "delete_pony") new_state = project_state.clone() operation.state_forwards("test_dlmo", new_state) self.assertNotIn(("test_dlmo", "pony"), new_state.models) @@ -570,32 +627,38 @@ class OperationTests(OperationTestBase): self.assertTableNotExists("test_dlprmo_proxypony") # And test reversal with connection.schema_editor() as editor: - operation.database_backwards("test_dlprmo", editor, new_state, project_state) + operation.database_backwards( + "test_dlprmo", editor, new_state, project_state + ) self.assertTableExists("test_dlprmo_pony") self.assertTableNotExists("test_dlprmo_proxypony") def test_delete_mti_model(self): - project_state = self.set_up_test_model('test_dlmtimo', mti_model=True) + project_state = self.set_up_test_model("test_dlmtimo", mti_model=True) # Test the state alteration - operation = migrations.DeleteModel('ShetlandPony') + operation = migrations.DeleteModel("ShetlandPony") new_state = project_state.clone() - operation.state_forwards('test_dlmtimo', new_state) - self.assertIn(('test_dlmtimo', 'shetlandpony'), project_state.models) - self.assertNotIn(('test_dlmtimo', 'shetlandpony'), new_state.models) + operation.state_forwards("test_dlmtimo", new_state) + self.assertIn(("test_dlmtimo", "shetlandpony"), project_state.models) + self.assertNotIn(("test_dlmtimo", "shetlandpony"), new_state.models) # Test the database alteration - self.assertTableExists('test_dlmtimo_pony') - self.assertTableExists('test_dlmtimo_shetlandpony') - self.assertColumnExists('test_dlmtimo_shetlandpony', 'pony_ptr_id') + self.assertTableExists("test_dlmtimo_pony") + self.assertTableExists("test_dlmtimo_shetlandpony") + self.assertColumnExists("test_dlmtimo_shetlandpony", "pony_ptr_id") with connection.schema_editor() as editor: - operation.database_forwards('test_dlmtimo', editor, project_state, new_state) - self.assertTableExists('test_dlmtimo_pony') - self.assertTableNotExists('test_dlmtimo_shetlandpony') + operation.database_forwards( + "test_dlmtimo", editor, project_state, new_state + ) + self.assertTableExists("test_dlmtimo_pony") + self.assertTableNotExists("test_dlmtimo_shetlandpony") # And test reversal with connection.schema_editor() as editor: - operation.database_backwards('test_dlmtimo', editor, new_state, project_state) - self.assertTableExists('test_dlmtimo_pony') - self.assertTableExists('test_dlmtimo_shetlandpony') - self.assertColumnExists('test_dlmtimo_shetlandpony', 'pony_ptr_id') + operation.database_backwards( + "test_dlmtimo", editor, new_state, project_state + ) + self.assertTableExists("test_dlmtimo_pony") + self.assertTableExists("test_dlmtimo_shetlandpony") + self.assertColumnExists("test_dlmtimo_shetlandpony", "pony_ptr_id") def test_rename_model(self): """ @@ -605,51 +668,69 @@ class OperationTests(OperationTestBase): # Test the state alteration operation = migrations.RenameModel("Pony", "Horse") self.assertEqual(operation.describe(), "Rename model Pony to Horse") - self.assertEqual(operation.migration_name_fragment, 'rename_pony_horse') + self.assertEqual(operation.migration_name_fragment, "rename_pony_horse") # Test initial state and database self.assertIn(("test_rnmo", "pony"), project_state.models) self.assertNotIn(("test_rnmo", "horse"), project_state.models) self.assertTableExists("test_rnmo_pony") self.assertTableNotExists("test_rnmo_horse") if connection.features.supports_foreign_keys: - self.assertFKExists("test_rnmo_rider", ["pony_id"], ("test_rnmo_pony", "id")) - self.assertFKNotExists("test_rnmo_rider", ["pony_id"], ("test_rnmo_horse", "id")) + self.assertFKExists( + "test_rnmo_rider", ["pony_id"], ("test_rnmo_pony", "id") + ) + self.assertFKNotExists( + "test_rnmo_rider", ["pony_id"], ("test_rnmo_horse", "id") + ) # Migrate forwards new_state = project_state.clone() atomic_rename = connection.features.supports_atomic_references_rename - new_state = self.apply_operations("test_rnmo", new_state, [operation], atomic=atomic_rename) + new_state = self.apply_operations( + "test_rnmo", new_state, [operation], atomic=atomic_rename + ) # Test new state and database self.assertNotIn(("test_rnmo", "pony"), new_state.models) self.assertIn(("test_rnmo", "horse"), new_state.models) # RenameModel also repoints all incoming FKs and M2Ms self.assertEqual( - new_state.models['test_rnmo', 'rider'].fields['pony'].remote_field.model, - 'test_rnmo.Horse', + new_state.models["test_rnmo", "rider"].fields["pony"].remote_field.model, + "test_rnmo.Horse", ) self.assertTableNotExists("test_rnmo_pony") self.assertTableExists("test_rnmo_horse") if connection.features.supports_foreign_keys: - self.assertFKNotExists("test_rnmo_rider", ["pony_id"], ("test_rnmo_pony", "id")) - self.assertFKExists("test_rnmo_rider", ["pony_id"], ("test_rnmo_horse", "id")) + self.assertFKNotExists( + "test_rnmo_rider", ["pony_id"], ("test_rnmo_pony", "id") + ) + self.assertFKExists( + "test_rnmo_rider", ["pony_id"], ("test_rnmo_horse", "id") + ) # Migrate backwards - original_state = self.unapply_operations("test_rnmo", project_state, [operation], atomic=atomic_rename) + original_state = self.unapply_operations( + "test_rnmo", project_state, [operation], atomic=atomic_rename + ) # Test original state and database self.assertIn(("test_rnmo", "pony"), original_state.models) self.assertNotIn(("test_rnmo", "horse"), original_state.models) self.assertEqual( - original_state.models['test_rnmo', 'rider'].fields['pony'].remote_field.model, - 'Pony', + original_state.models["test_rnmo", "rider"] + .fields["pony"] + .remote_field.model, + "Pony", ) self.assertTableExists("test_rnmo_pony") self.assertTableNotExists("test_rnmo_horse") if connection.features.supports_foreign_keys: - self.assertFKExists("test_rnmo_rider", ["pony_id"], ("test_rnmo_pony", "id")) - self.assertFKNotExists("test_rnmo_rider", ["pony_id"], ("test_rnmo_horse", "id")) + self.assertFKExists( + "test_rnmo_rider", ["pony_id"], ("test_rnmo_pony", "id") + ) + self.assertFKNotExists( + "test_rnmo_rider", ["pony_id"], ("test_rnmo_horse", "id") + ) # And deconstruction definition = operation.deconstruct() self.assertEqual(definition[0], "RenameModel") self.assertEqual(definition[1], []) - self.assertEqual(definition[2], {'old_name': "Pony", 'new_name': "Horse"}) + self.assertEqual(definition[2], {"old_name": "Pony", "new_name": "Horse"}) def test_rename_model_state_forwards(self): """ @@ -657,19 +738,19 @@ class OperationTests(OperationTestBase): on state without prior apps. """ state = ProjectState() - state.add_model(ModelState('migrations', 'Foo', [])) - operation = migrations.RenameModel('Foo', 'Bar') - operation.state_forwards('migrations', state) - self.assertNotIn('apps', state.__dict__) - self.assertNotIn(('migrations', 'foo'), state.models) - self.assertIn(('migrations', 'bar'), state.models) + state.add_model(ModelState("migrations", "Foo", [])) + operation = migrations.RenameModel("Foo", "Bar") + operation.state_forwards("migrations", state) + self.assertNotIn("apps", state.__dict__) + self.assertNotIn(("migrations", "foo"), state.models) + self.assertIn(("migrations", "bar"), state.models) # Now with apps cached. apps = state.apps - operation = migrations.RenameModel('Bar', 'Foo') - operation.state_forwards('migrations', state) + operation = migrations.RenameModel("Bar", "Foo") + operation.state_forwards("migrations", state) self.assertIs(state.apps, apps) - self.assertNotIn(('migrations', 'bar'), state.models) - self.assertIn(('migrations', 'foo'), state.models) + self.assertNotIn(("migrations", "bar"), state.models) + self.assertIn(("migrations", "foo"), state.models) def test_rename_model_with_self_referential_fk(self): """ @@ -685,105 +766,168 @@ class OperationTests(OperationTestBase): self.assertIn(("test_rmwsrf", "horserider"), new_state.models) # Remember, RenameModel also repoints all incoming FKs and M2Ms self.assertEqual( - 'self', - new_state.models["test_rmwsrf", "horserider"].fields['friend'].remote_field.model + "self", + new_state.models["test_rmwsrf", "horserider"] + .fields["friend"] + .remote_field.model, + ) + HorseRider = new_state.apps.get_model("test_rmwsrf", "horserider") + self.assertIs( + HorseRider._meta.get_field("horserider").remote_field.model, HorseRider ) - HorseRider = new_state.apps.get_model('test_rmwsrf', 'horserider') - self.assertIs(HorseRider._meta.get_field('horserider').remote_field.model, HorseRider) # Test the database alteration self.assertTableExists("test_rmwsrf_rider") self.assertTableNotExists("test_rmwsrf_horserider") if connection.features.supports_foreign_keys: - self.assertFKExists("test_rmwsrf_rider", ["friend_id"], ("test_rmwsrf_rider", "id")) - self.assertFKNotExists("test_rmwsrf_rider", ["friend_id"], ("test_rmwsrf_horserider", "id")) + self.assertFKExists( + "test_rmwsrf_rider", ["friend_id"], ("test_rmwsrf_rider", "id") + ) + self.assertFKNotExists( + "test_rmwsrf_rider", ["friend_id"], ("test_rmwsrf_horserider", "id") + ) atomic_rename = connection.features.supports_atomic_references_rename with connection.schema_editor(atomic=atomic_rename) as editor: operation.database_forwards("test_rmwsrf", editor, project_state, new_state) self.assertTableNotExists("test_rmwsrf_rider") self.assertTableExists("test_rmwsrf_horserider") if connection.features.supports_foreign_keys: - self.assertFKNotExists("test_rmwsrf_horserider", ["friend_id"], ("test_rmwsrf_rider", "id")) - self.assertFKExists("test_rmwsrf_horserider", ["friend_id"], ("test_rmwsrf_horserider", "id")) + self.assertFKNotExists( + "test_rmwsrf_horserider", ["friend_id"], ("test_rmwsrf_rider", "id") + ) + self.assertFKExists( + "test_rmwsrf_horserider", + ["friend_id"], + ("test_rmwsrf_horserider", "id"), + ) # And test reversal with connection.schema_editor(atomic=atomic_rename) as editor: - operation.database_backwards("test_rmwsrf", editor, new_state, project_state) + operation.database_backwards( + "test_rmwsrf", editor, new_state, project_state + ) self.assertTableExists("test_rmwsrf_rider") self.assertTableNotExists("test_rmwsrf_horserider") if connection.features.supports_foreign_keys: - self.assertFKExists("test_rmwsrf_rider", ["friend_id"], ("test_rmwsrf_rider", "id")) - self.assertFKNotExists("test_rmwsrf_rider", ["friend_id"], ("test_rmwsrf_horserider", "id")) + self.assertFKExists( + "test_rmwsrf_rider", ["friend_id"], ("test_rmwsrf_rider", "id") + ) + self.assertFKNotExists( + "test_rmwsrf_rider", ["friend_id"], ("test_rmwsrf_horserider", "id") + ) def test_rename_model_with_superclass_fk(self): """ Tests the RenameModel operation on a model which has a superclass that has a foreign key. """ - project_state = self.set_up_test_model("test_rmwsc", related_model=True, mti_model=True) + project_state = self.set_up_test_model( + "test_rmwsc", related_model=True, mti_model=True + ) # Test the state alteration operation = migrations.RenameModel("ShetlandPony", "LittleHorse") - self.assertEqual(operation.describe(), "Rename model ShetlandPony to LittleHorse") + self.assertEqual( + operation.describe(), "Rename model ShetlandPony to LittleHorse" + ) new_state = project_state.clone() operation.state_forwards("test_rmwsc", new_state) self.assertNotIn(("test_rmwsc", "shetlandpony"), new_state.models) self.assertIn(("test_rmwsc", "littlehorse"), new_state.models) # RenameModel shouldn't repoint the superclass's relations, only local ones self.assertEqual( - project_state.models['test_rmwsc', 'rider'].fields['pony'].remote_field.model, - new_state.models['test_rmwsc', 'rider'].fields['pony'].remote_field.model, + project_state.models["test_rmwsc", "rider"] + .fields["pony"] + .remote_field.model, + new_state.models["test_rmwsc", "rider"].fields["pony"].remote_field.model, ) # Before running the migration we have a table for Shetland Pony, not Little Horse self.assertTableExists("test_rmwsc_shetlandpony") self.assertTableNotExists("test_rmwsc_littlehorse") if connection.features.supports_foreign_keys: # and the foreign key on rider points to pony, not shetland pony - self.assertFKExists("test_rmwsc_rider", ["pony_id"], ("test_rmwsc_pony", "id")) - self.assertFKNotExists("test_rmwsc_rider", ["pony_id"], ("test_rmwsc_shetlandpony", "id")) - with connection.schema_editor(atomic=connection.features.supports_atomic_references_rename) as editor: + self.assertFKExists( + "test_rmwsc_rider", ["pony_id"], ("test_rmwsc_pony", "id") + ) + self.assertFKNotExists( + "test_rmwsc_rider", ["pony_id"], ("test_rmwsc_shetlandpony", "id") + ) + with connection.schema_editor( + atomic=connection.features.supports_atomic_references_rename + ) as editor: operation.database_forwards("test_rmwsc", editor, project_state, new_state) # Now we have a little horse table, not shetland pony self.assertTableNotExists("test_rmwsc_shetlandpony") self.assertTableExists("test_rmwsc_littlehorse") if connection.features.supports_foreign_keys: # but the Foreign keys still point at pony, not little horse - self.assertFKExists("test_rmwsc_rider", ["pony_id"], ("test_rmwsc_pony", "id")) - self.assertFKNotExists("test_rmwsc_rider", ["pony_id"], ("test_rmwsc_littlehorse", "id")) + self.assertFKExists( + "test_rmwsc_rider", ["pony_id"], ("test_rmwsc_pony", "id") + ) + self.assertFKNotExists( + "test_rmwsc_rider", ["pony_id"], ("test_rmwsc_littlehorse", "id") + ) def test_rename_model_with_self_referential_m2m(self): app_label = "test_rename_model_with_self_referential_m2m" - project_state = self.apply_operations(app_label, ProjectState(), operations=[ - migrations.CreateModel("ReflexivePony", fields=[ - ("id", models.AutoField(primary_key=True)), - ("ponies", models.ManyToManyField("self")), - ]), - ]) - project_state = self.apply_operations(app_label, project_state, operations=[ - migrations.RenameModel("ReflexivePony", "ReflexivePony2"), - ], atomic=connection.features.supports_atomic_references_rename) + project_state = self.apply_operations( + app_label, + ProjectState(), + operations=[ + migrations.CreateModel( + "ReflexivePony", + fields=[ + ("id", models.AutoField(primary_key=True)), + ("ponies", models.ManyToManyField("self")), + ], + ), + ], + ) + project_state = self.apply_operations( + app_label, + project_state, + operations=[ + migrations.RenameModel("ReflexivePony", "ReflexivePony2"), + ], + atomic=connection.features.supports_atomic_references_rename, + ) Pony = project_state.apps.get_model(app_label, "ReflexivePony2") pony = Pony.objects.create() pony.ponies.add(pony) def test_rename_model_with_m2m(self): app_label = "test_rename_model_with_m2m" - project_state = self.apply_operations(app_label, ProjectState(), operations=[ - migrations.CreateModel("Rider", fields=[ - ("id", models.AutoField(primary_key=True)), - ]), - migrations.CreateModel("Pony", fields=[ - ("id", models.AutoField(primary_key=True)), - ("riders", models.ManyToManyField("Rider")), - ]), - ]) + project_state = self.apply_operations( + app_label, + ProjectState(), + operations=[ + migrations.CreateModel( + "Rider", + fields=[ + ("id", models.AutoField(primary_key=True)), + ], + ), + migrations.CreateModel( + "Pony", + fields=[ + ("id", models.AutoField(primary_key=True)), + ("riders", models.ManyToManyField("Rider")), + ], + ), + ], + ) Pony = project_state.apps.get_model(app_label, "Pony") Rider = project_state.apps.get_model(app_label, "Rider") pony = Pony.objects.create() rider = Rider.objects.create() pony.riders.add(rider) - project_state = self.apply_operations(app_label, project_state, operations=[ - migrations.RenameModel("Pony", "Pony2"), - ], atomic=connection.features.supports_atomic_references_rename) + project_state = self.apply_operations( + app_label, + project_state, + operations=[ + migrations.RenameModel("Pony", "Pony2"), + ], + atomic=connection.features.supports_atomic_references_rename, + ) Pony = project_state.apps.get_model(app_label, "Pony2") Rider = project_state.apps.get_model(app_label, "Rider") pony = Pony.objects.create() @@ -791,21 +935,37 @@ class OperationTests(OperationTestBase): pony.riders.add(rider) self.assertEqual(Pony.objects.count(), 2) self.assertEqual(Rider.objects.count(), 2) - self.assertEqual(Pony._meta.get_field('riders').remote_field.through.objects.count(), 2) + self.assertEqual( + Pony._meta.get_field("riders").remote_field.through.objects.count(), 2 + ) def test_rename_model_with_db_table_noop(self): - app_label = 'test_rmwdbtn' - project_state = self.apply_operations(app_label, ProjectState(), operations=[ - migrations.CreateModel('Rider', fields=[ - ('id', models.AutoField(primary_key=True)), - ], options={'db_table': 'rider'}), - migrations.CreateModel('Pony', fields=[ - ('id', models.AutoField(primary_key=True)), - ('rider', models.ForeignKey('%s.Rider' % app_label, models.CASCADE)), - ]), - ]) + app_label = "test_rmwdbtn" + project_state = self.apply_operations( + app_label, + ProjectState(), + operations=[ + migrations.CreateModel( + "Rider", + fields=[ + ("id", models.AutoField(primary_key=True)), + ], + options={"db_table": "rider"}, + ), + migrations.CreateModel( + "Pony", + fields=[ + ("id", models.AutoField(primary_key=True)), + ( + "rider", + models.ForeignKey("%s.Rider" % app_label, models.CASCADE), + ), + ], + ), + ], + ) new_state = project_state.clone() - operation = migrations.RenameModel('Rider', 'Runner') + operation = migrations.RenameModel("Rider", "Runner") operation.state_forwards(app_label, new_state) with connection.schema_editor() as editor: @@ -813,28 +973,45 @@ class OperationTests(OperationTestBase): operation.database_forwards(app_label, editor, project_state, new_state) with connection.schema_editor() as editor: with self.assertNumQueries(0): - operation.database_backwards(app_label, editor, new_state, project_state) + operation.database_backwards( + app_label, editor, new_state, project_state + ) def test_rename_m2m_target_model(self): app_label = "test_rename_m2m_target_model" - project_state = self.apply_operations(app_label, ProjectState(), operations=[ - migrations.CreateModel("Rider", fields=[ - ("id", models.AutoField(primary_key=True)), - ]), - migrations.CreateModel("Pony", fields=[ - ("id", models.AutoField(primary_key=True)), - ("riders", models.ManyToManyField("Rider")), - ]), - ]) + project_state = self.apply_operations( + app_label, + ProjectState(), + operations=[ + migrations.CreateModel( + "Rider", + fields=[ + ("id", models.AutoField(primary_key=True)), + ], + ), + migrations.CreateModel( + "Pony", + fields=[ + ("id", models.AutoField(primary_key=True)), + ("riders", models.ManyToManyField("Rider")), + ], + ), + ], + ) Pony = project_state.apps.get_model(app_label, "Pony") Rider = project_state.apps.get_model(app_label, "Rider") pony = Pony.objects.create() rider = Rider.objects.create() pony.riders.add(rider) - project_state = self.apply_operations(app_label, project_state, operations=[ - migrations.RenameModel("Rider", "Rider2"), - ], atomic=connection.features.supports_atomic_references_rename) + project_state = self.apply_operations( + app_label, + project_state, + operations=[ + migrations.RenameModel("Rider", "Rider2"), + ], + atomic=connection.features.supports_atomic_references_rename, + ) Pony = project_state.apps.get_model(app_label, "Pony") Rider = project_state.apps.get_model(app_label, "Rider2") pony = Pony.objects.create() @@ -842,28 +1019,56 @@ class OperationTests(OperationTestBase): pony.riders.add(rider) self.assertEqual(Pony.objects.count(), 2) self.assertEqual(Rider.objects.count(), 2) - self.assertEqual(Pony._meta.get_field('riders').remote_field.through.objects.count(), 2) + self.assertEqual( + Pony._meta.get_field("riders").remote_field.through.objects.count(), 2 + ) def test_rename_m2m_through_model(self): app_label = "test_rename_through" - project_state = self.apply_operations(app_label, ProjectState(), operations=[ - migrations.CreateModel("Rider", fields=[ - ("id", models.AutoField(primary_key=True)), - ]), - migrations.CreateModel("Pony", fields=[ - ("id", models.AutoField(primary_key=True)), - ]), - migrations.CreateModel("PonyRider", fields=[ - ("id", models.AutoField(primary_key=True)), - ("rider", models.ForeignKey("test_rename_through.Rider", models.CASCADE)), - ("pony", models.ForeignKey("test_rename_through.Pony", models.CASCADE)), - ]), - migrations.AddField( - "Pony", - "riders", - models.ManyToManyField("test_rename_through.Rider", through="test_rename_through.PonyRider"), - ), - ]) + project_state = self.apply_operations( + app_label, + ProjectState(), + operations=[ + migrations.CreateModel( + "Rider", + fields=[ + ("id", models.AutoField(primary_key=True)), + ], + ), + migrations.CreateModel( + "Pony", + fields=[ + ("id", models.AutoField(primary_key=True)), + ], + ), + migrations.CreateModel( + "PonyRider", + fields=[ + ("id", models.AutoField(primary_key=True)), + ( + "rider", + models.ForeignKey( + "test_rename_through.Rider", models.CASCADE + ), + ), + ( + "pony", + models.ForeignKey( + "test_rename_through.Pony", models.CASCADE + ), + ), + ], + ), + migrations.AddField( + "Pony", + "riders", + models.ManyToManyField( + "test_rename_through.Rider", + through="test_rename_through.PonyRider", + ), + ), + ], + ) Pony = project_state.apps.get_model(app_label, "Pony") Rider = project_state.apps.get_model(app_label, "Rider") PonyRider = project_state.apps.get_model(app_label, "PonyRider") @@ -871,9 +1076,13 @@ class OperationTests(OperationTestBase): rider = Rider.objects.create() PonyRider.objects.create(pony=pony, rider=rider) - project_state = self.apply_operations(app_label, project_state, operations=[ - migrations.RenameModel("PonyRider", "PonyRider2"), - ]) + project_state = self.apply_operations( + app_label, + project_state, + operations=[ + migrations.RenameModel("PonyRider", "PonyRider2"), + ], + ) Pony = project_state.apps.get_model(app_label, "Pony") Rider = project_state.apps.get_model(app_label, "Rider") PonyRider = project_state.apps.get_model(app_label, "PonyRider2") @@ -887,28 +1096,49 @@ class OperationTests(OperationTestBase): def test_rename_m2m_model_after_rename_field(self): """RenameModel renames a many-to-many column after a RenameField.""" - app_label = 'test_rename_multiple' - project_state = self.apply_operations(app_label, ProjectState(), operations=[ - migrations.CreateModel('Pony', fields=[ - ('id', models.AutoField(primary_key=True)), - ('name', models.CharField(max_length=20)), - ]), - migrations.CreateModel('Rider', fields=[ - ('id', models.AutoField(primary_key=True)), - ('pony', models.ForeignKey('test_rename_multiple.Pony', models.CASCADE)), - ]), - migrations.CreateModel('PonyRider', fields=[ - ('id', models.AutoField(primary_key=True)), - ('riders', models.ManyToManyField('Rider')), - ]), - migrations.RenameField(model_name='pony', old_name='name', new_name='fancy_name'), - migrations.RenameModel(old_name='Rider', new_name='Jockey'), - ], atomic=connection.features.supports_atomic_references_rename) - Pony = project_state.apps.get_model(app_label, 'Pony') - Jockey = project_state.apps.get_model(app_label, 'Jockey') - PonyRider = project_state.apps.get_model(app_label, 'PonyRider') + app_label = "test_rename_multiple" + project_state = self.apply_operations( + app_label, + ProjectState(), + operations=[ + migrations.CreateModel( + "Pony", + fields=[ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=20)), + ], + ), + migrations.CreateModel( + "Rider", + fields=[ + ("id", models.AutoField(primary_key=True)), + ( + "pony", + models.ForeignKey( + "test_rename_multiple.Pony", models.CASCADE + ), + ), + ], + ), + migrations.CreateModel( + "PonyRider", + fields=[ + ("id", models.AutoField(primary_key=True)), + ("riders", models.ManyToManyField("Rider")), + ], + ), + migrations.RenameField( + model_name="pony", old_name="name", new_name="fancy_name" + ), + migrations.RenameModel(old_name="Rider", new_name="Jockey"), + ], + atomic=connection.features.supports_atomic_references_rename, + ) + Pony = project_state.apps.get_model(app_label, "Pony") + Jockey = project_state.apps.get_model(app_label, "Jockey") + PonyRider = project_state.apps.get_model(app_label, "PonyRider") # No "no such column" error means the column was renamed correctly. - pony = Pony.objects.create(fancy_name='a good name') + pony = Pony.objects.create(fancy_name="a good name") jockey = Jockey.objects.create(pony=pony) ponyrider = PonyRider.objects.create() ponyrider.riders.add(jockey) @@ -924,10 +1154,10 @@ class OperationTests(OperationTestBase): models.FloatField(null=True, default=5), ) self.assertEqual(operation.describe(), "Add field height to Pony") - self.assertEqual(operation.migration_name_fragment, 'pony_height') + self.assertEqual(operation.migration_name_fragment, "pony_height") project_state, new_state = self.make_test_state("test_adfl", operation) self.assertEqual(len(new_state.models["test_adfl", "pony"].fields), 4) - field = new_state.models['test_adfl', 'pony'].fields['height'] + field = new_state.models["test_adfl", "pony"].fields["height"] self.assertEqual(field.default, 5) # Test the database alteration self.assertColumnNotExists("test_adfl_pony", "height") @@ -953,30 +1183,34 @@ class OperationTests(OperationTestBase): Pony = project_state.apps.get_model("test_adchfl", "Pony") pony = Pony.objects.create(weight=42) - new_state = self.apply_operations("test_adchfl", project_state, [ - migrations.AddField( - "Pony", - "text", - models.CharField(max_length=10, default="some text"), - ), - migrations.AddField( - "Pony", - "empty", - models.CharField(max_length=10, default=""), - ), - # If not properly quoted digits would be interpreted as an int. - migrations.AddField( - "Pony", - "digits", - models.CharField(max_length=10, default="42"), - ), - # Manual quoting is fragile and could trip on quotes. Refs #xyz. - migrations.AddField( - "Pony", - "quotes", - models.CharField(max_length=10, default='"\'"'), - ), - ]) + new_state = self.apply_operations( + "test_adchfl", + project_state, + [ + migrations.AddField( + "Pony", + "text", + models.CharField(max_length=10, default="some text"), + ), + migrations.AddField( + "Pony", + "empty", + models.CharField(max_length=10, default=""), + ), + # If not properly quoted digits would be interpreted as an int. + migrations.AddField( + "Pony", + "digits", + models.CharField(max_length=10, default="42"), + ), + # Manual quoting is fragile and could trip on quotes. Refs #xyz. + migrations.AddField( + "Pony", + "quotes", + models.CharField(max_length=10, default='"\'"'), + ), + ], + ) Pony = new_state.apps.get_model("test_adchfl", "Pony") pony = Pony.objects.get(pk=pony.pk) @@ -994,30 +1228,34 @@ class OperationTests(OperationTestBase): Pony = project_state.apps.get_model("test_adtxtfl", "Pony") pony = Pony.objects.create(weight=42) - new_state = self.apply_operations("test_adtxtfl", project_state, [ - migrations.AddField( - "Pony", - "text", - models.TextField(default="some text"), - ), - migrations.AddField( - "Pony", - "empty", - models.TextField(default=""), - ), - # If not properly quoted digits would be interpreted as an int. - migrations.AddField( - "Pony", - "digits", - models.TextField(default="42"), - ), - # Manual quoting is fragile and could trip on quotes. Refs #xyz. - migrations.AddField( - "Pony", - "quotes", - models.TextField(default='"\'"'), - ), - ]) + new_state = self.apply_operations( + "test_adtxtfl", + project_state, + [ + migrations.AddField( + "Pony", + "text", + models.TextField(default="some text"), + ), + migrations.AddField( + "Pony", + "empty", + models.TextField(default=""), + ), + # If not properly quoted digits would be interpreted as an int. + migrations.AddField( + "Pony", + "digits", + models.TextField(default="42"), + ), + # Manual quoting is fragile and could trip on quotes. Refs #xyz. + migrations.AddField( + "Pony", + "quotes", + models.TextField(default='"\'"'), + ), + ], + ) Pony = new_state.apps.get_model("test_adtxtfl", "Pony") pony = Pony.objects.get(pk=pony.pk) @@ -1035,30 +1273,34 @@ class OperationTests(OperationTestBase): Pony = project_state.apps.get_model("test_adbinfl", "Pony") pony = Pony.objects.create(weight=42) - new_state = self.apply_operations("test_adbinfl", project_state, [ - migrations.AddField( - "Pony", - "blob", - models.BinaryField(default=b"some text"), - ), - migrations.AddField( - "Pony", - "empty", - models.BinaryField(default=b""), - ), - # If not properly quoted digits would be interpreted as an int. - migrations.AddField( - "Pony", - "digits", - models.BinaryField(default=b"42"), - ), - # Manual quoting is fragile and could trip on quotes. Refs #xyz. - migrations.AddField( - "Pony", - "quotes", - models.BinaryField(default=b'"\'"'), - ), - ]) + new_state = self.apply_operations( + "test_adbinfl", + project_state, + [ + migrations.AddField( + "Pony", + "blob", + models.BinaryField(default=b"some text"), + ), + migrations.AddField( + "Pony", + "empty", + models.BinaryField(default=b""), + ), + # If not properly quoted digits would be interpreted as an int. + migrations.AddField( + "Pony", + "digits", + models.BinaryField(default=b"42"), + ), + # Manual quoting is fragile and could trip on quotes. Refs #xyz. + migrations.AddField( + "Pony", + "quotes", + models.BinaryField(default=b'"\'"'), + ), + ], + ) Pony = new_state.apps.get_model("test_adbinfl", "Pony") pony = Pony.objects.get(pk=pony.pk) @@ -1082,7 +1324,9 @@ class OperationTests(OperationTestBase): new_state = project_state.clone() operation.state_forwards("test_regr22168", new_state) with connection.schema_editor() as editor: - operation.database_forwards("test_regr22168", editor, project_state, new_state) + operation.database_forwards( + "test_regr22168", editor, project_state, new_state + ) self.assertColumnExists("test_regr22168_pony", "order") def test_add_field_preserve_default(self): @@ -1101,7 +1345,7 @@ class OperationTests(OperationTestBase): new_state = project_state.clone() operation.state_forwards("test_adflpd", new_state) self.assertEqual(len(new_state.models["test_adflpd", "pony"].fields), 4) - field = new_state.models['test_adflpd', 'pony'].fields['height'] + field = new_state.models["test_adflpd", "pony"].fields["height"] self.assertEqual(field.default, models.NOT_PROVIDED) # Test the database alteration project_state.apps.get_model("test_adflpd", "pony").objects.create( @@ -1115,7 +1359,9 @@ class OperationTests(OperationTestBase): definition = operation.deconstruct() self.assertEqual(definition[0], "AddField") self.assertEqual(definition[1], []) - self.assertEqual(sorted(definition[2]), ["field", "model_name", "name", "preserve_default"]) + self.assertEqual( + sorted(definition[2]), ["field", "model_name", "name", "preserve_default"] + ) def test_add_field_m2m(self): """ @@ -1123,7 +1369,9 @@ class OperationTests(OperationTestBase): """ project_state = self.set_up_test_model("test_adflmm", second_model=True) # Test the state alteration - operation = migrations.AddField("Pony", "stables", models.ManyToManyField("Stable", related_name="ponies")) + operation = migrations.AddField( + "Pony", "stables", models.ManyToManyField("Stable", related_name="ponies") + ) new_state = project_state.clone() operation.state_forwards("test_adflmm", new_state) self.assertEqual(len(new_state.models["test_adflmm", "pony"].fields), 4) @@ -1142,37 +1390,73 @@ class OperationTests(OperationTestBase): p.stables.all().delete() # And test reversal with connection.schema_editor() as editor: - operation.database_backwards("test_adflmm", editor, new_state, project_state) + operation.database_backwards( + "test_adflmm", editor, new_state, project_state + ) self.assertTableNotExists("test_adflmm_pony_stables") def test_alter_field_m2m(self): project_state = self.set_up_test_model("test_alflmm", second_model=True) - project_state = self.apply_operations("test_alflmm", project_state, operations=[ - migrations.AddField("Pony", "stables", models.ManyToManyField("Stable", related_name="ponies")) - ]) + project_state = self.apply_operations( + "test_alflmm", + project_state, + operations=[ + migrations.AddField( + "Pony", + "stables", + models.ManyToManyField("Stable", related_name="ponies"), + ) + ], + ) Pony = project_state.apps.get_model("test_alflmm", "Pony") - self.assertFalse(Pony._meta.get_field('stables').blank) + self.assertFalse(Pony._meta.get_field("stables").blank) - project_state = self.apply_operations("test_alflmm", project_state, operations=[ - migrations.AlterField( - "Pony", "stables", models.ManyToManyField(to="Stable", related_name="ponies", blank=True) - ) - ]) + project_state = self.apply_operations( + "test_alflmm", + project_state, + operations=[ + migrations.AlterField( + "Pony", + "stables", + models.ManyToManyField( + to="Stable", related_name="ponies", blank=True + ), + ) + ], + ) Pony = project_state.apps.get_model("test_alflmm", "Pony") - self.assertTrue(Pony._meta.get_field('stables').blank) + self.assertTrue(Pony._meta.get_field("stables").blank) def test_repoint_field_m2m(self): - project_state = self.set_up_test_model("test_alflmm", second_model=True, third_model=True) + project_state = self.set_up_test_model( + "test_alflmm", second_model=True, third_model=True + ) - project_state = self.apply_operations("test_alflmm", project_state, operations=[ - migrations.AddField("Pony", "places", models.ManyToManyField("Stable", related_name="ponies")) - ]) + project_state = self.apply_operations( + "test_alflmm", + project_state, + operations=[ + migrations.AddField( + "Pony", + "places", + models.ManyToManyField("Stable", related_name="ponies"), + ) + ], + ) Pony = project_state.apps.get_model("test_alflmm", "Pony") - project_state = self.apply_operations("test_alflmm", project_state, operations=[ - migrations.AlterField("Pony", "places", models.ManyToManyField(to="Van", related_name="ponies")) - ]) + project_state = self.apply_operations( + "test_alflmm", + project_state, + operations=[ + migrations.AlterField( + "Pony", + "places", + models.ManyToManyField(to="Van", related_name="ponies"), + ) + ], + ) # Ensure the new field actually works Pony = project_state.apps.get_model("test_alflmm", "Pony") @@ -1184,14 +1468,24 @@ class OperationTests(OperationTestBase): def test_remove_field_m2m(self): project_state = self.set_up_test_model("test_rmflmm", second_model=True) - project_state = self.apply_operations("test_rmflmm", project_state, operations=[ - migrations.AddField("Pony", "stables", models.ManyToManyField("Stable", related_name="ponies")) - ]) + project_state = self.apply_operations( + "test_rmflmm", + project_state, + operations=[ + migrations.AddField( + "Pony", + "stables", + models.ManyToManyField("Stable", related_name="ponies"), + ) + ], + ) self.assertTableExists("test_rmflmm_pony_stables") with_field_state = project_state.clone() operations = [migrations.RemoveField("Pony", "stables")] - project_state = self.apply_operations("test_rmflmm", project_state, operations=operations) + project_state = self.apply_operations( + "test_rmflmm", project_state, operations=operations + ) self.assertTableNotExists("test_rmflmm_pony_stables") # And test reversal @@ -1202,19 +1496,40 @@ class OperationTests(OperationTestBase): project_state = self.set_up_test_model("test_rmflmmwt", second_model=True) self.assertTableNotExists("test_rmflmmwt_ponystables") - project_state = self.apply_operations("test_rmflmmwt", project_state, operations=[ - migrations.CreateModel("PonyStables", fields=[ - ("pony", models.ForeignKey('test_rmflmmwt.Pony', models.CASCADE)), - ("stable", models.ForeignKey('test_rmflmmwt.Stable', models.CASCADE)), - ]), - migrations.AddField( - "Pony", "stables", - models.ManyToManyField("Stable", related_name="ponies", through='test_rmflmmwt.PonyStables') - ) - ]) + project_state = self.apply_operations( + "test_rmflmmwt", + project_state, + operations=[ + migrations.CreateModel( + "PonyStables", + fields=[ + ( + "pony", + models.ForeignKey("test_rmflmmwt.Pony", models.CASCADE), + ), + ( + "stable", + models.ForeignKey("test_rmflmmwt.Stable", models.CASCADE), + ), + ], + ), + migrations.AddField( + "Pony", + "stables", + models.ManyToManyField( + "Stable", + related_name="ponies", + through="test_rmflmmwt.PonyStables", + ), + ), + ], + ) self.assertTableExists("test_rmflmmwt_ponystables") - operations = [migrations.RemoveField("Pony", "stables"), migrations.DeleteModel("PonyStables")] + operations = [ + migrations.RemoveField("Pony", "stables"), + migrations.DeleteModel("PonyStables"), + ] self.apply_operations("test_rmflmmwt", project_state, operations=operations) def test_remove_field(self): @@ -1225,7 +1540,7 @@ class OperationTests(OperationTestBase): # Test the state alteration operation = migrations.RemoveField("Pony", "pink") self.assertEqual(operation.describe(), "Remove field pink from Pony") - self.assertEqual(operation.migration_name_fragment, 'remove_pony_pink') + self.assertEqual(operation.migration_name_fragment, "remove_pony_pink") new_state = project_state.clone() operation.state_forwards("test_rmfl", new_state) self.assertEqual(len(new_state.models["test_rmfl", "pony"].fields), 2) @@ -1242,7 +1557,7 @@ class OperationTests(OperationTestBase): definition = operation.deconstruct() self.assertEqual(definition[0], "RemoveField") self.assertEqual(definition[1], []) - self.assertEqual(definition[2], {'model_name': "Pony", 'name': 'pink'}) + self.assertEqual(definition[2], {"model_name": "Pony", "name": "pink"}) def test_remove_fk(self): """ @@ -1268,11 +1583,16 @@ class OperationTests(OperationTestBase): project_state = self.set_up_test_model("test_almota") # Test the state alteration operation = migrations.AlterModelTable("Pony", "test_almota_pony_2") - self.assertEqual(operation.describe(), "Rename table for Pony to test_almota_pony_2") - self.assertEqual(operation.migration_name_fragment, 'alter_pony_table') + self.assertEqual( + operation.describe(), "Rename table for Pony to test_almota_pony_2" + ) + self.assertEqual(operation.migration_name_fragment, "alter_pony_table") new_state = project_state.clone() operation.state_forwards("test_almota", new_state) - self.assertEqual(new_state.models["test_almota", "pony"].options["db_table"], "test_almota_pony_2") + self.assertEqual( + new_state.models["test_almota", "pony"].options["db_table"], + "test_almota_pony_2", + ) # Test the database alteration self.assertTableExists("test_almota_pony") self.assertTableNotExists("test_almota_pony_2") @@ -1282,14 +1602,16 @@ class OperationTests(OperationTestBase): self.assertTableExists("test_almota_pony_2") # And test reversal with connection.schema_editor() as editor: - operation.database_backwards("test_almota", editor, new_state, project_state) + operation.database_backwards( + "test_almota", editor, new_state, project_state + ) self.assertTableExists("test_almota_pony") self.assertTableNotExists("test_almota_pony_2") # And deconstruction definition = operation.deconstruct() self.assertEqual(definition[0], "AlterModelTable") self.assertEqual(definition[1], []) - self.assertEqual(definition[2], {'name': "Pony", 'table': "test_almota_pony_2"}) + self.assertEqual(definition[2], {"name": "Pony", "table": "test_almota_pony_2"}) def test_alter_model_table_none(self): """ @@ -1307,7 +1629,10 @@ class OperationTests(OperationTestBase): operation = migrations.AlterModelTable("Pony", "test_almota_pony") new_state = project_state.clone() operation.state_forwards("test_almota", new_state) - self.assertEqual(new_state.models["test_almota", "pony"].options["db_table"], "test_almota_pony") + self.assertEqual( + new_state.models["test_almota", "pony"].options["db_table"], + "test_almota_pony", + ) # Test the database alteration self.assertTableExists("test_almota_pony") with connection.schema_editor() as editor: @@ -1315,7 +1640,9 @@ class OperationTests(OperationTestBase): self.assertTableExists("test_almota_pony") # And test reversal with connection.schema_editor() as editor: - operation.database_backwards("test_almota", editor, new_state, project_state) + operation.database_backwards( + "test_almota", editor, new_state, project_state + ) self.assertTableExists("test_almota_pony") def test_alter_model_table_m2m(self): @@ -1323,11 +1650,15 @@ class OperationTests(OperationTestBase): AlterModelTable should rename auto-generated M2M tables. """ app_label = "test_talflmltlm2m" - pony_db_table = 'pony_foo' - project_state = self.set_up_test_model(app_label, second_model=True, db_table=pony_db_table) + pony_db_table = "pony_foo" + project_state = self.set_up_test_model( + app_label, second_model=True, db_table=pony_db_table + ) # Add the M2M field first_state = project_state.clone() - operation = migrations.AddField("Pony", "stables", models.ManyToManyField("Stable")) + operation = migrations.AddField( + "Pony", "stables", models.ManyToManyField("Stable") + ) operation.state_forwards(app_label, first_state) with connection.schema_editor() as editor: operation.database_forwards(app_label, editor, project_state, first_state) @@ -1337,7 +1668,7 @@ class OperationTests(OperationTestBase): self.assertTableNotExists(new_m2m_table) # Rename the Pony db_table which should also rename the m2m table. second_state = first_state.clone() - operation = migrations.AlterModelTable(name='pony', table=None) + operation = migrations.AlterModelTable(name="pony", table=None) operation.state_forwards(app_label, second_state) atomic_rename = connection.features.supports_atomic_references_rename with connection.schema_editor(atomic=atomic_rename) as editor: @@ -1356,13 +1687,17 @@ class OperationTests(OperationTestBase): """ project_state = self.set_up_test_model("test_alfl") # Test the state alteration - operation = migrations.AlterField("Pony", "pink", models.IntegerField(null=True)) + operation = migrations.AlterField( + "Pony", "pink", models.IntegerField(null=True) + ) self.assertEqual(operation.describe(), "Alter field pink on Pony") - self.assertEqual(operation.migration_name_fragment, 'alter_pony_pink') + self.assertEqual(operation.migration_name_fragment, "alter_pony_pink") new_state = project_state.clone() operation.state_forwards("test_alfl", new_state) - self.assertIs(project_state.models['test_alfl', 'pony'].fields['pink'].null, False) - self.assertIs(new_state.models['test_alfl', 'pony'].fields['pink'].null, True) + self.assertIs( + project_state.models["test_alfl", "pony"].fields["pink"].null, False + ) + self.assertIs(new_state.models["test_alfl", "pony"].fields["pink"].null, True) # Test the database alteration self.assertColumnNotNull("test_alfl_pony", "pink") with connection.schema_editor() as editor: @@ -1383,53 +1718,57 @@ class OperationTests(OperationTestBase): AlterField operation is a noop when adding only a db_column and the column name is not changed. """ - app_label = 'test_afadbn' + app_label = "test_afadbn" project_state = self.set_up_test_model(app_label, related_model=True) - pony_table = '%s_pony' % app_label + pony_table = "%s_pony" % app_label new_state = project_state.clone() - operation = migrations.AlterField('Pony', 'weight', models.FloatField(db_column='weight')) + operation = migrations.AlterField( + "Pony", "weight", models.FloatField(db_column="weight") + ) operation.state_forwards(app_label, new_state) self.assertIsNone( - project_state.models[app_label, 'pony'].fields['weight'].db_column, + project_state.models[app_label, "pony"].fields["weight"].db_column, ) self.assertEqual( - new_state.models[app_label, 'pony'].fields['weight'].db_column, - 'weight', + new_state.models[app_label, "pony"].fields["weight"].db_column, + "weight", ) - self.assertColumnExists(pony_table, 'weight') + self.assertColumnExists(pony_table, "weight") with connection.schema_editor() as editor: with self.assertNumQueries(0): operation.database_forwards(app_label, editor, project_state, new_state) - self.assertColumnExists(pony_table, 'weight') + self.assertColumnExists(pony_table, "weight") with connection.schema_editor() as editor: with self.assertNumQueries(0): - operation.database_backwards(app_label, editor, new_state, project_state) - self.assertColumnExists(pony_table, 'weight') + operation.database_backwards( + app_label, editor, new_state, project_state + ) + self.assertColumnExists(pony_table, "weight") - rider_table = '%s_rider' % app_label + rider_table = "%s_rider" % app_label new_state = project_state.clone() operation = migrations.AlterField( - 'Rider', - 'pony', - models.ForeignKey('Pony', models.CASCADE, db_column='pony_id'), + "Rider", + "pony", + models.ForeignKey("Pony", models.CASCADE, db_column="pony_id"), ) operation.state_forwards(app_label, new_state) self.assertIsNone( - project_state.models[app_label, 'rider'].fields['pony'].db_column, + project_state.models[app_label, "rider"].fields["pony"].db_column, ) self.assertIs( - new_state.models[app_label, 'rider'].fields['pony'].db_column, - 'pony_id', + new_state.models[app_label, "rider"].fields["pony"].db_column, + "pony_id", ) - self.assertColumnExists(rider_table, 'pony_id') + self.assertColumnExists(rider_table, "pony_id") with connection.schema_editor() as editor: with self.assertNumQueries(0): operation.database_forwards(app_label, editor, project_state, new_state) - self.assertColumnExists(rider_table, 'pony_id') + self.assertColumnExists(rider_table, "pony_id") with connection.schema_editor() as editor: with self.assertNumQueries(0): operation.database_forwards(app_label, editor, new_state, project_state) - self.assertColumnExists(rider_table, 'pony_id') + self.assertColumnExists(rider_table, "pony_id") def test_alter_field_pk(self): """ @@ -1437,15 +1776,17 @@ class OperationTests(OperationTestBase): """ project_state = self.set_up_test_model("test_alflpk") # Test the state alteration - operation = migrations.AlterField("Pony", "id", models.IntegerField(primary_key=True)) + operation = migrations.AlterField( + "Pony", "id", models.IntegerField(primary_key=True) + ) new_state = project_state.clone() operation.state_forwards("test_alflpk", new_state) self.assertIsInstance( - project_state.models['test_alflpk', 'pony'].fields['id'], + project_state.models["test_alflpk", "pony"].fields["id"], models.AutoField, ) self.assertIsInstance( - new_state.models['test_alflpk', 'pony'].fields['id'], + new_state.models["test_alflpk", "pony"].fields["id"], models.IntegerField, ) # Test the database alteration @@ -1453,34 +1794,45 @@ class OperationTests(OperationTestBase): operation.database_forwards("test_alflpk", editor, project_state, new_state) # And test reversal with connection.schema_editor() as editor: - operation.database_backwards("test_alflpk", editor, new_state, project_state) + operation.database_backwards( + "test_alflpk", editor, new_state, project_state + ) - @skipUnlessDBFeature('supports_foreign_keys') + @skipUnlessDBFeature("supports_foreign_keys") def test_alter_field_pk_fk(self): """ Tests the AlterField operation on primary keys changes any FKs pointing to it. """ project_state = self.set_up_test_model("test_alflpkfk", related_model=True) - project_state = self.apply_operations('test_alflpkfk', project_state, [ - migrations.CreateModel('Stable', fields=[ - ('ponies', models.ManyToManyField('Pony')), - ]), - migrations.AddField( - 'Pony', - 'stables', - models.ManyToManyField('Stable'), - ), - ]) + project_state = self.apply_operations( + "test_alflpkfk", + project_state, + [ + migrations.CreateModel( + "Stable", + fields=[ + ("ponies", models.ManyToManyField("Pony")), + ], + ), + migrations.AddField( + "Pony", + "stables", + models.ManyToManyField("Stable"), + ), + ], + ) # Test the state alteration - operation = migrations.AlterField("Pony", "id", models.FloatField(primary_key=True)) + operation = migrations.AlterField( + "Pony", "id", models.FloatField(primary_key=True) + ) new_state = project_state.clone() operation.state_forwards("test_alflpkfk", new_state) self.assertIsInstance( - project_state.models['test_alflpkfk', 'pony'].fields['id'], + project_state.models["test_alflpkfk", "pony"].fields["id"], models.AutoField, ) self.assertIsInstance( - new_state.models['test_alflpkfk', 'pony'].fields['id'], + new_state.models["test_alflpkfk", "pony"].fields["id"], models.FloatField, ) @@ -1488,27 +1840,33 @@ class OperationTests(OperationTestBase): with connection.cursor() as cursor: id_type, id_null = [ (c.type_code, c.null_ok) - for c in connection.introspection.get_table_description(cursor, "test_alflpkfk_pony") + for c in connection.introspection.get_table_description( + cursor, "test_alflpkfk_pony" + ) if c.name == "id" ][0] fk_type, fk_null = [ (c.type_code, c.null_ok) - for c in connection.introspection.get_table_description(cursor, "test_alflpkfk_rider") + for c in connection.introspection.get_table_description( + cursor, "test_alflpkfk_rider" + ) if c.name == "pony_id" ][0] m2m_fk_type, m2m_fk_null = [ (c.type_code, c.null_ok) for c in connection.introspection.get_table_description( cursor, - 'test_alflpkfk_pony_stables', - ) if c.name == 'pony_id' + "test_alflpkfk_pony_stables", + ) + if c.name == "pony_id" ][0] remote_m2m_fk_type, remote_m2m_fk_null = [ (c.type_code, c.null_ok) for c in connection.introspection.get_table_description( cursor, - 'test_alflpkfk_stable_ponies', - ) if c.name == 'pony_id' + "test_alflpkfk_stable_ponies", + ) + if c.name == "pony_id" ][0] self.assertEqual(id_type, fk_type) self.assertEqual(id_type, m2m_fk_type) @@ -1520,55 +1878,68 @@ class OperationTests(OperationTestBase): assertIdTypeEqualsFkType() # Test the database alteration with connection.schema_editor() as editor: - operation.database_forwards("test_alflpkfk", editor, project_state, new_state) + operation.database_forwards( + "test_alflpkfk", editor, project_state, new_state + ) assertIdTypeEqualsFkType() if connection.features.supports_foreign_keys: self.assertFKExists( - 'test_alflpkfk_pony_stables', - ['pony_id'], - ('test_alflpkfk_pony', 'id'), + "test_alflpkfk_pony_stables", + ["pony_id"], + ("test_alflpkfk_pony", "id"), ) self.assertFKExists( - 'test_alflpkfk_stable_ponies', - ['pony_id'], - ('test_alflpkfk_pony', 'id'), + "test_alflpkfk_stable_ponies", + ["pony_id"], + ("test_alflpkfk_pony", "id"), ) # And test reversal with connection.schema_editor() as editor: - operation.database_backwards("test_alflpkfk", editor, new_state, project_state) + operation.database_backwards( + "test_alflpkfk", editor, new_state, project_state + ) assertIdTypeEqualsFkType() if connection.features.supports_foreign_keys: self.assertFKExists( - 'test_alflpkfk_pony_stables', - ['pony_id'], - ('test_alflpkfk_pony', 'id'), + "test_alflpkfk_pony_stables", + ["pony_id"], + ("test_alflpkfk_pony", "id"), ) self.assertFKExists( - 'test_alflpkfk_stable_ponies', - ['pony_id'], - ('test_alflpkfk_pony', 'id'), + "test_alflpkfk_stable_ponies", + ["pony_id"], + ("test_alflpkfk_pony", "id"), ) def test_alter_field_pk_mti_fk(self): - app_label = 'test_alflpkmtifk' + app_label = "test_alflpkmtifk" project_state = self.set_up_test_model(app_label, mti_model=True) - project_state = self.apply_operations(app_label, project_state, [ - migrations.CreateModel('ShetlandRider', fields=[ - ( - 'pony', - models.ForeignKey(f'{app_label}.ShetlandPony', models.CASCADE), + project_state = self.apply_operations( + app_label, + project_state, + [ + migrations.CreateModel( + "ShetlandRider", + fields=[ + ( + "pony", + models.ForeignKey( + f"{app_label}.ShetlandPony", models.CASCADE + ), + ), + ], ), - ]), - ]) + ], + ) operation = migrations.AlterField( - 'Pony', - 'id', + "Pony", + "id", models.BigAutoField(primary_key=True), ) new_state = project_state.clone() operation.state_forwards(app_label, new_state) self.assertIsInstance( - new_state.models[app_label, 'pony'].fields['id'], + new_state.models[app_label, "pony"].fields["id"], models.BigAutoField, ) @@ -1577,16 +1948,18 @@ class OperationTests(OperationTestBase): c.type_code for c in connection.introspection.get_table_description( cursor, - f'{app_label}_{table}', + f"{app_label}_{table}", ) if c.name == column ][0] def assertIdTypeEqualsMTIFkType(): with connection.cursor() as cursor: - parent_id_type = _get_column_id_type(cursor, 'pony', 'id') - child_id_type = _get_column_id_type(cursor, 'shetlandpony', 'pony_ptr_id') - mti_id_type = _get_column_id_type(cursor, 'shetlandrider', 'pony_id') + parent_id_type = _get_column_id_type(cursor, "pony", "id") + child_id_type = _get_column_id_type( + cursor, "shetlandpony", "pony_ptr_id" + ) + mti_id_type = _get_column_id_type(cursor, "shetlandrider", "pony_id") self.assertEqual(parent_id_type, child_id_type) self.assertEqual(parent_id_type, mti_id_type) @@ -1597,14 +1970,14 @@ class OperationTests(OperationTestBase): assertIdTypeEqualsMTIFkType() if connection.features.supports_foreign_keys: self.assertFKExists( - f'{app_label}_shetlandpony', - ['pony_ptr_id'], - (f'{app_label}_pony', 'id'), + f"{app_label}_shetlandpony", + ["pony_ptr_id"], + (f"{app_label}_pony", "id"), ) self.assertFKExists( - f'{app_label}_shetlandrider', - ['pony_id'], - (f'{app_label}_shetlandpony', 'pony_ptr_id'), + f"{app_label}_shetlandrider", + ["pony_id"], + (f"{app_label}_shetlandpony", "pony_ptr_id"), ) # Reversal. with connection.schema_editor() as editor: @@ -1612,30 +1985,32 @@ class OperationTests(OperationTestBase): assertIdTypeEqualsMTIFkType() if connection.features.supports_foreign_keys: self.assertFKExists( - f'{app_label}_shetlandpony', - ['pony_ptr_id'], - (f'{app_label}_pony', 'id'), + f"{app_label}_shetlandpony", + ["pony_ptr_id"], + (f"{app_label}_pony", "id"), ) self.assertFKExists( - f'{app_label}_shetlandrider', - ['pony_id'], - (f'{app_label}_shetlandpony', 'pony_ptr_id'), + f"{app_label}_shetlandrider", + ["pony_id"], + (f"{app_label}_shetlandpony", "pony_ptr_id"), ) def test_alter_field_pk_mti_and_fk_to_base(self): - app_label = 'test_alflpkmtiftb' + app_label = "test_alflpkmtiftb" project_state = self.set_up_test_model( - app_label, mti_model=True, related_model=True, + app_label, + mti_model=True, + related_model=True, ) operation = migrations.AlterField( - 'Pony', - 'id', + "Pony", + "id", models.BigAutoField(primary_key=True), ) new_state = project_state.clone() operation.state_forwards(app_label, new_state) self.assertIsInstance( - new_state.models[app_label, 'pony'].fields['id'], + new_state.models[app_label, "pony"].fields["id"], models.BigAutoField, ) @@ -1644,16 +2019,18 @@ class OperationTests(OperationTestBase): c.type_code for c in connection.introspection.get_table_description( cursor, - f'{app_label}_{table}', + f"{app_label}_{table}", ) if c.name == column ][0] def assertIdTypeEqualsMTIFkType(): with connection.cursor() as cursor: - parent_id_type = _get_column_id_type(cursor, 'pony', 'id') - fk_id_type = _get_column_id_type(cursor, 'rider', 'pony_id') - child_id_type = _get_column_id_type(cursor, 'shetlandpony', 'pony_ptr_id') + parent_id_type = _get_column_id_type(cursor, "pony", "id") + fk_id_type = _get_column_id_type(cursor, "rider", "pony_id") + child_id_type = _get_column_id_type( + cursor, "shetlandpony", "pony_ptr_id" + ) self.assertEqual(parent_id_type, child_id_type) self.assertEqual(parent_id_type, fk_id_type) @@ -1664,14 +2041,14 @@ class OperationTests(OperationTestBase): assertIdTypeEqualsMTIFkType() if connection.features.supports_foreign_keys: self.assertFKExists( - f'{app_label}_shetlandpony', - ['pony_ptr_id'], - (f'{app_label}_pony', 'id'), + f"{app_label}_shetlandpony", + ["pony_ptr_id"], + (f"{app_label}_pony", "id"), ) self.assertFKExists( - f'{app_label}_rider', - ['pony_id'], - (f'{app_label}_pony', 'id'), + f"{app_label}_rider", + ["pony_id"], + (f"{app_label}_pony", "id"), ) # Reversal. with connection.schema_editor() as editor: @@ -1679,69 +2056,99 @@ class OperationTests(OperationTestBase): assertIdTypeEqualsMTIFkType() if connection.features.supports_foreign_keys: self.assertFKExists( - f'{app_label}_shetlandpony', - ['pony_ptr_id'], - (f'{app_label}_pony', 'id'), + f"{app_label}_shetlandpony", + ["pony_ptr_id"], + (f"{app_label}_pony", "id"), ) self.assertFKExists( - f'{app_label}_rider', - ['pony_id'], - (f'{app_label}_pony', 'id'), + f"{app_label}_rider", + ["pony_id"], + (f"{app_label}_pony", "id"), ) - @skipUnlessDBFeature('supports_foreign_keys') + @skipUnlessDBFeature("supports_foreign_keys") def test_alter_field_reloads_state_on_fk_with_to_field_target_type_change(self): - app_label = 'test_alflrsfkwtflttc' - project_state = self.apply_operations(app_label, ProjectState(), operations=[ - migrations.CreateModel('Rider', fields=[ - ('id', models.AutoField(primary_key=True)), - ('code', models.IntegerField(unique=True)), - ]), - migrations.CreateModel('Pony', fields=[ - ('id', models.AutoField(primary_key=True)), - ('rider', models.ForeignKey('%s.Rider' % app_label, models.CASCADE, to_field='code')), - ]), - ]) + app_label = "test_alflrsfkwtflttc" + project_state = self.apply_operations( + app_label, + ProjectState(), + operations=[ + migrations.CreateModel( + "Rider", + fields=[ + ("id", models.AutoField(primary_key=True)), + ("code", models.IntegerField(unique=True)), + ], + ), + migrations.CreateModel( + "Pony", + fields=[ + ("id", models.AutoField(primary_key=True)), + ( + "rider", + models.ForeignKey( + "%s.Rider" % app_label, models.CASCADE, to_field="code" + ), + ), + ], + ), + ], + ) operation = migrations.AlterField( - 'Rider', - 'code', + "Rider", + "code", models.CharField(max_length=100, unique=True), ) self.apply_operations(app_label, project_state, operations=[operation]) id_type, id_null = [ (c.type_code, c.null_ok) - for c in self.get_table_description('%s_rider' % app_label) - if c.name == 'code' + for c in self.get_table_description("%s_rider" % app_label) + if c.name == "code" ][0] fk_type, fk_null = [ (c.type_code, c.null_ok) - for c in self.get_table_description('%s_pony' % app_label) - if c.name == 'rider_id' + for c in self.get_table_description("%s_pony" % app_label) + if c.name == "rider_id" ][0] self.assertEqual(id_type, fk_type) self.assertEqual(id_null, fk_null) - @skipUnlessDBFeature('supports_foreign_keys') - def test_alter_field_reloads_state_on_fk_with_to_field_related_name_target_type_change(self): - app_label = 'test_alflrsfkwtflrnttc' - project_state = self.apply_operations(app_label, ProjectState(), operations=[ - migrations.CreateModel('Rider', fields=[ - ('id', models.AutoField(primary_key=True)), - ('code', models.PositiveIntegerField(unique=True)), - ]), - migrations.CreateModel('Pony', fields=[ - ('id', models.AutoField(primary_key=True)), - ('rider', models.ForeignKey( - '%s.Rider' % app_label, - models.CASCADE, - to_field='code', - related_name='+', - )), - ]), - ]) + @skipUnlessDBFeature("supports_foreign_keys") + def test_alter_field_reloads_state_on_fk_with_to_field_related_name_target_type_change( + self, + ): + app_label = "test_alflrsfkwtflrnttc" + project_state = self.apply_operations( + app_label, + ProjectState(), + operations=[ + migrations.CreateModel( + "Rider", + fields=[ + ("id", models.AutoField(primary_key=True)), + ("code", models.PositiveIntegerField(unique=True)), + ], + ), + migrations.CreateModel( + "Pony", + fields=[ + ("id", models.AutoField(primary_key=True)), + ( + "rider", + models.ForeignKey( + "%s.Rider" % app_label, + models.CASCADE, + to_field="code", + related_name="+", + ), + ), + ], + ), + ], + ) operation = migrations.AlterField( - 'Rider', - 'code', + "Rider", + "code", models.CharField(max_length=100, unique=True), ) self.apply_operations(app_label, project_state, operations=[operation]) @@ -1752,24 +2159,51 @@ class OperationTests(OperationTestBase): crashes on MySQL due to not dropping the PonyRider.pony foreign key constraint before modifying the column. """ - app_label = 'alter_alter_field_reloads_state_on_fk_target_changes' - project_state = self.apply_operations(app_label, ProjectState(), operations=[ - migrations.CreateModel('Rider', fields=[ - ('id', models.CharField(primary_key=True, max_length=100)), - ]), - migrations.CreateModel('Pony', fields=[ - ('id', models.CharField(primary_key=True, max_length=100)), - ('rider', models.ForeignKey('%s.Rider' % app_label, models.CASCADE)), - ]), - migrations.CreateModel('PonyRider', fields=[ - ('id', models.AutoField(primary_key=True)), - ('pony', models.ForeignKey('%s.Pony' % app_label, models.CASCADE)), - ]), - ]) - project_state = self.apply_operations(app_label, project_state, operations=[ - migrations.AlterField('Rider', 'id', models.CharField(primary_key=True, max_length=99)), - migrations.AlterField('Pony', 'id', models.CharField(primary_key=True, max_length=99)), - ]) + app_label = "alter_alter_field_reloads_state_on_fk_target_changes" + project_state = self.apply_operations( + app_label, + ProjectState(), + operations=[ + migrations.CreateModel( + "Rider", + fields=[ + ("id", models.CharField(primary_key=True, max_length=100)), + ], + ), + migrations.CreateModel( + "Pony", + fields=[ + ("id", models.CharField(primary_key=True, max_length=100)), + ( + "rider", + models.ForeignKey("%s.Rider" % app_label, models.CASCADE), + ), + ], + ), + migrations.CreateModel( + "PonyRider", + fields=[ + ("id", models.AutoField(primary_key=True)), + ( + "pony", + models.ForeignKey("%s.Pony" % app_label, models.CASCADE), + ), + ], + ), + ], + ) + project_state = self.apply_operations( + app_label, + project_state, + operations=[ + migrations.AlterField( + "Rider", "id", models.CharField(primary_key=True, max_length=99) + ), + migrations.AlterField( + "Pony", "id", models.CharField(primary_key=True, max_length=99) + ), + ], + ) def test_alter_field_reloads_state_on_fk_with_to_field_target_changes(self): """ @@ -1777,26 +2211,57 @@ class OperationTests(OperationTestBase): crashes on MySQL due to not dropping the PonyRider.pony foreign key constraint before modifying the column. """ - app_label = 'alter_alter_field_reloads_state_on_fk_with_to_field_target_changes' - project_state = self.apply_operations(app_label, ProjectState(), operations=[ - migrations.CreateModel('Rider', fields=[ - ('id', models.CharField(primary_key=True, max_length=100)), - ('slug', models.CharField(unique=True, max_length=100)), - ]), - migrations.CreateModel('Pony', fields=[ - ('id', models.CharField(primary_key=True, max_length=100)), - ('rider', models.ForeignKey('%s.Rider' % app_label, models.CASCADE, to_field='slug')), - ('slug', models.CharField(unique=True, max_length=100)), - ]), - migrations.CreateModel('PonyRider', fields=[ - ('id', models.AutoField(primary_key=True)), - ('pony', models.ForeignKey('%s.Pony' % app_label, models.CASCADE, to_field='slug')), - ]), - ]) - project_state = self.apply_operations(app_label, project_state, operations=[ - migrations.AlterField('Rider', 'slug', models.CharField(unique=True, max_length=99)), - migrations.AlterField('Pony', 'slug', models.CharField(unique=True, max_length=99)), - ]) + app_label = "alter_alter_field_reloads_state_on_fk_with_to_field_target_changes" + project_state = self.apply_operations( + app_label, + ProjectState(), + operations=[ + migrations.CreateModel( + "Rider", + fields=[ + ("id", models.CharField(primary_key=True, max_length=100)), + ("slug", models.CharField(unique=True, max_length=100)), + ], + ), + migrations.CreateModel( + "Pony", + fields=[ + ("id", models.CharField(primary_key=True, max_length=100)), + ( + "rider", + models.ForeignKey( + "%s.Rider" % app_label, models.CASCADE, to_field="slug" + ), + ), + ("slug", models.CharField(unique=True, max_length=100)), + ], + ), + migrations.CreateModel( + "PonyRider", + fields=[ + ("id", models.AutoField(primary_key=True)), + ( + "pony", + models.ForeignKey( + "%s.Pony" % app_label, models.CASCADE, to_field="slug" + ), + ), + ], + ), + ], + ) + project_state = self.apply_operations( + app_label, + project_state, + operations=[ + migrations.AlterField( + "Rider", "slug", models.CharField(unique=True, max_length=99) + ), + migrations.AlterField( + "Pony", "slug", models.CharField(unique=True, max_length=99) + ), + ], + ) def test_rename_field_reloads_state_on_fk_target_changes(self): """ @@ -1804,44 +2269,80 @@ class OperationTests(OperationTestBase): crashes on MySQL due to not dropping the PonyRider.pony foreign key constraint before modifying the column. """ - app_label = 'alter_rename_field_reloads_state_on_fk_target_changes' - project_state = self.apply_operations(app_label, ProjectState(), operations=[ - migrations.CreateModel('Rider', fields=[ - ('id', models.CharField(primary_key=True, max_length=100)), - ]), - migrations.CreateModel('Pony', fields=[ - ('id', models.CharField(primary_key=True, max_length=100)), - ('rider', models.ForeignKey('%s.Rider' % app_label, models.CASCADE)), - ]), - migrations.CreateModel('PonyRider', fields=[ - ('id', models.AutoField(primary_key=True)), - ('pony', models.ForeignKey('%s.Pony' % app_label, models.CASCADE)), - ]), - ]) - project_state = self.apply_operations(app_label, project_state, operations=[ - migrations.RenameField('Rider', 'id', 'id2'), - migrations.AlterField('Pony', 'id', models.CharField(primary_key=True, max_length=99)), - ], atomic=connection.features.supports_atomic_references_rename) + app_label = "alter_rename_field_reloads_state_on_fk_target_changes" + project_state = self.apply_operations( + app_label, + ProjectState(), + operations=[ + migrations.CreateModel( + "Rider", + fields=[ + ("id", models.CharField(primary_key=True, max_length=100)), + ], + ), + migrations.CreateModel( + "Pony", + fields=[ + ("id", models.CharField(primary_key=True, max_length=100)), + ( + "rider", + models.ForeignKey("%s.Rider" % app_label, models.CASCADE), + ), + ], + ), + migrations.CreateModel( + "PonyRider", + fields=[ + ("id", models.AutoField(primary_key=True)), + ( + "pony", + models.ForeignKey("%s.Pony" % app_label, models.CASCADE), + ), + ], + ), + ], + ) + project_state = self.apply_operations( + app_label, + project_state, + operations=[ + migrations.RenameField("Rider", "id", "id2"), + migrations.AlterField( + "Pony", "id", models.CharField(primary_key=True, max_length=99) + ), + ], + atomic=connection.features.supports_atomic_references_rename, + ) def test_rename_field(self): """ Tests the RenameField operation. """ - project_state = self.set_up_test_model("test_rnfl", unique_together=True, index_together=True) + project_state = self.set_up_test_model( + "test_rnfl", unique_together=True, index_together=True + ) # Test the state alteration operation = migrations.RenameField("Pony", "pink", "blue") self.assertEqual(operation.describe(), "Rename field pink on Pony to blue") - self.assertEqual(operation.migration_name_fragment, 'rename_pink_pony_blue') + self.assertEqual(operation.migration_name_fragment, "rename_pink_pony_blue") new_state = project_state.clone() operation.state_forwards("test_rnfl", new_state) self.assertIn("blue", new_state.models["test_rnfl", "pony"].fields) self.assertNotIn("pink", new_state.models["test_rnfl", "pony"].fields) # Make sure the unique_together has the renamed column too - self.assertIn("blue", new_state.models["test_rnfl", "pony"].options['unique_together'][0]) - self.assertNotIn("pink", new_state.models["test_rnfl", "pony"].options['unique_together'][0]) + self.assertIn( + "blue", new_state.models["test_rnfl", "pony"].options["unique_together"][0] + ) + self.assertNotIn( + "pink", new_state.models["test_rnfl", "pony"].options["unique_together"][0] + ) # Make sure the index_together has the renamed column too - self.assertIn("blue", new_state.models["test_rnfl", "pony"].options['index_together'][0]) - self.assertNotIn("pink", new_state.models["test_rnfl", "pony"].options['index_together'][0]) + self.assertIn( + "blue", new_state.models["test_rnfl", "pony"].options["index_together"][0] + ) + self.assertNotIn( + "pink", new_state.models["test_rnfl", "pony"].options["index_together"][0] + ) # Test the database alteration self.assertColumnExists("test_rnfl_pony", "pink") self.assertColumnNotExists("test_rnfl_pony", "blue") @@ -1854,7 +2355,9 @@ class OperationTests(OperationTestBase): cursor.execute("INSERT INTO test_rnfl_pony (blue, weight) VALUES (1, 1)") with self.assertRaises(IntegrityError): with atomic(): - cursor.execute("INSERT INTO test_rnfl_pony (blue, weight) VALUES (1, 1)") + cursor.execute( + "INSERT INTO test_rnfl_pony (blue, weight) VALUES (1, 1)" + ) cursor.execute("DELETE FROM test_rnfl_pony") # Ensure the index constraint has been ported over self.assertIndexExists("test_rnfl_pony", ["weight", "blue"]) @@ -1869,105 +2372,189 @@ class OperationTests(OperationTestBase): definition = operation.deconstruct() self.assertEqual(definition[0], "RenameField") self.assertEqual(definition[1], []) - self.assertEqual(definition[2], {'model_name': "Pony", 'old_name': "pink", 'new_name': "blue"}) + self.assertEqual( + definition[2], + {"model_name": "Pony", "old_name": "pink", "new_name": "blue"}, + ) def test_rename_field_with_db_column(self): - project_state = self.apply_operations('test_rfwdbc', ProjectState(), operations=[ - migrations.CreateModel('Pony', fields=[ - ('id', models.AutoField(primary_key=True)), - ('field', models.IntegerField(db_column='db_field')), - ('fk_field', models.ForeignKey( - 'Pony', - models.CASCADE, - db_column='db_fk_field', - )), - ]), - ]) + project_state = self.apply_operations( + "test_rfwdbc", + ProjectState(), + operations=[ + migrations.CreateModel( + "Pony", + fields=[ + ("id", models.AutoField(primary_key=True)), + ("field", models.IntegerField(db_column="db_field")), + ( + "fk_field", + models.ForeignKey( + "Pony", + models.CASCADE, + db_column="db_fk_field", + ), + ), + ], + ), + ], + ) new_state = project_state.clone() - operation = migrations.RenameField('Pony', 'field', 'renamed_field') - operation.state_forwards('test_rfwdbc', new_state) - self.assertIn('renamed_field', new_state.models['test_rfwdbc', 'pony'].fields) - self.assertNotIn('field', new_state.models['test_rfwdbc', 'pony'].fields) - self.assertColumnExists('test_rfwdbc_pony', 'db_field') + operation = migrations.RenameField("Pony", "field", "renamed_field") + operation.state_forwards("test_rfwdbc", new_state) + self.assertIn("renamed_field", new_state.models["test_rfwdbc", "pony"].fields) + self.assertNotIn("field", new_state.models["test_rfwdbc", "pony"].fields) + self.assertColumnExists("test_rfwdbc_pony", "db_field") with connection.schema_editor() as editor: with self.assertNumQueries(0): - operation.database_forwards('test_rfwdbc', editor, project_state, new_state) - self.assertColumnExists('test_rfwdbc_pony', 'db_field') + operation.database_forwards( + "test_rfwdbc", editor, project_state, new_state + ) + self.assertColumnExists("test_rfwdbc_pony", "db_field") with connection.schema_editor() as editor: with self.assertNumQueries(0): - operation.database_backwards('test_rfwdbc', editor, new_state, project_state) - self.assertColumnExists('test_rfwdbc_pony', 'db_field') + operation.database_backwards( + "test_rfwdbc", editor, new_state, project_state + ) + self.assertColumnExists("test_rfwdbc_pony", "db_field") new_state = project_state.clone() - operation = migrations.RenameField('Pony', 'fk_field', 'renamed_fk_field') - operation.state_forwards('test_rfwdbc', new_state) - self.assertIn('renamed_fk_field', new_state.models['test_rfwdbc', 'pony'].fields) - self.assertNotIn('fk_field', new_state.models['test_rfwdbc', 'pony'].fields) - self.assertColumnExists('test_rfwdbc_pony', 'db_fk_field') + operation = migrations.RenameField("Pony", "fk_field", "renamed_fk_field") + operation.state_forwards("test_rfwdbc", new_state) + self.assertIn( + "renamed_fk_field", new_state.models["test_rfwdbc", "pony"].fields + ) + self.assertNotIn("fk_field", new_state.models["test_rfwdbc", "pony"].fields) + self.assertColumnExists("test_rfwdbc_pony", "db_fk_field") with connection.schema_editor() as editor: with self.assertNumQueries(0): - operation.database_forwards('test_rfwdbc', editor, project_state, new_state) - self.assertColumnExists('test_rfwdbc_pony', 'db_fk_field') + operation.database_forwards( + "test_rfwdbc", editor, project_state, new_state + ) + self.assertColumnExists("test_rfwdbc_pony", "db_fk_field") with connection.schema_editor() as editor: with self.assertNumQueries(0): - operation.database_backwards('test_rfwdbc', editor, new_state, project_state) - self.assertColumnExists('test_rfwdbc_pony', 'db_fk_field') + operation.database_backwards( + "test_rfwdbc", editor, new_state, project_state + ) + self.assertColumnExists("test_rfwdbc_pony", "db_fk_field") def test_rename_field_case(self): - project_state = self.apply_operations('test_rfmx', ProjectState(), operations=[ - migrations.CreateModel('Pony', fields=[ - ('id', models.AutoField(primary_key=True)), - ('field', models.IntegerField()), - ]), - ]) + project_state = self.apply_operations( + "test_rfmx", + ProjectState(), + operations=[ + migrations.CreateModel( + "Pony", + fields=[ + ("id", models.AutoField(primary_key=True)), + ("field", models.IntegerField()), + ], + ), + ], + ) new_state = project_state.clone() - operation = migrations.RenameField('Pony', 'field', 'FiElD') - operation.state_forwards('test_rfmx', new_state) - self.assertIn('FiElD', new_state.models['test_rfmx', 'pony'].fields) - self.assertColumnExists('test_rfmx_pony', 'field') + operation = migrations.RenameField("Pony", "field", "FiElD") + operation.state_forwards("test_rfmx", new_state) + self.assertIn("FiElD", new_state.models["test_rfmx", "pony"].fields) + self.assertColumnExists("test_rfmx_pony", "field") with connection.schema_editor() as editor: - operation.database_forwards('test_rfmx', editor, project_state, new_state) + operation.database_forwards("test_rfmx", editor, project_state, new_state) self.assertColumnExists( - 'test_rfmx_pony', - connection.introspection.identifier_converter('FiElD'), + "test_rfmx_pony", + connection.introspection.identifier_converter("FiElD"), ) with connection.schema_editor() as editor: - operation.database_backwards('test_rfmx', editor, new_state, project_state) - self.assertColumnExists('test_rfmx_pony', 'field') + operation.database_backwards("test_rfmx", editor, new_state, project_state) + self.assertColumnExists("test_rfmx_pony", "field") def test_rename_missing_field(self): state = ProjectState() - state.add_model(ModelState('app', 'model', [])) - with self.assertRaisesMessage(FieldDoesNotExist, "app.model has no field named 'field'"): - migrations.RenameField('model', 'field', 'new_field').state_forwards('app', state) + state.add_model(ModelState("app", "model", [])) + with self.assertRaisesMessage( + FieldDoesNotExist, "app.model has no field named 'field'" + ): + migrations.RenameField("model", "field", "new_field").state_forwards( + "app", state + ) def test_rename_referenced_field_state_forward(self): state = ProjectState() - state.add_model(ModelState('app', 'Model', [ - ('id', models.AutoField(primary_key=True)), - ('field', models.IntegerField(unique=True)), - ])) - state.add_model(ModelState('app', 'OtherModel', [ - ('id', models.AutoField(primary_key=True)), - ('fk', models.ForeignKey('Model', models.CASCADE, to_field='field')), - ('fo', models.ForeignObject('Model', models.CASCADE, from_fields=('fk',), to_fields=('field',))), - ])) - operation = migrations.RenameField('Model', 'field', 'renamed') + state.add_model( + ModelState( + "app", + "Model", + [ + ("id", models.AutoField(primary_key=True)), + ("field", models.IntegerField(unique=True)), + ], + ) + ) + state.add_model( + ModelState( + "app", + "OtherModel", + [ + ("id", models.AutoField(primary_key=True)), + ( + "fk", + models.ForeignKey("Model", models.CASCADE, to_field="field"), + ), + ( + "fo", + models.ForeignObject( + "Model", + models.CASCADE, + from_fields=("fk",), + to_fields=("field",), + ), + ), + ], + ) + ) + operation = migrations.RenameField("Model", "field", "renamed") new_state = state.clone() - operation.state_forwards('app', new_state) - self.assertEqual(new_state.models['app', 'othermodel'].fields['fk'].remote_field.field_name, 'renamed') - self.assertEqual(new_state.models['app', 'othermodel'].fields['fk'].from_fields, ['self']) - self.assertEqual(new_state.models['app', 'othermodel'].fields['fk'].to_fields, ('renamed',)) - self.assertEqual(new_state.models['app', 'othermodel'].fields['fo'].from_fields, ('fk',)) - self.assertEqual(new_state.models['app', 'othermodel'].fields['fo'].to_fields, ('renamed',)) - operation = migrations.RenameField('OtherModel', 'fk', 'renamed_fk') + operation.state_forwards("app", new_state) + self.assertEqual( + new_state.models["app", "othermodel"].fields["fk"].remote_field.field_name, + "renamed", + ) + self.assertEqual( + new_state.models["app", "othermodel"].fields["fk"].from_fields, ["self"] + ) + self.assertEqual( + new_state.models["app", "othermodel"].fields["fk"].to_fields, ("renamed",) + ) + self.assertEqual( + new_state.models["app", "othermodel"].fields["fo"].from_fields, ("fk",) + ) + self.assertEqual( + new_state.models["app", "othermodel"].fields["fo"].to_fields, ("renamed",) + ) + operation = migrations.RenameField("OtherModel", "fk", "renamed_fk") new_state = state.clone() - operation.state_forwards('app', new_state) - self.assertEqual(new_state.models['app', 'othermodel'].fields['renamed_fk'].remote_field.field_name, 'renamed') - self.assertEqual(new_state.models['app', 'othermodel'].fields['renamed_fk'].from_fields, ('self',)) - self.assertEqual(new_state.models['app', 'othermodel'].fields['renamed_fk'].to_fields, ('renamed',)) - self.assertEqual(new_state.models['app', 'othermodel'].fields['fo'].from_fields, ('renamed_fk',)) - self.assertEqual(new_state.models['app', 'othermodel'].fields['fo'].to_fields, ('renamed',)) + operation.state_forwards("app", new_state) + self.assertEqual( + new_state.models["app", "othermodel"] + .fields["renamed_fk"] + .remote_field.field_name, + "renamed", + ) + self.assertEqual( + new_state.models["app", "othermodel"].fields["renamed_fk"].from_fields, + ("self",), + ) + self.assertEqual( + new_state.models["app", "othermodel"].fields["renamed_fk"].to_fields, + ("renamed",), + ) + self.assertEqual( + new_state.models["app", "othermodel"].fields["fo"].from_fields, + ("renamed_fk",), + ) + self.assertEqual( + new_state.models["app", "othermodel"].fields["fo"].to_fields, ("renamed",) + ) def test_alter_unique_together(self): """ @@ -1976,15 +2563,31 @@ class OperationTests(OperationTestBase): project_state = self.set_up_test_model("test_alunto") # Test the state alteration operation = migrations.AlterUniqueTogether("Pony", [("pink", "weight")]) - self.assertEqual(operation.describe(), "Alter unique_together for Pony (1 constraint(s))") + self.assertEqual( + operation.describe(), "Alter unique_together for Pony (1 constraint(s))" + ) self.assertEqual( operation.migration_name_fragment, - 'alter_pony_unique_together', + "alter_pony_unique_together", ) new_state = project_state.clone() operation.state_forwards("test_alunto", new_state) - self.assertEqual(len(project_state.models["test_alunto", "pony"].options.get("unique_together", set())), 0) - self.assertEqual(len(new_state.models["test_alunto", "pony"].options.get("unique_together", set())), 1) + self.assertEqual( + len( + project_state.models["test_alunto", "pony"].options.get( + "unique_together", set() + ) + ), + 0, + ) + self.assertEqual( + len( + new_state.models["test_alunto", "pony"].options.get( + "unique_together", set() + ) + ), + 1, + ) # Make sure we can insert duplicate rows with connection.cursor() as cursor: cursor.execute("INSERT INTO test_alunto_pony (pink, weight) VALUES (1, 1)") @@ -1992,31 +2595,48 @@ class OperationTests(OperationTestBase): cursor.execute("DELETE FROM test_alunto_pony") # Test the database alteration with connection.schema_editor() as editor: - operation.database_forwards("test_alunto", editor, project_state, new_state) + operation.database_forwards( + "test_alunto", editor, project_state, new_state + ) cursor.execute("INSERT INTO test_alunto_pony (pink, weight) VALUES (1, 1)") with self.assertRaises(IntegrityError): with atomic(): - cursor.execute("INSERT INTO test_alunto_pony (pink, weight) VALUES (1, 1)") + cursor.execute( + "INSERT INTO test_alunto_pony (pink, weight) VALUES (1, 1)" + ) cursor.execute("DELETE FROM test_alunto_pony") # And test reversal with connection.schema_editor() as editor: - operation.database_backwards("test_alunto", editor, new_state, project_state) + operation.database_backwards( + "test_alunto", editor, new_state, project_state + ) cursor.execute("INSERT INTO test_alunto_pony (pink, weight) VALUES (1, 1)") cursor.execute("INSERT INTO test_alunto_pony (pink, weight) VALUES (1, 1)") cursor.execute("DELETE FROM test_alunto_pony") # Test flat unique_together operation = migrations.AlterUniqueTogether("Pony", ("pink", "weight")) operation.state_forwards("test_alunto", new_state) - self.assertEqual(len(new_state.models["test_alunto", "pony"].options.get("unique_together", set())), 1) + self.assertEqual( + len( + new_state.models["test_alunto", "pony"].options.get( + "unique_together", set() + ) + ), + 1, + ) # And deconstruction definition = operation.deconstruct() self.assertEqual(definition[0], "AlterUniqueTogether") self.assertEqual(definition[1], []) - self.assertEqual(definition[2], {'name': "Pony", 'unique_together': {("pink", "weight")}}) + self.assertEqual( + definition[2], {"name": "Pony", "unique_together": {("pink", "weight")}} + ) def test_alter_unique_together_remove(self): operation = migrations.AlterUniqueTogether("Pony", None) - self.assertEqual(operation.describe(), "Alter unique_together for Pony (0 constraint(s))") + self.assertEqual( + operation.describe(), "Alter unique_together for Pony (0 constraint(s))" + ) def test_add_index(self): """ @@ -2031,15 +2651,20 @@ class OperationTests(OperationTestBase): migrations.AddIndex("Pony", models.Index(fields=["pink"])) index = models.Index(fields=["pink"], name="test_adin_pony_pink_idx") operation = migrations.AddIndex("Pony", index) - self.assertEqual(operation.describe(), "Create index test_adin_pony_pink_idx on field(s) pink of model Pony") + self.assertEqual( + operation.describe(), + "Create index test_adin_pony_pink_idx on field(s) pink of model Pony", + ) self.assertEqual( operation.migration_name_fragment, - 'pony_test_adin_pony_pink_idx', + "pony_test_adin_pony_pink_idx", ) new_state = project_state.clone() operation.state_forwards("test_adin", new_state) # Test the database alteration - self.assertEqual(len(new_state.models["test_adin", "pony"].options['indexes']), 1) + self.assertEqual( + len(new_state.models["test_adin", "pony"].options["indexes"]), 1 + ) self.assertIndexNotExists("test_adin_pony", ["pink"]) with connection.schema_editor() as editor: operation.database_forwards("test_adin", editor, project_state, new_state) @@ -2052,7 +2677,7 @@ class OperationTests(OperationTestBase): definition = operation.deconstruct() self.assertEqual(definition[0], "AddIndex") self.assertEqual(definition[1], []) - self.assertEqual(definition[2], {'model_name': "Pony", 'index': index}) + self.assertEqual(definition[2], {"model_name": "Pony", "index": index}) def test_remove_index(self): """ @@ -2065,12 +2690,14 @@ class OperationTests(OperationTestBase): self.assertEqual(operation.describe(), "Remove index pony_test_idx from Pony") self.assertEqual( operation.migration_name_fragment, - 'remove_pony_pony_test_idx', + "remove_pony_pony_test_idx", ) new_state = project_state.clone() operation.state_forwards("test_rmin", new_state) # Test the state alteration - self.assertEqual(len(new_state.models["test_rmin", "pony"].options['indexes']), 0) + self.assertEqual( + len(new_state.models["test_rmin", "pony"].options["indexes"]), 0 + ) self.assertIndexExists("test_rmin_pony", ["pink", "weight"]) # Test the database alteration with connection.schema_editor() as editor: @@ -2084,7 +2711,7 @@ class OperationTests(OperationTestBase): definition = operation.deconstruct() self.assertEqual(definition[0], "RemoveIndex") self.assertEqual(definition[1], []) - self.assertEqual(definition[2], {'model_name': "Pony", 'name': "pony_test_idx"}) + self.assertEqual(definition[2], {"model_name": "Pony", "name": "pony_test_idx"}) # Also test a field dropped with index - sqlite remake issue operations = [ @@ -2095,7 +2722,7 @@ class OperationTests(OperationTestBase): self.assertIndexExists("test_rmin_pony", ["pink", "weight"]) # Test database alteration new_state = project_state.clone() - self.apply_operations('test_rmin', new_state, operations=operations) + self.apply_operations("test_rmin", new_state, operations=operations) self.assertColumnNotExists("test_rmin_pony", "pink") self.assertIndexNotExists("test_rmin_pony", ["pink", "weight"]) # And test reversal @@ -2103,47 +2730,47 @@ class OperationTests(OperationTestBase): self.assertIndexExists("test_rmin_pony", ["pink", "weight"]) def test_add_index_state_forwards(self): - project_state = self.set_up_test_model('test_adinsf') - index = models.Index(fields=['pink'], name='test_adinsf_pony_pink_idx') - old_model = project_state.apps.get_model('test_adinsf', 'Pony') + project_state = self.set_up_test_model("test_adinsf") + index = models.Index(fields=["pink"], name="test_adinsf_pony_pink_idx") + old_model = project_state.apps.get_model("test_adinsf", "Pony") new_state = project_state.clone() - operation = migrations.AddIndex('Pony', index) - operation.state_forwards('test_adinsf', new_state) - new_model = new_state.apps.get_model('test_adinsf', 'Pony') + operation = migrations.AddIndex("Pony", index) + operation.state_forwards("test_adinsf", new_state) + new_model = new_state.apps.get_model("test_adinsf", "Pony") self.assertIsNot(old_model, new_model) def test_remove_index_state_forwards(self): - project_state = self.set_up_test_model('test_rminsf') - index = models.Index(fields=['pink'], name='test_rminsf_pony_pink_idx') - migrations.AddIndex('Pony', index).state_forwards('test_rminsf', project_state) - old_model = project_state.apps.get_model('test_rminsf', 'Pony') + project_state = self.set_up_test_model("test_rminsf") + index = models.Index(fields=["pink"], name="test_rminsf_pony_pink_idx") + migrations.AddIndex("Pony", index).state_forwards("test_rminsf", project_state) + old_model = project_state.apps.get_model("test_rminsf", "Pony") new_state = project_state.clone() - operation = migrations.RemoveIndex('Pony', 'test_rminsf_pony_pink_idx') - operation.state_forwards('test_rminsf', new_state) - new_model = new_state.apps.get_model('test_rminsf', 'Pony') + operation = migrations.RemoveIndex("Pony", "test_rminsf_pony_pink_idx") + operation.state_forwards("test_rminsf", new_state) + new_model = new_state.apps.get_model("test_rminsf", "Pony") self.assertIsNot(old_model, new_model) - @skipUnlessDBFeature('supports_expression_indexes') + @skipUnlessDBFeature("supports_expression_indexes") def test_add_func_index(self): - app_label = 'test_addfuncin' - index_name = f'{app_label}_pony_abs_idx' - table_name = f'{app_label}_pony' + app_label = "test_addfuncin" + index_name = f"{app_label}_pony_abs_idx" + table_name = f"{app_label}_pony" project_state = self.set_up_test_model(app_label) - index = models.Index(Abs('weight'), name=index_name) - operation = migrations.AddIndex('Pony', index) + index = models.Index(Abs("weight"), name=index_name) + operation = migrations.AddIndex("Pony", index) self.assertEqual( operation.describe(), - 'Create index test_addfuncin_pony_abs_idx on Abs(F(weight)) on model Pony', + "Create index test_addfuncin_pony_abs_idx on Abs(F(weight)) on model Pony", ) self.assertEqual( operation.migration_name_fragment, - 'pony_test_addfuncin_pony_abs_idx', + "pony_test_addfuncin_pony_abs_idx", ) new_state = project_state.clone() operation.state_forwards(app_label, new_state) - self.assertEqual(len(new_state.models[app_label, 'pony'].options['indexes']), 1) + self.assertEqual(len(new_state.models[app_label, "pony"].options["indexes"]), 1) self.assertIndexNameNotExists(table_name, index_name) # Add index. with connection.schema_editor() as editor: @@ -2155,32 +2782,35 @@ class OperationTests(OperationTestBase): self.assertIndexNameNotExists(table_name, index_name) # Deconstruction. definition = operation.deconstruct() - self.assertEqual(definition[0], 'AddIndex') + self.assertEqual(definition[0], "AddIndex") self.assertEqual(definition[1], []) - self.assertEqual(definition[2], {'model_name': 'Pony', 'index': index}) + self.assertEqual(definition[2], {"model_name": "Pony", "index": index}) - @skipUnlessDBFeature('supports_expression_indexes') + @skipUnlessDBFeature("supports_expression_indexes") def test_remove_func_index(self): - app_label = 'test_rmfuncin' - index_name = f'{app_label}_pony_abs_idx' - table_name = f'{app_label}_pony' - project_state = self.set_up_test_model(app_label, indexes=[ - models.Index(Abs('weight'), name=index_name), - ]) + app_label = "test_rmfuncin" + index_name = f"{app_label}_pony_abs_idx" + table_name = f"{app_label}_pony" + project_state = self.set_up_test_model( + app_label, + indexes=[ + models.Index(Abs("weight"), name=index_name), + ], + ) self.assertTableExists(table_name) self.assertIndexNameExists(table_name, index_name) - operation = migrations.RemoveIndex('Pony', index_name) + operation = migrations.RemoveIndex("Pony", index_name) self.assertEqual( operation.describe(), - 'Remove index test_rmfuncin_pony_abs_idx from Pony', + "Remove index test_rmfuncin_pony_abs_idx from Pony", ) self.assertEqual( operation.migration_name_fragment, - 'remove_pony_test_rmfuncin_pony_abs_idx', + "remove_pony_test_rmfuncin_pony_abs_idx", ) new_state = project_state.clone() operation.state_forwards(app_label, new_state) - self.assertEqual(len(new_state.models[app_label, 'pony'].options['indexes']), 0) + self.assertEqual(len(new_state.models[app_label, "pony"].options["indexes"]), 0) # Remove index. with connection.schema_editor() as editor: operation.database_forwards(app_label, editor, project_state, new_state) @@ -2191,20 +2821,22 @@ class OperationTests(OperationTestBase): self.assertIndexNameExists(table_name, index_name) # Deconstruction. definition = operation.deconstruct() - self.assertEqual(definition[0], 'RemoveIndex') + self.assertEqual(definition[0], "RemoveIndex") self.assertEqual(definition[1], []) - self.assertEqual(definition[2], {'model_name': 'Pony', 'name': index_name}) + self.assertEqual(definition[2], {"model_name": "Pony", "name": index_name}) - @skipUnlessDBFeature('supports_expression_indexes') + @skipUnlessDBFeature("supports_expression_indexes") def test_alter_field_with_func_index(self): - app_label = 'test_alfuncin' - index_name = f'{app_label}_pony_idx' - table_name = f'{app_label}_pony' + app_label = "test_alfuncin" + index_name = f"{app_label}_pony_idx" + table_name = f"{app_label}_pony" project_state = self.set_up_test_model( app_label, - indexes=[models.Index(Abs('pink'), name=index_name)], + indexes=[models.Index(Abs("pink"), name=index_name)], + ) + operation = migrations.AlterField( + "Pony", "pink", models.IntegerField(null=True) ) - operation = migrations.AlterField('Pony', 'pink', models.IntegerField(null=True)) new_state = project_state.clone() operation.state_forwards(app_label, new_state) with connection.schema_editor() as editor: @@ -2220,7 +2852,9 @@ class OperationTests(OperationTestBase): Meta.indexes don't get dropped with sqlite3 remake. """ project_state = self.set_up_test_model("test_alflin", index=True) - operation = migrations.AlterField("Pony", "pink", models.IntegerField(null=True)) + operation = migrations.AlterField( + "Pony", "pink", models.IntegerField(null=True) + ) new_state = project_state.clone() operation.state_forwards("test_alflin", new_state) # Test the database alteration @@ -2231,7 +2865,9 @@ class OperationTests(OperationTestBase): self.assertIndexExists("test_alflin_pony", ["pink"]) # And test reversal with connection.schema_editor() as editor: - operation.database_backwards("test_alflin", editor, new_state, project_state) + operation.database_backwards( + "test_alflin", editor, new_state, project_state + ) # Ensure the index is still there self.assertIndexExists("test_alflin_pony", ["pink"]) @@ -2242,15 +2878,31 @@ class OperationTests(OperationTestBase): project_state = self.set_up_test_model("test_alinto") # Test the state alteration operation = migrations.AlterIndexTogether("Pony", [("pink", "weight")]) - self.assertEqual(operation.describe(), "Alter index_together for Pony (1 constraint(s))") + self.assertEqual( + operation.describe(), "Alter index_together for Pony (1 constraint(s))" + ) self.assertEqual( operation.migration_name_fragment, - 'alter_pony_index_together', + "alter_pony_index_together", ) new_state = project_state.clone() operation.state_forwards("test_alinto", new_state) - self.assertEqual(len(project_state.models["test_alinto", "pony"].options.get("index_together", set())), 0) - self.assertEqual(len(new_state.models["test_alinto", "pony"].options.get("index_together", set())), 1) + self.assertEqual( + len( + project_state.models["test_alinto", "pony"].options.get( + "index_together", set() + ) + ), + 0, + ) + self.assertEqual( + len( + new_state.models["test_alinto", "pony"].options.get( + "index_together", set() + ) + ), + 1, + ) # Make sure there's no matching index self.assertIndexNotExists("test_alinto_pony", ["pink", "weight"]) # Test the database alteration @@ -2259,263 +2911,332 @@ class OperationTests(OperationTestBase): self.assertIndexExists("test_alinto_pony", ["pink", "weight"]) # And test reversal with connection.schema_editor() as editor: - operation.database_backwards("test_alinto", editor, new_state, project_state) + operation.database_backwards( + "test_alinto", editor, new_state, project_state + ) self.assertIndexNotExists("test_alinto_pony", ["pink", "weight"]) # And deconstruction definition = operation.deconstruct() self.assertEqual(definition[0], "AlterIndexTogether") self.assertEqual(definition[1], []) - self.assertEqual(definition[2], {'name': "Pony", 'index_together': {("pink", "weight")}}) + self.assertEqual( + definition[2], {"name": "Pony", "index_together": {("pink", "weight")}} + ) def test_alter_index_together_remove(self): operation = migrations.AlterIndexTogether("Pony", None) - self.assertEqual(operation.describe(), "Alter index_together for Pony (0 constraint(s))") + self.assertEqual( + operation.describe(), "Alter index_together for Pony (0 constraint(s))" + ) - @skipUnlessDBFeature('allows_multiple_constraints_on_same_fields') + @skipUnlessDBFeature("allows_multiple_constraints_on_same_fields") def test_alter_index_together_remove_with_unique_together(self): - app_label = 'test_alintoremove_wunto' - table_name = '%s_pony' % app_label + app_label = "test_alintoremove_wunto" + table_name = "%s_pony" % app_label project_state = self.set_up_test_model(app_label, unique_together=True) - self.assertUniqueConstraintExists(table_name, ['pink', 'weight']) + self.assertUniqueConstraintExists(table_name, ["pink", "weight"]) # Add index together. new_state = project_state.clone() - operation = migrations.AlterIndexTogether('Pony', [('pink', 'weight')]) + operation = migrations.AlterIndexTogether("Pony", [("pink", "weight")]) operation.state_forwards(app_label, new_state) with connection.schema_editor() as editor: operation.database_forwards(app_label, editor, project_state, new_state) - self.assertIndexExists(table_name, ['pink', 'weight']) + self.assertIndexExists(table_name, ["pink", "weight"]) # Remove index together. project_state = new_state new_state = project_state.clone() - operation = migrations.AlterIndexTogether('Pony', set()) + operation = migrations.AlterIndexTogether("Pony", set()) operation.state_forwards(app_label, new_state) with connection.schema_editor() as editor: operation.database_forwards(app_label, editor, project_state, new_state) - self.assertIndexNotExists(table_name, ['pink', 'weight']) - self.assertUniqueConstraintExists(table_name, ['pink', 'weight']) + self.assertIndexNotExists(table_name, ["pink", "weight"]) + self.assertUniqueConstraintExists(table_name, ["pink", "weight"]) - @skipUnlessDBFeature('supports_table_check_constraints') + @skipUnlessDBFeature("supports_table_check_constraints") def test_add_constraint(self): project_state = self.set_up_test_model("test_addconstraint") gt_check = models.Q(pink__gt=2) - gt_constraint = models.CheckConstraint(check=gt_check, name="test_add_constraint_pony_pink_gt_2") + gt_constraint = models.CheckConstraint( + check=gt_check, name="test_add_constraint_pony_pink_gt_2" + ) gt_operation = migrations.AddConstraint("Pony", gt_constraint) self.assertEqual( - gt_operation.describe(), "Create constraint test_add_constraint_pony_pink_gt_2 on model Pony" + gt_operation.describe(), + "Create constraint test_add_constraint_pony_pink_gt_2 on model Pony", ) self.assertEqual( gt_operation.migration_name_fragment, - 'pony_test_add_constraint_pony_pink_gt_2', + "pony_test_add_constraint_pony_pink_gt_2", ) # Test the state alteration new_state = project_state.clone() gt_operation.state_forwards("test_addconstraint", new_state) - self.assertEqual(len(new_state.models["test_addconstraint", "pony"].options["constraints"]), 1) + self.assertEqual( + len(new_state.models["test_addconstraint", "pony"].options["constraints"]), + 1, + ) Pony = new_state.apps.get_model("test_addconstraint", "Pony") self.assertEqual(len(Pony._meta.constraints), 1) # Test the database alteration with connection.schema_editor() as editor: - gt_operation.database_forwards("test_addconstraint", editor, project_state, new_state) + gt_operation.database_forwards( + "test_addconstraint", editor, project_state, new_state + ) with self.assertRaises(IntegrityError), transaction.atomic(): Pony.objects.create(pink=1, weight=1.0) # Add another one. lt_check = models.Q(pink__lt=100) - lt_constraint = models.CheckConstraint(check=lt_check, name="test_add_constraint_pony_pink_lt_100") + lt_constraint = models.CheckConstraint( + check=lt_check, name="test_add_constraint_pony_pink_lt_100" + ) lt_operation = migrations.AddConstraint("Pony", lt_constraint) lt_operation.state_forwards("test_addconstraint", new_state) - self.assertEqual(len(new_state.models["test_addconstraint", "pony"].options["constraints"]), 2) + self.assertEqual( + len(new_state.models["test_addconstraint", "pony"].options["constraints"]), + 2, + ) Pony = new_state.apps.get_model("test_addconstraint", "Pony") self.assertEqual(len(Pony._meta.constraints), 2) with connection.schema_editor() as editor: - lt_operation.database_forwards("test_addconstraint", editor, project_state, new_state) + lt_operation.database_forwards( + "test_addconstraint", editor, project_state, new_state + ) with self.assertRaises(IntegrityError), transaction.atomic(): Pony.objects.create(pink=100, weight=1.0) # Test reversal with connection.schema_editor() as editor: - gt_operation.database_backwards("test_addconstraint", editor, new_state, project_state) + gt_operation.database_backwards( + "test_addconstraint", editor, new_state, project_state + ) Pony.objects.create(pink=1, weight=1.0) # Test deconstruction definition = gt_operation.deconstruct() self.assertEqual(definition[0], "AddConstraint") self.assertEqual(definition[1], []) - self.assertEqual(definition[2], {'model_name': "Pony", 'constraint': gt_constraint}) + self.assertEqual( + definition[2], {"model_name": "Pony", "constraint": gt_constraint} + ) - @skipUnlessDBFeature('supports_table_check_constraints') + @skipUnlessDBFeature("supports_table_check_constraints") def test_add_constraint_percent_escaping(self): - app_label = 'add_constraint_string_quoting' + app_label = "add_constraint_string_quoting" operations = [ migrations.CreateModel( - 'Author', + "Author", fields=[ - ('id', models.AutoField(primary_key=True)), - ('name', models.CharField(max_length=100)), - ('surname', models.CharField(max_length=100, default='')), - ('rebate', models.CharField(max_length=100)), + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=100)), + ("surname", models.CharField(max_length=100, default="")), + ("rebate", models.CharField(max_length=100)), ], ), ] from_state = self.apply_operations(app_label, ProjectState(), operations) # "%" generated in startswith lookup should be escaped in a way that is # considered a leading wildcard. - check = models.Q(name__startswith='Albert') - constraint = models.CheckConstraint(check=check, name='name_constraint') - operation = migrations.AddConstraint('Author', constraint) + check = models.Q(name__startswith="Albert") + constraint = models.CheckConstraint(check=check, name="name_constraint") + operation = migrations.AddConstraint("Author", constraint) to_state = from_state.clone() operation.state_forwards(app_label, to_state) with connection.schema_editor() as editor: operation.database_forwards(app_label, editor, from_state, to_state) - Author = to_state.apps.get_model(app_label, 'Author') + Author = to_state.apps.get_model(app_label, "Author") with self.assertRaises(IntegrityError), transaction.atomic(): - Author.objects.create(name='Artur') + Author.objects.create(name="Artur") # Literal "%" should be escaped in a way that is not a considered a # wildcard. - check = models.Q(rebate__endswith='%') - constraint = models.CheckConstraint(check=check, name='rebate_constraint') - operation = migrations.AddConstraint('Author', constraint) + check = models.Q(rebate__endswith="%") + constraint = models.CheckConstraint(check=check, name="rebate_constraint") + operation = migrations.AddConstraint("Author", constraint) from_state = to_state to_state = from_state.clone() operation.state_forwards(app_label, to_state) - Author = to_state.apps.get_model(app_label, 'Author') + Author = to_state.apps.get_model(app_label, "Author") with connection.schema_editor() as editor: operation.database_forwards(app_label, editor, from_state, to_state) - Author = to_state.apps.get_model(app_label, 'Author') + Author = to_state.apps.get_model(app_label, "Author") with self.assertRaises(IntegrityError), transaction.atomic(): - Author.objects.create(name='Albert', rebate='10$') - author = Author.objects.create(name='Albert', rebate='10%') + Author.objects.create(name="Albert", rebate="10$") + author = Author.objects.create(name="Albert", rebate="10%") self.assertEqual(Author.objects.get(), author) # Right-hand-side baked "%" literals should not be used for parameters # interpolation. - check = ~models.Q(surname__startswith=models.F('name')) - constraint = models.CheckConstraint(check=check, name='name_constraint_rhs') - operation = migrations.AddConstraint('Author', constraint) + check = ~models.Q(surname__startswith=models.F("name")) + constraint = models.CheckConstraint(check=check, name="name_constraint_rhs") + operation = migrations.AddConstraint("Author", constraint) from_state = to_state to_state = from_state.clone() operation.state_forwards(app_label, to_state) with connection.schema_editor() as editor: operation.database_forwards(app_label, editor, from_state, to_state) - Author = to_state.apps.get_model(app_label, 'Author') + Author = to_state.apps.get_model(app_label, "Author") with self.assertRaises(IntegrityError), transaction.atomic(): - Author.objects.create(name='Albert', surname='Alberto') + Author.objects.create(name="Albert", surname="Alberto") - @skipUnlessDBFeature('supports_table_check_constraints') + @skipUnlessDBFeature("supports_table_check_constraints") def test_add_or_constraint(self): - app_label = 'test_addorconstraint' - constraint_name = 'add_constraint_or' + app_label = "test_addorconstraint" + constraint_name = "add_constraint_or" from_state = self.set_up_test_model(app_label) check = models.Q(pink__gt=2, weight__gt=2) | models.Q(weight__lt=0) constraint = models.CheckConstraint(check=check, name=constraint_name) - operation = migrations.AddConstraint('Pony', constraint) + operation = migrations.AddConstraint("Pony", constraint) to_state = from_state.clone() operation.state_forwards(app_label, to_state) with connection.schema_editor() as editor: operation.database_forwards(app_label, editor, from_state, to_state) - Pony = to_state.apps.get_model(app_label, 'Pony') + Pony = to_state.apps.get_model(app_label, "Pony") with self.assertRaises(IntegrityError), transaction.atomic(): Pony.objects.create(pink=2, weight=3.0) with self.assertRaises(IntegrityError), transaction.atomic(): Pony.objects.create(pink=3, weight=1.0) - Pony.objects.bulk_create([ - Pony(pink=3, weight=-1.0), - Pony(pink=1, weight=-1.0), - Pony(pink=3, weight=3.0), - ]) + Pony.objects.bulk_create( + [ + Pony(pink=3, weight=-1.0), + Pony(pink=1, weight=-1.0), + Pony(pink=3, weight=3.0), + ] + ) - @skipUnlessDBFeature('supports_table_check_constraints') + @skipUnlessDBFeature("supports_table_check_constraints") def test_add_constraint_combinable(self): - app_label = 'test_addconstraint_combinable' + app_label = "test_addconstraint_combinable" operations = [ migrations.CreateModel( - 'Book', + "Book", fields=[ - ('id', models.AutoField(primary_key=True)), - ('read', models.PositiveIntegerField()), - ('unread', models.PositiveIntegerField()), + ("id", models.AutoField(primary_key=True)), + ("read", models.PositiveIntegerField()), + ("unread", models.PositiveIntegerField()), ], ), ] from_state = self.apply_operations(app_label, ProjectState(), operations) constraint = models.CheckConstraint( - check=models.Q(read=(100 - models.F('unread'))), - name='test_addconstraint_combinable_sum_100', + check=models.Q(read=(100 - models.F("unread"))), + name="test_addconstraint_combinable_sum_100", ) - operation = migrations.AddConstraint('Book', constraint) + operation = migrations.AddConstraint("Book", constraint) to_state = from_state.clone() operation.state_forwards(app_label, to_state) with connection.schema_editor() as editor: operation.database_forwards(app_label, editor, from_state, to_state) - Book = to_state.apps.get_model(app_label, 'Book') + Book = to_state.apps.get_model(app_label, "Book") with self.assertRaises(IntegrityError), transaction.atomic(): Book.objects.create(read=70, unread=10) Book.objects.create(read=70, unread=30) - @skipUnlessDBFeature('supports_table_check_constraints') + @skipUnlessDBFeature("supports_table_check_constraints") def test_remove_constraint(self): - project_state = self.set_up_test_model("test_removeconstraint", constraints=[ - models.CheckConstraint(check=models.Q(pink__gt=2), name="test_remove_constraint_pony_pink_gt_2"), - models.CheckConstraint(check=models.Q(pink__lt=100), name="test_remove_constraint_pony_pink_lt_100"), - ]) - gt_operation = migrations.RemoveConstraint("Pony", "test_remove_constraint_pony_pink_gt_2") + project_state = self.set_up_test_model( + "test_removeconstraint", + constraints=[ + models.CheckConstraint( + check=models.Q(pink__gt=2), + name="test_remove_constraint_pony_pink_gt_2", + ), + models.CheckConstraint( + check=models.Q(pink__lt=100), + name="test_remove_constraint_pony_pink_lt_100", + ), + ], + ) + gt_operation = migrations.RemoveConstraint( + "Pony", "test_remove_constraint_pony_pink_gt_2" + ) self.assertEqual( - gt_operation.describe(), "Remove constraint test_remove_constraint_pony_pink_gt_2 from model Pony" + gt_operation.describe(), + "Remove constraint test_remove_constraint_pony_pink_gt_2 from model Pony", ) self.assertEqual( gt_operation.migration_name_fragment, - 'remove_pony_test_remove_constraint_pony_pink_gt_2', + "remove_pony_test_remove_constraint_pony_pink_gt_2", ) # Test state alteration new_state = project_state.clone() gt_operation.state_forwards("test_removeconstraint", new_state) - self.assertEqual(len(new_state.models["test_removeconstraint", "pony"].options['constraints']), 1) + self.assertEqual( + len( + new_state.models["test_removeconstraint", "pony"].options["constraints"] + ), + 1, + ) Pony = new_state.apps.get_model("test_removeconstraint", "Pony") self.assertEqual(len(Pony._meta.constraints), 1) # Test database alteration with connection.schema_editor() as editor: - gt_operation.database_forwards("test_removeconstraint", editor, project_state, new_state) + gt_operation.database_forwards( + "test_removeconstraint", editor, project_state, new_state + ) Pony.objects.create(pink=1, weight=1.0).delete() with self.assertRaises(IntegrityError), transaction.atomic(): Pony.objects.create(pink=100, weight=1.0) # Remove the other one. - lt_operation = migrations.RemoveConstraint("Pony", "test_remove_constraint_pony_pink_lt_100") + lt_operation = migrations.RemoveConstraint( + "Pony", "test_remove_constraint_pony_pink_lt_100" + ) lt_operation.state_forwards("test_removeconstraint", new_state) - self.assertEqual(len(new_state.models["test_removeconstraint", "pony"].options['constraints']), 0) + self.assertEqual( + len( + new_state.models["test_removeconstraint", "pony"].options["constraints"] + ), + 0, + ) Pony = new_state.apps.get_model("test_removeconstraint", "Pony") self.assertEqual(len(Pony._meta.constraints), 0) with connection.schema_editor() as editor: - lt_operation.database_forwards("test_removeconstraint", editor, project_state, new_state) + lt_operation.database_forwards( + "test_removeconstraint", editor, project_state, new_state + ) Pony.objects.create(pink=100, weight=1.0).delete() # Test reversal with connection.schema_editor() as editor: - gt_operation.database_backwards("test_removeconstraint", editor, new_state, project_state) + gt_operation.database_backwards( + "test_removeconstraint", editor, new_state, project_state + ) with self.assertRaises(IntegrityError), transaction.atomic(): Pony.objects.create(pink=1, weight=1.0) # Test deconstruction definition = gt_operation.deconstruct() self.assertEqual(definition[0], "RemoveConstraint") self.assertEqual(definition[1], []) - self.assertEqual(definition[2], {'model_name': "Pony", 'name': "test_remove_constraint_pony_pink_gt_2"}) + self.assertEqual( + definition[2], + {"model_name": "Pony", "name": "test_remove_constraint_pony_pink_gt_2"}, + ) def test_add_partial_unique_constraint(self): - project_state = self.set_up_test_model('test_addpartialuniqueconstraint') + project_state = self.set_up_test_model("test_addpartialuniqueconstraint") partial_unique_constraint = models.UniqueConstraint( - fields=['pink'], + fields=["pink"], condition=models.Q(weight__gt=5), - name='test_constraint_pony_pink_for_weight_gt_5_uniq', + name="test_constraint_pony_pink_for_weight_gt_5_uniq", ) - operation = migrations.AddConstraint('Pony', partial_unique_constraint) + operation = migrations.AddConstraint("Pony", partial_unique_constraint) self.assertEqual( operation.describe(), - 'Create constraint test_constraint_pony_pink_for_weight_gt_5_uniq ' - 'on model Pony' + "Create constraint test_constraint_pony_pink_for_weight_gt_5_uniq " + "on model Pony", ) # Test the state alteration new_state = project_state.clone() - operation.state_forwards('test_addpartialuniqueconstraint', new_state) - self.assertEqual(len(new_state.models['test_addpartialuniqueconstraint', 'pony'].options['constraints']), 1) - Pony = new_state.apps.get_model('test_addpartialuniqueconstraint', 'Pony') + operation.state_forwards("test_addpartialuniqueconstraint", new_state) + self.assertEqual( + len( + new_state.models["test_addpartialuniqueconstraint", "pony"].options[ + "constraints" + ] + ), + 1, + ) + Pony = new_state.apps.get_model("test_addpartialuniqueconstraint", "Pony") self.assertEqual(len(Pony._meta.constraints), 1) # Test the database alteration with connection.schema_editor() as editor: - operation.database_forwards('test_addpartialuniqueconstraint', editor, project_state, new_state) + operation.database_forwards( + "test_addpartialuniqueconstraint", editor, project_state, new_state + ) # Test constraint works Pony.objects.create(pink=1, weight=4.0) Pony.objects.create(pink=1, weight=4.0) @@ -2527,36 +3248,56 @@ class OperationTests(OperationTestBase): Pony.objects.create(pink=1, weight=7.0) # Test reversal with connection.schema_editor() as editor: - operation.database_backwards('test_addpartialuniqueconstraint', editor, new_state, project_state) + operation.database_backwards( + "test_addpartialuniqueconstraint", editor, new_state, project_state + ) # Test constraint doesn't work Pony.objects.create(pink=1, weight=7.0) # Test deconstruction definition = operation.deconstruct() - self.assertEqual(definition[0], 'AddConstraint') + self.assertEqual(definition[0], "AddConstraint") self.assertEqual(definition[1], []) - self.assertEqual(definition[2], {'model_name': 'Pony', 'constraint': partial_unique_constraint}) + self.assertEqual( + definition[2], + {"model_name": "Pony", "constraint": partial_unique_constraint}, + ) def test_remove_partial_unique_constraint(self): - project_state = self.set_up_test_model('test_removepartialuniqueconstraint', constraints=[ - models.UniqueConstraint( - fields=['pink'], - condition=models.Q(weight__gt=5), - name='test_constraint_pony_pink_for_weight_gt_5_uniq', - ), - ]) - gt_operation = migrations.RemoveConstraint('Pony', 'test_constraint_pony_pink_for_weight_gt_5_uniq') + project_state = self.set_up_test_model( + "test_removepartialuniqueconstraint", + constraints=[ + models.UniqueConstraint( + fields=["pink"], + condition=models.Q(weight__gt=5), + name="test_constraint_pony_pink_for_weight_gt_5_uniq", + ), + ], + ) + gt_operation = migrations.RemoveConstraint( + "Pony", "test_constraint_pony_pink_for_weight_gt_5_uniq" + ) self.assertEqual( - gt_operation.describe(), 'Remove constraint test_constraint_pony_pink_for_weight_gt_5_uniq from model Pony' + gt_operation.describe(), + "Remove constraint test_constraint_pony_pink_for_weight_gt_5_uniq from model Pony", ) # Test state alteration new_state = project_state.clone() - gt_operation.state_forwards('test_removepartialuniqueconstraint', new_state) - self.assertEqual(len(new_state.models['test_removepartialuniqueconstraint', 'pony'].options['constraints']), 0) - Pony = new_state.apps.get_model('test_removepartialuniqueconstraint', 'Pony') + gt_operation.state_forwards("test_removepartialuniqueconstraint", new_state) + self.assertEqual( + len( + new_state.models["test_removepartialuniqueconstraint", "pony"].options[ + "constraints" + ] + ), + 0, + ) + Pony = new_state.apps.get_model("test_removepartialuniqueconstraint", "Pony") self.assertEqual(len(Pony._meta.constraints), 0) # Test database alteration with connection.schema_editor() as editor: - gt_operation.database_forwards('test_removepartialuniqueconstraint', editor, project_state, new_state) + gt_operation.database_forwards( + "test_removepartialuniqueconstraint", editor, project_state, new_state + ) # Test constraint doesn't work Pony.objects.create(pink=1, weight=4.0) Pony.objects.create(pink=1, weight=4.0) @@ -2564,7 +3305,9 @@ class OperationTests(OperationTestBase): Pony.objects.create(pink=1, weight=7.0).delete() # Test reversal with connection.schema_editor() as editor: - gt_operation.database_backwards('test_removepartialuniqueconstraint', editor, new_state, project_state) + gt_operation.database_backwards( + "test_removepartialuniqueconstraint", editor, new_state, project_state + ) # Test constraint works if connection.features.supports_partial_indexes: with self.assertRaises(IntegrityError), transaction.atomic(): @@ -2573,33 +3316,40 @@ class OperationTests(OperationTestBase): Pony.objects.create(pink=1, weight=7.0) # Test deconstruction definition = gt_operation.deconstruct() - self.assertEqual(definition[0], 'RemoveConstraint') + self.assertEqual(definition[0], "RemoveConstraint") self.assertEqual(definition[1], []) - self.assertEqual(definition[2], { - 'model_name': 'Pony', - 'name': 'test_constraint_pony_pink_for_weight_gt_5_uniq', - }) + self.assertEqual( + definition[2], + { + "model_name": "Pony", + "name": "test_constraint_pony_pink_for_weight_gt_5_uniq", + }, + ) def test_add_deferred_unique_constraint(self): - app_label = 'test_adddeferred_uc' + app_label = "test_adddeferred_uc" project_state = self.set_up_test_model(app_label) deferred_unique_constraint = models.UniqueConstraint( - fields=['pink'], - name='deferred_pink_constraint_add', + fields=["pink"], + name="deferred_pink_constraint_add", deferrable=models.Deferrable.DEFERRED, ) - operation = migrations.AddConstraint('Pony', deferred_unique_constraint) + operation = migrations.AddConstraint("Pony", deferred_unique_constraint) self.assertEqual( operation.describe(), - 'Create constraint deferred_pink_constraint_add on model Pony', + "Create constraint deferred_pink_constraint_add on model Pony", ) # Add constraint. new_state = project_state.clone() operation.state_forwards(app_label, new_state) - self.assertEqual(len(new_state.models[app_label, 'pony'].options['constraints']), 1) - Pony = new_state.apps.get_model(app_label, 'Pony') + self.assertEqual( + len(new_state.models[app_label, "pony"].options["constraints"]), 1 + ) + Pony = new_state.apps.get_model(app_label, "Pony") self.assertEqual(len(Pony._meta.constraints), 1) - with connection.schema_editor() as editor, CaptureQueriesContext(connection) as ctx: + with connection.schema_editor() as editor, CaptureQueriesContext( + connection + ) as ctx: operation.database_forwards(app_label, editor, project_state, new_state) Pony.objects.create(pink=1, weight=4.0) if connection.features.supports_deferrable_unique_constraints: @@ -2611,8 +3361,10 @@ class OperationTests(OperationTestBase): # Constraint behavior can be changed with SET CONSTRAINTS. with self.assertRaises(IntegrityError): with transaction.atomic(), connection.cursor() as cursor: - quoted_name = connection.ops.quote_name(deferred_unique_constraint.name) - cursor.execute('SET CONSTRAINTS %s IMMEDIATE' % quoted_name) + quoted_name = connection.ops.quote_name( + deferred_unique_constraint.name + ) + cursor.execute("SET CONSTRAINTS %s IMMEDIATE" % quoted_name) obj = Pony.objects.create(pink=1, weight=4.0) obj.pink = 3 obj.save() @@ -2626,33 +3378,39 @@ class OperationTests(OperationTestBase): Pony.objects.create(pink=1, weight=4.0) # Deconstruction. definition = operation.deconstruct() - self.assertEqual(definition[0], 'AddConstraint') + self.assertEqual(definition[0], "AddConstraint") self.assertEqual(definition[1], []) self.assertEqual( definition[2], - {'model_name': 'Pony', 'constraint': deferred_unique_constraint}, + {"model_name": "Pony", "constraint": deferred_unique_constraint}, ) def test_remove_deferred_unique_constraint(self): - app_label = 'test_removedeferred_uc' + app_label = "test_removedeferred_uc" deferred_unique_constraint = models.UniqueConstraint( - fields=['pink'], - name='deferred_pink_constraint_rm', + fields=["pink"], + name="deferred_pink_constraint_rm", deferrable=models.Deferrable.DEFERRED, ) - project_state = self.set_up_test_model(app_label, constraints=[deferred_unique_constraint]) - operation = migrations.RemoveConstraint('Pony', deferred_unique_constraint.name) + project_state = self.set_up_test_model( + app_label, constraints=[deferred_unique_constraint] + ) + operation = migrations.RemoveConstraint("Pony", deferred_unique_constraint.name) self.assertEqual( operation.describe(), - 'Remove constraint deferred_pink_constraint_rm from model Pony', + "Remove constraint deferred_pink_constraint_rm from model Pony", ) # Remove constraint. new_state = project_state.clone() operation.state_forwards(app_label, new_state) - self.assertEqual(len(new_state.models[app_label, 'pony'].options['constraints']), 0) - Pony = new_state.apps.get_model(app_label, 'Pony') + self.assertEqual( + len(new_state.models[app_label, "pony"].options["constraints"]), 0 + ) + Pony = new_state.apps.get_model(app_label, "Pony") self.assertEqual(len(Pony._meta.constraints), 0) - with connection.schema_editor() as editor, CaptureQueriesContext(connection) as ctx: + with connection.schema_editor() as editor, CaptureQueriesContext( + connection + ) as ctx: operation.database_forwards(app_label, editor, project_state, new_state) # Constraint doesn't work. Pony.objects.create(pink=1, weight=4.0) @@ -2671,8 +3429,10 @@ class OperationTests(OperationTestBase): # Constraint behavior can be changed with SET CONSTRAINTS. with self.assertRaises(IntegrityError): with transaction.atomic(), connection.cursor() as cursor: - quoted_name = connection.ops.quote_name(deferred_unique_constraint.name) - cursor.execute('SET CONSTRAINTS %s IMMEDIATE' % quoted_name) + quoted_name = connection.ops.quote_name( + deferred_unique_constraint.name + ) + cursor.execute("SET CONSTRAINTS %s IMMEDIATE" % quoted_name) obj = Pony.objects.create(pink=1, weight=4.0) obj.pink = 3 obj.save() @@ -2680,33 +3440,40 @@ class OperationTests(OperationTestBase): Pony.objects.create(pink=1, weight=4.0) # Deconstruction. definition = operation.deconstruct() - self.assertEqual(definition[0], 'RemoveConstraint') + self.assertEqual(definition[0], "RemoveConstraint") self.assertEqual(definition[1], []) - self.assertEqual(definition[2], { - 'model_name': 'Pony', - 'name': 'deferred_pink_constraint_rm', - }) + self.assertEqual( + definition[2], + { + "model_name": "Pony", + "name": "deferred_pink_constraint_rm", + }, + ) def test_add_covering_unique_constraint(self): - app_label = 'test_addcovering_uc' + app_label = "test_addcovering_uc" project_state = self.set_up_test_model(app_label) covering_unique_constraint = models.UniqueConstraint( - fields=['pink'], - name='covering_pink_constraint_add', - include=['weight'], + fields=["pink"], + name="covering_pink_constraint_add", + include=["weight"], ) - operation = migrations.AddConstraint('Pony', covering_unique_constraint) + operation = migrations.AddConstraint("Pony", covering_unique_constraint) self.assertEqual( operation.describe(), - 'Create constraint covering_pink_constraint_add on model Pony', + "Create constraint covering_pink_constraint_add on model Pony", ) # Add constraint. new_state = project_state.clone() operation.state_forwards(app_label, new_state) - self.assertEqual(len(new_state.models[app_label, 'pony'].options['constraints']), 1) - Pony = new_state.apps.get_model(app_label, 'Pony') + self.assertEqual( + len(new_state.models[app_label, "pony"].options["constraints"]), 1 + ) + Pony = new_state.apps.get_model(app_label, "Pony") self.assertEqual(len(Pony._meta.constraints), 1) - with connection.schema_editor() as editor, CaptureQueriesContext(connection) as ctx: + with connection.schema_editor() as editor, CaptureQueriesContext( + connection + ) as ctx: operation.database_forwards(app_label, editor, project_state, new_state) Pony.objects.create(pink=1, weight=4.0) if connection.features.supports_covering_indexes: @@ -2722,33 +3489,39 @@ class OperationTests(OperationTestBase): Pony.objects.create(pink=1, weight=4.0) # Deconstruction. definition = operation.deconstruct() - self.assertEqual(definition[0], 'AddConstraint') + self.assertEqual(definition[0], "AddConstraint") self.assertEqual(definition[1], []) self.assertEqual( definition[2], - {'model_name': 'Pony', 'constraint': covering_unique_constraint}, + {"model_name": "Pony", "constraint": covering_unique_constraint}, ) def test_remove_covering_unique_constraint(self): - app_label = 'test_removecovering_uc' + app_label = "test_removecovering_uc" covering_unique_constraint = models.UniqueConstraint( - fields=['pink'], - name='covering_pink_constraint_rm', - include=['weight'], + fields=["pink"], + name="covering_pink_constraint_rm", + include=["weight"], + ) + project_state = self.set_up_test_model( + app_label, constraints=[covering_unique_constraint] ) - project_state = self.set_up_test_model(app_label, constraints=[covering_unique_constraint]) - operation = migrations.RemoveConstraint('Pony', covering_unique_constraint.name) + operation = migrations.RemoveConstraint("Pony", covering_unique_constraint.name) self.assertEqual( operation.describe(), - 'Remove constraint covering_pink_constraint_rm from model Pony', + "Remove constraint covering_pink_constraint_rm from model Pony", ) # Remove constraint. new_state = project_state.clone() operation.state_forwards(app_label, new_state) - self.assertEqual(len(new_state.models[app_label, 'pony'].options['constraints']), 0) - Pony = new_state.apps.get_model(app_label, 'Pony') + self.assertEqual( + len(new_state.models[app_label, "pony"].options["constraints"]), 0 + ) + Pony = new_state.apps.get_model(app_label, "Pony") self.assertEqual(len(Pony._meta.constraints), 0) - with connection.schema_editor() as editor, CaptureQueriesContext(connection) as ctx: + with connection.schema_editor() as editor, CaptureQueriesContext( + connection + ) as ctx: operation.database_forwards(app_label, editor, project_state, new_state) # Constraint doesn't work. Pony.objects.create(pink=1, weight=4.0) @@ -2765,22 +3538,29 @@ class OperationTests(OperationTestBase): Pony.objects.create(pink=1, weight=4.0) # Deconstruction. definition = operation.deconstruct() - self.assertEqual(definition[0], 'RemoveConstraint') + self.assertEqual(definition[0], "RemoveConstraint") self.assertEqual(definition[1], []) - self.assertEqual(definition[2], { - 'model_name': 'Pony', - 'name': 'covering_pink_constraint_rm', - }) + self.assertEqual( + definition[2], + { + "model_name": "Pony", + "name": "covering_pink_constraint_rm", + }, + ) def test_alter_field_with_func_unique_constraint(self): - app_label = 'test_alfuncuc' - constraint_name = f'{app_label}_pony_uq' - table_name = f'{app_label}_pony' + app_label = "test_alfuncuc" + constraint_name = f"{app_label}_pony_uq" + table_name = f"{app_label}_pony" project_state = self.set_up_test_model( app_label, - constraints=[models.UniqueConstraint('pink', 'weight', name=constraint_name)] + constraints=[ + models.UniqueConstraint("pink", "weight", name=constraint_name) + ], + ) + operation = migrations.AlterField( + "Pony", "pink", models.IntegerField(null=True) ) - operation = migrations.AlterField('Pony', 'pink', models.IntegerField(null=True)) new_state = project_state.clone() operation.state_forwards(app_label, new_state) with connection.schema_editor() as editor: @@ -2793,28 +3573,30 @@ class OperationTests(OperationTestBase): self.assertIndexNameExists(table_name, constraint_name) def test_add_func_unique_constraint(self): - app_label = 'test_adfuncuc' - constraint_name = f'{app_label}_pony_abs_uq' - table_name = f'{app_label}_pony' + app_label = "test_adfuncuc" + constraint_name = f"{app_label}_pony_abs_uq" + table_name = f"{app_label}_pony" project_state = self.set_up_test_model(app_label) - constraint = models.UniqueConstraint(Abs('weight'), name=constraint_name) - operation = migrations.AddConstraint('Pony', constraint) + constraint = models.UniqueConstraint(Abs("weight"), name=constraint_name) + operation = migrations.AddConstraint("Pony", constraint) self.assertEqual( operation.describe(), - 'Create constraint test_adfuncuc_pony_abs_uq on model Pony', + "Create constraint test_adfuncuc_pony_abs_uq on model Pony", ) self.assertEqual( operation.migration_name_fragment, - 'pony_test_adfuncuc_pony_abs_uq', + "pony_test_adfuncuc_pony_abs_uq", ) new_state = project_state.clone() operation.state_forwards(app_label, new_state) - self.assertEqual(len(new_state.models[app_label, 'pony'].options['constraints']), 1) + self.assertEqual( + len(new_state.models[app_label, "pony"].options["constraints"]), 1 + ) self.assertIndexNameNotExists(table_name, constraint_name) # Add constraint. with connection.schema_editor() as editor: operation.database_forwards(app_label, editor, project_state, new_state) - Pony = new_state.apps.get_model(app_label, 'Pony') + Pony = new_state.apps.get_model(app_label, "Pony") Pony.objects.create(weight=4.0) if connection.features.supports_expression_indexes: self.assertIndexNameExists(table_name, constraint_name) @@ -2831,36 +3613,41 @@ class OperationTests(OperationTestBase): Pony.objects.create(weight=-4.0) # Deconstruction. definition = operation.deconstruct() - self.assertEqual(definition[0], 'AddConstraint') + self.assertEqual(definition[0], "AddConstraint") self.assertEqual(definition[1], []) self.assertEqual( definition[2], - {'model_name': 'Pony', 'constraint': constraint}, + {"model_name": "Pony", "constraint": constraint}, ) def test_remove_func_unique_constraint(self): - app_label = 'test_rmfuncuc' - constraint_name = f'{app_label}_pony_abs_uq' - table_name = f'{app_label}_pony' - project_state = self.set_up_test_model(app_label, constraints=[ - models.UniqueConstraint(Abs('weight'), name=constraint_name), - ]) + app_label = "test_rmfuncuc" + constraint_name = f"{app_label}_pony_abs_uq" + table_name = f"{app_label}_pony" + project_state = self.set_up_test_model( + app_label, + constraints=[ + models.UniqueConstraint(Abs("weight"), name=constraint_name), + ], + ) self.assertTableExists(table_name) if connection.features.supports_expression_indexes: self.assertIndexNameExists(table_name, constraint_name) - operation = migrations.RemoveConstraint('Pony', constraint_name) + operation = migrations.RemoveConstraint("Pony", constraint_name) self.assertEqual( operation.describe(), - 'Remove constraint test_rmfuncuc_pony_abs_uq from model Pony', + "Remove constraint test_rmfuncuc_pony_abs_uq from model Pony", ) self.assertEqual( operation.migration_name_fragment, - 'remove_pony_test_rmfuncuc_pony_abs_uq', + "remove_pony_test_rmfuncuc_pony_abs_uq", ) new_state = project_state.clone() operation.state_forwards(app_label, new_state) - self.assertEqual(len(new_state.models[app_label, 'pony'].options['constraints']), 0) - Pony = new_state.apps.get_model(app_label, 'Pony') + self.assertEqual( + len(new_state.models[app_label, "pony"].options["constraints"]), 0 + ) + Pony = new_state.apps.get_model(app_label, "Pony") self.assertEqual(len(Pony._meta.constraints), 0) # Remove constraint. with connection.schema_editor() as editor: @@ -2881,9 +3668,9 @@ class OperationTests(OperationTestBase): Pony.objects.create(weight=-4.0) # Deconstruction. definition = operation.deconstruct() - self.assertEqual(definition[0], 'RemoveConstraint') + self.assertEqual(definition[0], "RemoveConstraint") self.assertEqual(definition[1], []) - self.assertEqual(definition[2], {'model_name': 'Pony', 'name': constraint_name}) + self.assertEqual(definition[2], {"model_name": "Pony", "name": constraint_name}) def test_alter_model_options(self): """ @@ -2891,19 +3678,37 @@ class OperationTests(OperationTestBase): """ project_state = self.set_up_test_model("test_almoop") # Test the state alteration (no DB alteration to test) - operation = migrations.AlterModelOptions("Pony", {"permissions": [("can_groom", "Can groom")]}) + operation = migrations.AlterModelOptions( + "Pony", {"permissions": [("can_groom", "Can groom")]} + ) self.assertEqual(operation.describe(), "Change Meta options on Pony") - self.assertEqual(operation.migration_name_fragment, 'alter_pony_options') + self.assertEqual(operation.migration_name_fragment, "alter_pony_options") new_state = project_state.clone() operation.state_forwards("test_almoop", new_state) - self.assertEqual(len(project_state.models["test_almoop", "pony"].options.get("permissions", [])), 0) - self.assertEqual(len(new_state.models["test_almoop", "pony"].options.get("permissions", [])), 1) - self.assertEqual(new_state.models["test_almoop", "pony"].options["permissions"][0][0], "can_groom") + self.assertEqual( + len( + project_state.models["test_almoop", "pony"].options.get( + "permissions", [] + ) + ), + 0, + ) + self.assertEqual( + len(new_state.models["test_almoop", "pony"].options.get("permissions", [])), + 1, + ) + self.assertEqual( + new_state.models["test_almoop", "pony"].options["permissions"][0][0], + "can_groom", + ) # And deconstruction definition = operation.deconstruct() self.assertEqual(definition[0], "AlterModelOptions") self.assertEqual(definition[1], []) - self.assertEqual(definition[2], {'name': "Pony", 'options': {"permissions": [("can_groom", "Can groom")]}}) + self.assertEqual( + definition[2], + {"name": "Pony", "options": {"permissions": [("can_groom", "Can groom")]}}, + ) def test_alter_model_options_emptying(self): """ @@ -2915,13 +3720,23 @@ class OperationTests(OperationTestBase): self.assertEqual(operation.describe(), "Change Meta options on Pony") new_state = project_state.clone() operation.state_forwards("test_almoop", new_state) - self.assertEqual(len(project_state.models["test_almoop", "pony"].options.get("permissions", [])), 1) - self.assertEqual(len(new_state.models["test_almoop", "pony"].options.get("permissions", [])), 0) + self.assertEqual( + len( + project_state.models["test_almoop", "pony"].options.get( + "permissions", [] + ) + ), + 1, + ) + self.assertEqual( + len(new_state.models["test_almoop", "pony"].options.get("permissions", [])), + 0, + ) # And deconstruction definition = operation.deconstruct() self.assertEqual(definition[0], "AlterModelOptions") self.assertEqual(definition[1], []) - self.assertEqual(definition[2], {'name': "Pony", 'options': {}}) + self.assertEqual(definition[2], {"name": "Pony", "options": {}}) def test_alter_order_with_respect_to(self): """ @@ -2930,48 +3745,68 @@ class OperationTests(OperationTestBase): project_state = self.set_up_test_model("test_alorwrtto", related_model=True) # Test the state alteration operation = migrations.AlterOrderWithRespectTo("Rider", "pony") - self.assertEqual(operation.describe(), "Set order_with_respect_to on Rider to pony") + self.assertEqual( + operation.describe(), "Set order_with_respect_to on Rider to pony" + ) self.assertEqual( operation.migration_name_fragment, - 'alter_rider_order_with_respect_to', + "alter_rider_order_with_respect_to", ) new_state = project_state.clone() operation.state_forwards("test_alorwrtto", new_state) self.assertIsNone( - project_state.models["test_alorwrtto", "rider"].options.get("order_with_respect_to", None) + project_state.models["test_alorwrtto", "rider"].options.get( + "order_with_respect_to", None + ) ) self.assertEqual( - new_state.models["test_alorwrtto", "rider"].options.get("order_with_respect_to", None), - "pony" + new_state.models["test_alorwrtto", "rider"].options.get( + "order_with_respect_to", None + ), + "pony", ) # Make sure there's no matching index self.assertColumnNotExists("test_alorwrtto_rider", "_order") # Create some rows before alteration rendered_state = project_state.apps - pony = rendered_state.get_model("test_alorwrtto", "Pony").objects.create(weight=50) - rider1 = rendered_state.get_model("test_alorwrtto", "Rider").objects.create(pony=pony) + pony = rendered_state.get_model("test_alorwrtto", "Pony").objects.create( + weight=50 + ) + rider1 = rendered_state.get_model("test_alorwrtto", "Rider").objects.create( + pony=pony + ) rider1.friend = rider1 rider1.save() - rider2 = rendered_state.get_model("test_alorwrtto", "Rider").objects.create(pony=pony) + rider2 = rendered_state.get_model("test_alorwrtto", "Rider").objects.create( + pony=pony + ) rider2.friend = rider2 rider2.save() # Test the database alteration with connection.schema_editor() as editor: - operation.database_forwards("test_alorwrtto", editor, project_state, new_state) + operation.database_forwards( + "test_alorwrtto", editor, project_state, new_state + ) self.assertColumnExists("test_alorwrtto_rider", "_order") # Check for correct value in rows - updated_riders = new_state.apps.get_model("test_alorwrtto", "Rider").objects.all() + updated_riders = new_state.apps.get_model( + "test_alorwrtto", "Rider" + ).objects.all() self.assertEqual(updated_riders[0]._order, 0) self.assertEqual(updated_riders[1]._order, 0) # And test reversal with connection.schema_editor() as editor: - operation.database_backwards("test_alorwrtto", editor, new_state, project_state) + operation.database_backwards( + "test_alorwrtto", editor, new_state, project_state + ) self.assertColumnNotExists("test_alorwrtto_rider", "_order") # And deconstruction definition = operation.deconstruct() self.assertEqual(definition[0], "AlterOrderWithRespectTo") self.assertEqual(definition[1], []) - self.assertEqual(definition[2], {'name': "Rider", 'order_with_respect_to': "pony"}) + self.assertEqual( + definition[2], {"name": "Rider", "order_with_respect_to": "pony"} + ) def test_alter_model_managers(self): """ @@ -2985,10 +3820,10 @@ class OperationTests(OperationTestBase): ("food_qs", FoodQuerySet.as_manager()), ("food_mgr", FoodManager("a", "b")), ("food_mgr_kwargs", FoodManager("x", "y", 3, 4)), - ] + ], ) self.assertEqual(operation.describe(), "Change managers on Pony") - self.assertEqual(operation.migration_name_fragment, 'alter_pony_managers') + self.assertEqual(operation.migration_name_fragment, "alter_pony_managers") managers = project_state.models["test_almoma", "pony"].managers self.assertEqual(managers, []) @@ -3005,7 +3840,7 @@ class OperationTests(OperationTestBase): self.assertIsInstance(managers[2][1], FoodManager) self.assertEqual(managers[2][1].args, ("x", "y", 3, 4)) rendered_state = new_state.apps - model = rendered_state.get_model('test_almoma', 'pony') + model = rendered_state.get_model("test_almoma", "pony") self.assertIsInstance(model.food_qs, models.Manager) self.assertIsInstance(model.food_mgr, FoodManager) self.assertIsInstance(model.food_mgr_kwargs, FoodManager) @@ -3051,15 +3886,19 @@ class OperationTests(OperationTestBase): create_state = project_state.clone() create_operation.state_forwards("test_alfk", create_state) alter_operation = migrations.AlterField( - model_name='Rider', - name='pony', + model_name="Rider", + name="pony", field=models.ForeignKey("Pony", models.CASCADE, editable=False), ) alter_state = create_state.clone() alter_operation.state_forwards("test_alfk", alter_state) with connection.schema_editor() as editor: - create_operation.database_forwards("test_alfk", editor, project_state, create_state) - alter_operation.database_forwards("test_alfk", editor, create_state, alter_state) + create_operation.database_forwards( + "test_alfk", editor, project_state, create_state + ) + alter_operation.database_forwards( + "test_alfk", editor, create_state, alter_state + ) def test_alter_fk_non_fk(self): """ @@ -3071,7 +3910,9 @@ class OperationTests(OperationTestBase): name="pony", field=models.FloatField(), ) - project_state, new_state = self.make_test_state("test_afknfk", operation, related_model=True) + project_state, new_state = self.make_test_state( + "test_afknfk", operation, related_model=True + ) # Test the database alteration self.assertColumnExists("test_afknfk_rider", "pony_id") self.assertColumnNotExists("test_afknfk_rider", "pony") @@ -3081,7 +3922,9 @@ class OperationTests(OperationTestBase): self.assertColumnNotExists("test_afknfk_rider", "pony_id") # And test reversal with connection.schema_editor() as editor: - operation.database_backwards("test_afknfk", editor, new_state, project_state) + operation.database_backwards( + "test_afknfk", editor, new_state, project_state + ) self.assertColumnExists("test_afknfk_rider", "pony_id") self.assertColumnNotExists("test_afknfk_rider", "pony") @@ -3098,27 +3941,33 @@ class OperationTests(OperationTestBase): "INSERT INTO i_love_ponies (id, special_thing) VALUES (2, 'i love django');\n" "UPDATE i_love_ponies SET special_thing = 'Ponies' WHERE special_thing LIKE '%%ponies';" "UPDATE i_love_ponies SET special_thing = 'Django' WHERE special_thing LIKE '%django';", - # Run delete queries to test for parameter substitution failure # reported in #23426 "DELETE FROM i_love_ponies WHERE special_thing LIKE '%Django%';" "DELETE FROM i_love_ponies WHERE special_thing LIKE '%%Ponies%%';" "DROP TABLE i_love_ponies", - - state_operations=[migrations.CreateModel("SomethingElse", [("id", models.AutoField(primary_key=True))])], + state_operations=[ + migrations.CreateModel( + "SomethingElse", [("id", models.AutoField(primary_key=True))] + ) + ], ) self.assertEqual(operation.describe(), "Raw SQL operation") # Test the state alteration new_state = project_state.clone() operation.state_forwards("test_runsql", new_state) - self.assertEqual(len(new_state.models["test_runsql", "somethingelse"].fields), 1) + self.assertEqual( + len(new_state.models["test_runsql", "somethingelse"].fields), 1 + ) # Make sure there's no table self.assertTableNotExists("i_love_ponies") # Test SQL collection with connection.schema_editor(collect_sql=True) as editor: operation.database_forwards("test_runsql", editor, project_state, new_state) self.assertIn("LIKE '%%ponies';", "\n".join(editor.collected_sql)) - operation.database_backwards("test_runsql", editor, project_state, new_state) + operation.database_backwards( + "test_runsql", editor, project_state, new_state + ) self.assertIn("LIKE '%%Ponies%%';", "\n".join(editor.collected_sql)) # Test the database alteration with connection.schema_editor() as editor: @@ -3128,23 +3977,31 @@ class OperationTests(OperationTestBase): with connection.cursor() as cursor: cursor.execute("SELECT COUNT(*) FROM i_love_ponies") self.assertEqual(cursor.fetchall()[0][0], 2) - cursor.execute("SELECT COUNT(*) FROM i_love_ponies WHERE special_thing = 'Django'") + cursor.execute( + "SELECT COUNT(*) FROM i_love_ponies WHERE special_thing = 'Django'" + ) self.assertEqual(cursor.fetchall()[0][0], 1) - cursor.execute("SELECT COUNT(*) FROM i_love_ponies WHERE special_thing = 'Ponies'") + cursor.execute( + "SELECT COUNT(*) FROM i_love_ponies WHERE special_thing = 'Ponies'" + ) self.assertEqual(cursor.fetchall()[0][0], 1) # And test reversal self.assertTrue(operation.reversible) with connection.schema_editor() as editor: - operation.database_backwards("test_runsql", editor, new_state, project_state) + operation.database_backwards( + "test_runsql", editor, new_state, project_state + ) self.assertTableNotExists("i_love_ponies") # And deconstruction definition = operation.deconstruct() self.assertEqual(definition[0], "RunSQL") self.assertEqual(definition[1], []) - self.assertEqual(sorted(definition[2]), ["reverse_sql", "sql", "state_operations"]) + self.assertEqual( + sorted(definition[2]), ["reverse_sql", "sql", "state_operations"] + ) # And elidable reduction self.assertIs(False, operation.reduce(operation, [])) - elidable_operation = migrations.RunSQL('SELECT 1 FROM void;', elidable=True) + elidable_operation = migrations.RunSQL("SELECT 1 FROM void;", elidable=True) self.assertEqual(elidable_operation.reduce(operation, []), [operation]) def test_run_sql_params(self): @@ -3161,15 +4018,27 @@ class OperationTests(OperationTestBase): # forwards ( "INSERT INTO i_love_ponies (id, special_thing) VALUES (1, 'Django');", - ["INSERT INTO i_love_ponies (id, special_thing) VALUES (2, %s);", ['Ponies']], - ("INSERT INTO i_love_ponies (id, special_thing) VALUES (%s, %s);", (3, 'Python',)), + [ + "INSERT INTO i_love_ponies (id, special_thing) VALUES (2, %s);", + ["Ponies"], + ], + ( + "INSERT INTO i_love_ponies (id, special_thing) VALUES (%s, %s);", + ( + 3, + "Python", + ), + ), ), # backwards [ "DELETE FROM i_love_ponies WHERE special_thing = 'Django';", ["DELETE FROM i_love_ponies WHERE special_thing = 'Ponies';", None], - ("DELETE FROM i_love_ponies WHERE id = %s OR special_thing = %s;", [3, 'Python']), - ] + ( + "DELETE FROM i_love_ponies WHERE id = %s OR special_thing = %s;", + [3, "Python"], + ), + ], ) # Make sure there's no table @@ -3181,21 +4050,27 @@ class OperationTests(OperationTestBase): # Test parameter passing with connection.schema_editor() as editor: - param_operation.database_forwards("test_runsql", editor, project_state, new_state) + param_operation.database_forwards( + "test_runsql", editor, project_state, new_state + ) # Make sure all the SQL was processed with connection.cursor() as cursor: cursor.execute("SELECT COUNT(*) FROM i_love_ponies") self.assertEqual(cursor.fetchall()[0][0], 3) with connection.schema_editor() as editor: - param_operation.database_backwards("test_runsql", editor, new_state, project_state) + param_operation.database_backwards( + "test_runsql", editor, new_state, project_state + ) with connection.cursor() as cursor: cursor.execute("SELECT COUNT(*) FROM i_love_ponies") self.assertEqual(cursor.fetchall()[0][0], 0) # And test reversal with connection.schema_editor() as editor: - operation.database_backwards("test_runsql", editor, new_state, project_state) + operation.database_backwards( + "test_runsql", editor, new_state, project_state + ) self.assertTableNotExists("i_love_ponies") def test_run_sql_params_invalid(self): @@ -3207,22 +4082,22 @@ class OperationTests(OperationTestBase): new_state = project_state.clone() operation = migrations.RunSQL( # forwards - [ - ["INSERT INTO foo (bar) VALUES ('buz');"] - ], + [["INSERT INTO foo (bar) VALUES ('buz');"]], # backwards - ( - ("DELETE FROM foo WHERE bar = 'buz';", 'invalid', 'parameter count'), - ), + (("DELETE FROM foo WHERE bar = 'buz';", "invalid", "parameter count"),), ) with connection.schema_editor() as editor: with self.assertRaisesMessage(ValueError, "Expected a 2-tuple but got 1"): - operation.database_forwards("test_runsql", editor, project_state, new_state) + operation.database_forwards( + "test_runsql", editor, project_state, new_state + ) with connection.schema_editor() as editor: with self.assertRaisesMessage(ValueError, "Expected a 2-tuple but got 3"): - operation.database_backwards("test_runsql", editor, new_state, project_state) + operation.database_backwards( + "test_runsql", editor, new_state, project_state + ) def test_run_sql_noop(self): """ @@ -3234,19 +4109,21 @@ class OperationTests(OperationTestBase): operation.database_backwards("test_runsql", editor, None, None) def test_run_sql_add_missing_semicolon_on_collect_sql(self): - project_state = self.set_up_test_model('test_runsql') + project_state = self.set_up_test_model("test_runsql") new_state = project_state.clone() tests = [ - 'INSERT INTO test_runsql_pony (pink, weight) VALUES (1, 1);\n', - 'INSERT INTO test_runsql_pony (pink, weight) VALUES (1, 1)\n', + "INSERT INTO test_runsql_pony (pink, weight) VALUES (1, 1);\n", + "INSERT INTO test_runsql_pony (pink, weight) VALUES (1, 1)\n", ] for sql in tests: with self.subTest(sql=sql): operation = migrations.RunSQL(sql, migrations.RunPython.noop) with connection.schema_editor(collect_sql=True) as editor: - operation.database_forwards('test_runsql', editor, project_state, new_state) - collected_sql = '\n'.join(editor.collected_sql) - self.assertEqual(collected_sql.count(';'), 1) + operation.database_forwards( + "test_runsql", editor, project_state, new_state + ) + collected_sql = "\n".join(editor.collected_sql) + self.assertEqual(collected_sql.count(";"), 1) def test_run_python(self): """ @@ -3265,24 +4142,39 @@ class OperationTests(OperationTestBase): Pony = models.get_model("test_runpython", "Pony") Pony.objects.filter(pink=1, weight=3.55).delete() Pony.objects.filter(weight=5).delete() - operation = migrations.RunPython(inner_method, reverse_code=inner_method_reverse) + + operation = migrations.RunPython( + inner_method, reverse_code=inner_method_reverse + ) self.assertEqual(operation.describe(), "Raw Python operation") # Test the state alteration does nothing new_state = project_state.clone() operation.state_forwards("test_runpython", new_state) self.assertEqual(new_state, project_state) # Test the database alteration - self.assertEqual(project_state.apps.get_model("test_runpython", "Pony").objects.count(), 0) + self.assertEqual( + project_state.apps.get_model("test_runpython", "Pony").objects.count(), 0 + ) with connection.schema_editor() as editor: - operation.database_forwards("test_runpython", editor, project_state, new_state) - self.assertEqual(project_state.apps.get_model("test_runpython", "Pony").objects.count(), 2) + operation.database_forwards( + "test_runpython", editor, project_state, new_state + ) + self.assertEqual( + project_state.apps.get_model("test_runpython", "Pony").objects.count(), 2 + ) # Now test reversal self.assertTrue(operation.reversible) with connection.schema_editor() as editor: - operation.database_backwards("test_runpython", editor, project_state, new_state) - self.assertEqual(project_state.apps.get_model("test_runpython", "Pony").objects.count(), 0) + operation.database_backwards( + "test_runpython", editor, project_state, new_state + ) + self.assertEqual( + project_state.apps.get_model("test_runpython", "Pony").objects.count(), 0 + ) # Now test we can't use a string - with self.assertRaisesMessage(ValueError, 'RunPython must be supplied with a callable'): + with self.assertRaisesMessage( + ValueError, "RunPython must be supplied with a callable" + ): migrations.RunPython("print 'ahahaha'") # And deconstruction definition = operation.deconstruct() @@ -3294,10 +4186,16 @@ class OperationTests(OperationTestBase): no_reverse_operation = migrations.RunPython(inner_method) self.assertFalse(no_reverse_operation.reversible) with connection.schema_editor() as editor: - no_reverse_operation.database_forwards("test_runpython", editor, project_state, new_state) + no_reverse_operation.database_forwards( + "test_runpython", editor, project_state, new_state + ) with self.assertRaises(NotImplementedError): - no_reverse_operation.database_backwards("test_runpython", editor, new_state, project_state) - self.assertEqual(project_state.apps.get_model("test_runpython", "Pony").objects.count(), 2) + no_reverse_operation.database_backwards( + "test_runpython", editor, new_state, project_state + ) + self.assertEqual( + project_state.apps.get_model("test_runpython", "Pony").objects.count(), 2 + ) def create_ponies(models, schema_editor): Pony = models.get_model("test_runpython", "Pony") @@ -3309,8 +4207,12 @@ class OperationTests(OperationTestBase): operation = migrations.RunPython(create_ponies) with connection.schema_editor() as editor: - operation.database_forwards("test_runpython", editor, project_state, new_state) - self.assertEqual(project_state.apps.get_model("test_runpython", "Pony").objects.count(), 4) + operation.database_forwards( + "test_runpython", editor, project_state, new_state + ) + self.assertEqual( + project_state.apps.get_model("test_runpython", "Pony").objects.count(), 4 + ) # And deconstruction definition = operation.deconstruct() self.assertEqual(definition[0], "RunPython") @@ -3327,9 +4229,18 @@ class OperationTests(OperationTestBase): operation = migrations.RunPython(create_shetlandponies) with connection.schema_editor() as editor: - operation.database_forwards("test_runpython", editor, project_state, new_state) - self.assertEqual(project_state.apps.get_model("test_runpython", "Pony").objects.count(), 6) - self.assertEqual(project_state.apps.get_model("test_runpython", "ShetlandPony").objects.count(), 2) + operation.database_forwards( + "test_runpython", editor, project_state, new_state + ) + self.assertEqual( + project_state.apps.get_model("test_runpython", "Pony").objects.count(), 6 + ) + self.assertEqual( + project_state.apps.get_model( + "test_runpython", "ShetlandPony" + ).objects.count(), + 2, + ) # And elidable reduction self.assertIs(False, operation.reduce(operation, [])) elidable_operation = migrations.RunPython(inner_method, elidable=True) @@ -3348,55 +4259,121 @@ class OperationTests(OperationTestBase): # Verify atomicity when applying. atomic_migration = Migration("test", "test_runpythonatomic") - atomic_migration.operations = [migrations.RunPython(inner_method, reverse_code=inner_method)] + atomic_migration.operations = [ + migrations.RunPython(inner_method, reverse_code=inner_method) + ] non_atomic_migration = Migration("test", "test_runpythonatomic") - non_atomic_migration.operations = [migrations.RunPython(inner_method, reverse_code=inner_method, atomic=False)] + non_atomic_migration.operations = [ + migrations.RunPython(inner_method, reverse_code=inner_method, atomic=False) + ] # If we're a fully-transactional database, both versions should rollback if connection.features.can_rollback_ddl: - self.assertEqual(project_state.apps.get_model("test_runpythonatomic", "Pony").objects.count(), 0) + self.assertEqual( + project_state.apps.get_model( + "test_runpythonatomic", "Pony" + ).objects.count(), + 0, + ) with self.assertRaises(ValueError): with connection.schema_editor() as editor: atomic_migration.apply(project_state, editor) - self.assertEqual(project_state.apps.get_model("test_runpythonatomic", "Pony").objects.count(), 0) + self.assertEqual( + project_state.apps.get_model( + "test_runpythonatomic", "Pony" + ).objects.count(), + 0, + ) with self.assertRaises(ValueError): with connection.schema_editor() as editor: non_atomic_migration.apply(project_state, editor) - self.assertEqual(project_state.apps.get_model("test_runpythonatomic", "Pony").objects.count(), 0) + self.assertEqual( + project_state.apps.get_model( + "test_runpythonatomic", "Pony" + ).objects.count(), + 0, + ) # Otherwise, the non-atomic operation should leave a row there else: - self.assertEqual(project_state.apps.get_model("test_runpythonatomic", "Pony").objects.count(), 0) + self.assertEqual( + project_state.apps.get_model( + "test_runpythonatomic", "Pony" + ).objects.count(), + 0, + ) with self.assertRaises(ValueError): with connection.schema_editor() as editor: atomic_migration.apply(project_state, editor) - self.assertEqual(project_state.apps.get_model("test_runpythonatomic", "Pony").objects.count(), 0) + self.assertEqual( + project_state.apps.get_model( + "test_runpythonatomic", "Pony" + ).objects.count(), + 0, + ) with self.assertRaises(ValueError): with connection.schema_editor() as editor: non_atomic_migration.apply(project_state, editor) - self.assertEqual(project_state.apps.get_model("test_runpythonatomic", "Pony").objects.count(), 1) + self.assertEqual( + project_state.apps.get_model( + "test_runpythonatomic", "Pony" + ).objects.count(), + 1, + ) # Reset object count to zero and verify atomicity when unapplying. - project_state.apps.get_model("test_runpythonatomic", "Pony").objects.all().delete() + project_state.apps.get_model( + "test_runpythonatomic", "Pony" + ).objects.all().delete() # On a fully-transactional database, both versions rollback. if connection.features.can_rollback_ddl: - self.assertEqual(project_state.apps.get_model("test_runpythonatomic", "Pony").objects.count(), 0) + self.assertEqual( + project_state.apps.get_model( + "test_runpythonatomic", "Pony" + ).objects.count(), + 0, + ) with self.assertRaises(ValueError): with connection.schema_editor() as editor: atomic_migration.unapply(project_state, editor) - self.assertEqual(project_state.apps.get_model("test_runpythonatomic", "Pony").objects.count(), 0) + self.assertEqual( + project_state.apps.get_model( + "test_runpythonatomic", "Pony" + ).objects.count(), + 0, + ) with self.assertRaises(ValueError): with connection.schema_editor() as editor: non_atomic_migration.unapply(project_state, editor) - self.assertEqual(project_state.apps.get_model("test_runpythonatomic", "Pony").objects.count(), 0) + self.assertEqual( + project_state.apps.get_model( + "test_runpythonatomic", "Pony" + ).objects.count(), + 0, + ) # Otherwise, the non-atomic operation leaves a row there. else: - self.assertEqual(project_state.apps.get_model("test_runpythonatomic", "Pony").objects.count(), 0) + self.assertEqual( + project_state.apps.get_model( + "test_runpythonatomic", "Pony" + ).objects.count(), + 0, + ) with self.assertRaises(ValueError): with connection.schema_editor() as editor: atomic_migration.unapply(project_state, editor) - self.assertEqual(project_state.apps.get_model("test_runpythonatomic", "Pony").objects.count(), 0) + self.assertEqual( + project_state.apps.get_model( + "test_runpythonatomic", "Pony" + ).objects.count(), + 0, + ) with self.assertRaises(ValueError): with connection.schema_editor() as editor: non_atomic_migration.unapply(project_state, editor) - self.assertEqual(project_state.apps.get_model("test_runpythonatomic", "Pony").objects.count(), 1) + self.assertEqual( + project_state.apps.get_model( + "test_runpythonatomic", "Pony" + ).objects.count(), + 1, + ) # Verify deconstruction. definition = non_atomic_migration.operations[0].deconstruct() self.assertEqual(definition[0], "RunPython") @@ -3428,7 +4405,7 @@ class OperationTests(OperationTestBase): [ ("id", models.AutoField(primary_key=True)), ("title", models.CharField(max_length=100)), - ("author", models.ForeignKey("test_authors.Author", models.CASCADE)) + ("author", models.ForeignKey("test_authors.Author", models.CASCADE)), ], options={}, ) @@ -3443,35 +4420,44 @@ class OperationTests(OperationTestBase): new_state = project_state.clone() with connection.schema_editor() as editor: create_author.state_forwards("test_authors", new_state) - create_author.database_forwards("test_authors", editor, project_state, new_state) + create_author.database_forwards( + "test_authors", editor, project_state, new_state + ) project_state = new_state new_state = new_state.clone() with connection.schema_editor() as editor: create_book.state_forwards("test_books", new_state) - create_book.database_forwards("test_books", editor, project_state, new_state) + create_book.database_forwards( + "test_books", editor, project_state, new_state + ) project_state = new_state new_state = new_state.clone() with connection.schema_editor() as editor: add_hometown.state_forwards("test_authors", new_state) - add_hometown.database_forwards("test_authors", editor, project_state, new_state) + add_hometown.database_forwards( + "test_authors", editor, project_state, new_state + ) project_state = new_state new_state = new_state.clone() with connection.schema_editor() as editor: create_old_man.state_forwards("test_books", new_state) - create_old_man.database_forwards("test_books", editor, project_state, new_state) + create_old_man.database_forwards( + "test_books", editor, project_state, new_state + ) def test_model_with_bigautofield(self): """ A model with BigAutoField can be created. """ + def create_data(models, schema_editor): Author = models.get_model("test_author", "Author") Book = models.get_model("test_book", "Book") author1 = Author.objects.create(name="Hemingway") Book.objects.create(title="Old Man and The Sea", author=author1) - Book.objects.create(id=2 ** 33, title="A farewell to arms", author=author1) + Book.objects.create(id=2**33, title="A farewell to arms", author=author1) - author2 = Author.objects.create(id=2 ** 33, name="Remarque") + author2 = Author.objects.create(id=2**33, name="Remarque") Book.objects.create(title="All quiet on the western front", author=author2) Book.objects.create(title="Arc de Triomphe", author=author2) @@ -3488,7 +4474,12 @@ class OperationTests(OperationTestBase): [ ("id", models.BigAutoField(primary_key=True)), ("title", models.CharField(max_length=100)), - ("author", models.ForeignKey(to="test_author.Author", on_delete=models.CASCADE)) + ( + "author", + models.ForeignKey( + to="test_author.Author", on_delete=models.CASCADE + ), + ), ], options={}, ) @@ -3498,7 +4489,9 @@ class OperationTests(OperationTestBase): new_state = project_state.clone() with connection.schema_editor() as editor: create_author.state_forwards("test_author", new_state) - create_author.database_forwards("test_author", editor, project_state, new_state) + create_author.database_forwards( + "test_author", editor, project_state, new_state + ) project_state = new_state new_state = new_state.clone() @@ -3512,7 +4505,9 @@ class OperationTests(OperationTestBase): fill_data.state_forwards("fill_data", new_state) fill_data.database_forwards("fill_data", editor, project_state, new_state) - def _test_autofield_foreignfield_growth(self, source_field, target_field, target_value): + def _test_autofield_foreignfield_growth( + self, source_field, target_field, target_value + ): """ A field may be migrated in the following ways: @@ -3520,6 +4515,7 @@ class OperationTests(OperationTestBase): - SmallAutoField to AutoField - SmallAutoField to BigAutoField """ + def create_initial_data(models, schema_editor): Article = models.get_model("test_article", "Article") Blog = models.get_model("test_blog", "Blog") @@ -3546,17 +4542,26 @@ class OperationTests(OperationTestBase): "Article", [ ("id", source_field(primary_key=True)), - ("blog", models.ForeignKey(to="test_blog.Blog", on_delete=models.CASCADE)), + ( + "blog", + models.ForeignKey(to="test_blog.Blog", on_delete=models.CASCADE), + ), ("name", models.CharField(max_length=100)), ("data", models.TextField(default="")), ], options={}, ) - fill_initial_data = migrations.RunPython(create_initial_data, create_initial_data) + fill_initial_data = migrations.RunPython( + create_initial_data, create_initial_data + ) fill_big_data = migrations.RunPython(create_big_data, create_big_data) - grow_article_id = migrations.AlterField('Article', 'id', target_field(primary_key=True)) - grow_blog_id = migrations.AlterField('Blog', 'id', target_field(primary_key=True)) + grow_article_id = migrations.AlterField( + "Article", "id", target_field(primary_key=True) + ) + grow_blog_id = migrations.AlterField( + "Blog", "id", target_field(primary_key=True) + ) project_state = ProjectState() new_state = project_state.clone() @@ -3568,19 +4573,25 @@ class OperationTests(OperationTestBase): new_state = new_state.clone() with connection.schema_editor() as editor: create_article.state_forwards("test_article", new_state) - create_article.database_forwards("test_article", editor, project_state, new_state) + create_article.database_forwards( + "test_article", editor, project_state, new_state + ) project_state = new_state new_state = new_state.clone() with connection.schema_editor() as editor: fill_initial_data.state_forwards("fill_initial_data", new_state) - fill_initial_data.database_forwards("fill_initial_data", editor, project_state, new_state) + fill_initial_data.database_forwards( + "fill_initial_data", editor, project_state, new_state + ) project_state = new_state new_state = new_state.clone() with connection.schema_editor() as editor: grow_article_id.state_forwards("test_article", new_state) - grow_article_id.database_forwards("test_article", editor, project_state, new_state) + grow_article_id.database_forwards( + "test_article", editor, project_state, new_state + ) state = new_state.clone() article = state.apps.get_model("test_article.Article") @@ -3590,7 +4601,9 @@ class OperationTests(OperationTestBase): new_state = new_state.clone() with connection.schema_editor() as editor: grow_blog_id.state_forwards("test_blog", new_state) - grow_blog_id.database_forwards("test_blog", editor, project_state, new_state) + grow_blog_id.database_forwards( + "test_blog", editor, project_state, new_state + ) state = new_state.clone() blog = state.apps.get_model("test_blog.Blog") @@ -3600,14 +4613,16 @@ class OperationTests(OperationTestBase): new_state = new_state.clone() with connection.schema_editor() as editor: fill_big_data.state_forwards("fill_big_data", new_state) - fill_big_data.database_forwards("fill_big_data", editor, project_state, new_state) + fill_big_data.database_forwards( + "fill_big_data", editor, project_state, new_state + ) def test_autofield__bigautofield_foreignfield_growth(self): """A field may be migrated from AutoField to BigAutoField.""" self._test_autofield_foreignfield_growth( models.AutoField, models.BigAutoField, - 2 ** 33, + 2**33, ) def test_smallfield_autofield_foreignfield_growth(self): @@ -3615,7 +4630,7 @@ class OperationTests(OperationTestBase): self._test_autofield_foreignfield_growth( models.SmallAutoField, models.AutoField, - 2 ** 22, + 2**22, ) def test_smallfield_bigautofield_foreignfield_growth(self): @@ -3623,7 +4638,7 @@ class OperationTests(OperationTestBase): self._test_autofield_foreignfield_growth( models.SmallAutoField, models.BigAutoField, - 2 ** 33, + 2**33, ) def test_run_python_noop(self): @@ -3632,10 +4647,16 @@ class OperationTests(OperationTestBase): """ project_state = ProjectState() new_state = project_state.clone() - operation = migrations.RunPython(migrations.RunPython.noop, migrations.RunPython.noop) + operation = migrations.RunPython( + migrations.RunPython.noop, migrations.RunPython.noop + ) with connection.schema_editor() as editor: - operation.database_forwards("test_runpython", editor, project_state, new_state) - operation.database_backwards("test_runpython", editor, new_state, project_state) + operation.database_forwards( + "test_runpython", editor, project_state, new_state + ) + operation.database_backwards( + "test_runpython", editor, new_state, project_state + ) def test_separate_database_and_state(self): """ @@ -3645,34 +4666,50 @@ class OperationTests(OperationTestBase): # Create the operation database_operation = migrations.RunSQL( "CREATE TABLE i_love_ponies (id int, special_thing int);", - "DROP TABLE i_love_ponies;" + "DROP TABLE i_love_ponies;", + ) + state_operation = migrations.CreateModel( + "SomethingElse", [("id", models.AutoField(primary_key=True))] ) - state_operation = migrations.CreateModel("SomethingElse", [("id", models.AutoField(primary_key=True))]) operation = migrations.SeparateDatabaseAndState( - state_operations=[state_operation], - database_operations=[database_operation] + state_operations=[state_operation], database_operations=[database_operation] + ) + self.assertEqual( + operation.describe(), "Custom state/database change combination" ) - self.assertEqual(operation.describe(), "Custom state/database change combination") # Test the state alteration new_state = project_state.clone() operation.state_forwards("test_separatedatabaseandstate", new_state) - self.assertEqual(len(new_state.models["test_separatedatabaseandstate", "somethingelse"].fields), 1) + self.assertEqual( + len( + new_state.models[ + "test_separatedatabaseandstate", "somethingelse" + ].fields + ), + 1, + ) # Make sure there's no table self.assertTableNotExists("i_love_ponies") # Test the database alteration with connection.schema_editor() as editor: - operation.database_forwards("test_separatedatabaseandstate", editor, project_state, new_state) + operation.database_forwards( + "test_separatedatabaseandstate", editor, project_state, new_state + ) self.assertTableExists("i_love_ponies") # And test reversal self.assertTrue(operation.reversible) with connection.schema_editor() as editor: - operation.database_backwards("test_separatedatabaseandstate", editor, new_state, project_state) + operation.database_backwards( + "test_separatedatabaseandstate", editor, new_state, project_state + ) self.assertTableNotExists("i_love_ponies") # And deconstruction definition = operation.deconstruct() self.assertEqual(definition[0], "SeparateDatabaseAndState") self.assertEqual(definition[1], []) - self.assertEqual(sorted(definition[2]), ["database_operations", "state_operations"]) + self.assertEqual( + sorted(definition[2]), ["database_operations", "state_operations"] + ) def test_separate_database_and_state2(self): """ @@ -3728,7 +4765,10 @@ class OperationTests(OperationTestBase): def assertModelsAndTables(after_db): # Tables and models exist, or don't, as they should: self.assertNotIn((app_label, "somethingelse"), new_state.models) - self.assertEqual(len(new_state.models[app_label, "somethingcompletelydifferent"].fields), 1) + self.assertEqual( + len(new_state.models[app_label, "somethingcompletelydifferent"].fields), + 1, + ) self.assertNotIn((app_label, "iloveponiesonies"), new_state.models) self.assertNotIn((app_label, "ilovemoreponies"), new_state.models) self.assertNotIn((app_label, "iloveevenmoreponies"), new_state.models) @@ -3761,7 +4801,7 @@ class SwappableOperationTests(OperationTestBase): is in a common base class anyway) """ - available_apps = ['migrations'] + available_apps = ["migrations"] @override_settings(TEST_SWAP_MODEL="migrations.SomeFakeModel") def test_create_ignore_swapped(self): @@ -3791,7 +4831,9 @@ class SwappableOperationTests(OperationTestBase): self.assertTableNotExists("test_crigsw_pony") # And test reversal with connection.schema_editor() as editor: - operation.database_backwards("test_crigsw", editor, new_state, project_state) + operation.database_backwards( + "test_crigsw", editor, new_state, project_state + ) self.assertTableNotExists("test_crigsw_pony") @override_settings(TEST_SWAP_MODEL="migrations.SomeFakeModel") @@ -3808,7 +4850,9 @@ class SwappableOperationTests(OperationTestBase): self.assertTableNotExists("test_dligsw_pony") # And test reversal with connection.schema_editor() as editor: - operation.database_backwards("test_dligsw", editor, new_state, project_state) + operation.database_backwards( + "test_dligsw", editor, new_state, project_state + ) self.assertTableNotExists("test_dligsw_pony") @override_settings(TEST_SWAP_MODEL="migrations.SomeFakeModel") @@ -3826,87 +4870,142 @@ class SwappableOperationTests(OperationTestBase): # Test the database alteration self.assertTableNotExists("test_adfligsw_pony") with connection.schema_editor() as editor: - operation.database_forwards("test_adfligsw", editor, project_state, new_state) + operation.database_forwards( + "test_adfligsw", editor, project_state, new_state + ) self.assertTableNotExists("test_adfligsw_pony") # And test reversal with connection.schema_editor() as editor: - operation.database_backwards("test_adfligsw", editor, new_state, project_state) + operation.database_backwards( + "test_adfligsw", editor, new_state, project_state + ) self.assertTableNotExists("test_adfligsw_pony") - @override_settings(TEST_SWAP_MODEL='migrations.SomeFakeModel') + @override_settings(TEST_SWAP_MODEL="migrations.SomeFakeModel") def test_indexes_ignore_swapped(self): """ Add/RemoveIndex operations ignore swapped models. """ - operation = migrations.AddIndex('Pony', models.Index(fields=['pink'], name='my_name_idx')) - project_state, new_state = self.make_test_state('test_adinigsw', operation) + operation = migrations.AddIndex( + "Pony", models.Index(fields=["pink"], name="my_name_idx") + ) + project_state, new_state = self.make_test_state("test_adinigsw", operation) with connection.schema_editor() as editor: # No database queries should be run for swapped models - operation.database_forwards('test_adinigsw', editor, project_state, new_state) - operation.database_backwards('test_adinigsw', editor, new_state, project_state) + operation.database_forwards( + "test_adinigsw", editor, project_state, new_state + ) + operation.database_backwards( + "test_adinigsw", editor, new_state, project_state + ) - operation = migrations.RemoveIndex('Pony', models.Index(fields=['pink'], name='my_name_idx')) + operation = migrations.RemoveIndex( + "Pony", models.Index(fields=["pink"], name="my_name_idx") + ) project_state, new_state = self.make_test_state("test_rminigsw", operation) with connection.schema_editor() as editor: - operation.database_forwards('test_rminigsw', editor, project_state, new_state) - operation.database_backwards('test_rminigsw', editor, new_state, project_state) + operation.database_forwards( + "test_rminigsw", editor, project_state, new_state + ) + operation.database_backwards( + "test_rminigsw", editor, new_state, project_state + ) class TestCreateModel(SimpleTestCase): - def test_references_model_mixin(self): migrations.CreateModel( - 'name', + "name", fields=[], bases=(Mixin, models.Model), - ).references_model('other_model', 'migrations') + ).references_model("other_model", "migrations") class FieldOperationTests(SimpleTestCase): def test_references_model(self): - operation = FieldOperation('MoDel', 'field', models.ForeignKey('Other', models.CASCADE)) + operation = FieldOperation( + "MoDel", "field", models.ForeignKey("Other", models.CASCADE) + ) # Model name match. - self.assertIs(operation.references_model('mOdEl', 'migrations'), True) + self.assertIs(operation.references_model("mOdEl", "migrations"), True) # Referenced field. - self.assertIs(operation.references_model('oTher', 'migrations'), True) + self.assertIs(operation.references_model("oTher", "migrations"), True) # Doesn't reference. - self.assertIs(operation.references_model('Whatever', 'migrations'), False) + self.assertIs(operation.references_model("Whatever", "migrations"), False) def test_references_field_by_name(self): - operation = FieldOperation('MoDel', 'field', models.BooleanField(default=False)) - self.assertIs(operation.references_field('model', 'field', 'migrations'), True) + operation = FieldOperation("MoDel", "field", models.BooleanField(default=False)) + self.assertIs(operation.references_field("model", "field", "migrations"), True) def test_references_field_by_remote_field_model(self): - operation = FieldOperation('Model', 'field', models.ForeignKey('Other', models.CASCADE)) - self.assertIs(operation.references_field('Other', 'whatever', 'migrations'), True) - self.assertIs(operation.references_field('Missing', 'whatever', 'migrations'), False) + operation = FieldOperation( + "Model", "field", models.ForeignKey("Other", models.CASCADE) + ) + self.assertIs( + operation.references_field("Other", "whatever", "migrations"), True + ) + self.assertIs( + operation.references_field("Missing", "whatever", "migrations"), False + ) def test_references_field_by_from_fields(self): operation = FieldOperation( - 'Model', 'field', models.fields.related.ForeignObject('Other', models.CASCADE, ['from'], ['to']) + "Model", + "field", + models.fields.related.ForeignObject( + "Other", models.CASCADE, ["from"], ["to"] + ), ) - self.assertIs(operation.references_field('Model', 'from', 'migrations'), True) - self.assertIs(operation.references_field('Model', 'to', 'migrations'), False) - self.assertIs(operation.references_field('Other', 'from', 'migrations'), False) - self.assertIs(operation.references_field('Model', 'to', 'migrations'), False) + self.assertIs(operation.references_field("Model", "from", "migrations"), True) + self.assertIs(operation.references_field("Model", "to", "migrations"), False) + self.assertIs(operation.references_field("Other", "from", "migrations"), False) + self.assertIs(operation.references_field("Model", "to", "migrations"), False) def test_references_field_by_to_fields(self): - operation = FieldOperation('Model', 'field', models.ForeignKey('Other', models.CASCADE, to_field='field')) - self.assertIs(operation.references_field('Other', 'field', 'migrations'), True) - self.assertIs(operation.references_field('Other', 'whatever', 'migrations'), False) - self.assertIs(operation.references_field('Missing', 'whatever', 'migrations'), False) + operation = FieldOperation( + "Model", + "field", + models.ForeignKey("Other", models.CASCADE, to_field="field"), + ) + self.assertIs(operation.references_field("Other", "field", "migrations"), True) + self.assertIs( + operation.references_field("Other", "whatever", "migrations"), False + ) + self.assertIs( + operation.references_field("Missing", "whatever", "migrations"), False + ) def test_references_field_by_through(self): - operation = FieldOperation('Model', 'field', models.ManyToManyField('Other', through='Through')) - self.assertIs(operation.references_field('Other', 'whatever', 'migrations'), True) - self.assertIs(operation.references_field('Through', 'whatever', 'migrations'), True) - self.assertIs(operation.references_field('Missing', 'whatever', 'migrations'), False) + operation = FieldOperation( + "Model", "field", models.ManyToManyField("Other", through="Through") + ) + self.assertIs( + operation.references_field("Other", "whatever", "migrations"), True + ) + self.assertIs( + operation.references_field("Through", "whatever", "migrations"), True + ) + self.assertIs( + operation.references_field("Missing", "whatever", "migrations"), False + ) def test_reference_field_by_through_fields(self): operation = FieldOperation( - 'Model', 'field', models.ManyToManyField('Other', through='Through', through_fields=('first', 'second')) + "Model", + "field", + models.ManyToManyField( + "Other", through="Through", through_fields=("first", "second") + ), + ) + self.assertIs( + operation.references_field("Other", "whatever", "migrations"), True + ) + self.assertIs( + operation.references_field("Through", "whatever", "migrations"), False + ) + self.assertIs( + operation.references_field("Through", "first", "migrations"), True + ) + self.assertIs( + operation.references_field("Through", "second", "migrations"), True ) - self.assertIs(operation.references_field('Other', 'whatever', 'migrations'), True) - self.assertIs(operation.references_field('Through', 'whatever', 'migrations'), False) - self.assertIs(operation.references_field('Through', 'first', 'migrations'), True) - self.assertIs(operation.references_field('Through', 'second', 'migrations'), True) diff --git a/tests/migrations/test_optimizer.py b/tests/migrations/test_optimizer.py index 0caaf66f9e..b69563ebab 100644 --- a/tests/migrations/test_optimizer.py +++ b/tests/migrations/test_optimizer.py @@ -22,18 +22,22 @@ class OptimizerTests(SimpleTestCase): def serialize(self, value): return serializer_factory(value).serialize()[0] - def assertOptimizesTo(self, operations, expected, exact=None, less_than=None, app_label=None): - result, iterations = self.optimize(operations, app_label or 'migrations') + def assertOptimizesTo( + self, operations, expected, exact=None, less_than=None, app_label=None + ): + result, iterations = self.optimize(operations, app_label or "migrations") result = [self.serialize(f) for f in result] expected = [self.serialize(f) for f in expected] self.assertEqual(expected, result) if exact is not None and iterations != exact: raise self.failureException( - "Optimization did not take exactly %s iterations (it took %s)" % (exact, iterations) + "Optimization did not take exactly %s iterations (it took %s)" + % (exact, iterations) ) if less_than is not None and iterations >= less_than: raise self.failureException( - "Optimization did not take less than %s iterations (it took %s)" % (less_than, iterations) + "Optimization did not take less than %s iterations (it took %s)" + % (less_than, iterations) ) def assertDoesNotOptimize(self, operations, **kwargs): @@ -41,7 +45,7 @@ class OptimizerTests(SimpleTestCase): def test_none_app_label(self): optimizer = MigrationOptimizer() - with self.assertRaisesMessage(TypeError, 'app_label must be a str'): + with self.assertRaisesMessage(TypeError, "app_label must be a str"): optimizer.optimize([], None) def test_single(self): @@ -61,7 +65,9 @@ class OptimizerTests(SimpleTestCase): """ self.assertOptimizesTo( [ - migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]), + migrations.CreateModel( + "Foo", [("name", models.CharField(max_length=255))] + ), migrations.DeleteModel("Foo"), ], [], @@ -71,13 +77,13 @@ class OptimizerTests(SimpleTestCase): """ CreateModel should absorb RenameModels. """ - managers = [('objects', EmptyManager())] + managers = [("objects", EmptyManager())] self.assertOptimizesTo( [ migrations.CreateModel( name="Foo", fields=[("name", models.CharField(max_length=255))], - options={'verbose_name': 'Foo'}, + options={"verbose_name": "Foo"}, bases=(UnicodeModel,), managers=managers, ), @@ -87,7 +93,7 @@ class OptimizerTests(SimpleTestCase): migrations.CreateModel( "Bar", [("name", models.CharField(max_length=255))], - options={'verbose_name': 'Foo'}, + options={"verbose_name": "Foo"}, bases=(UnicodeModel,), managers=managers, ) @@ -111,46 +117,50 @@ class OptimizerTests(SimpleTestCase): def test_create_alter_model_options(self): self.assertOptimizesTo( [ - migrations.CreateModel('Foo', fields=[]), - migrations.AlterModelOptions(name='Foo', options={'verbose_name_plural': 'Foozes'}), + migrations.CreateModel("Foo", fields=[]), + migrations.AlterModelOptions( + name="Foo", options={"verbose_name_plural": "Foozes"} + ), ], [ - migrations.CreateModel('Foo', fields=[], options={'verbose_name_plural': 'Foozes'}), - ] + migrations.CreateModel( + "Foo", fields=[], options={"verbose_name_plural": "Foozes"} + ), + ], ) def test_create_model_and_remove_model_options(self): self.assertOptimizesTo( [ migrations.CreateModel( - 'MyModel', + "MyModel", fields=[], - options={'verbose_name': 'My Model'}, + options={"verbose_name": "My Model"}, ), - migrations.AlterModelOptions('MyModel', options={}), + migrations.AlterModelOptions("MyModel", options={}), ], - [migrations.CreateModel('MyModel', fields=[])], + [migrations.CreateModel("MyModel", fields=[])], ) self.assertOptimizesTo( [ migrations.CreateModel( - 'MyModel', + "MyModel", fields=[], options={ - 'verbose_name': 'My Model', - 'verbose_name_plural': 'My Model plural', + "verbose_name": "My Model", + "verbose_name_plural": "My Model plural", }, ), migrations.AlterModelOptions( - 'MyModel', - options={'verbose_name': 'My Model'}, + "MyModel", + options={"verbose_name": "My Model"}, ), ], [ migrations.CreateModel( - 'MyModel', + "MyModel", fields=[], - options={'verbose_name': 'My Model'}, + options={"verbose_name": "My Model"}, ), ], ) @@ -162,7 +172,9 @@ class OptimizerTests(SimpleTestCase): """ self.assertOptimizesTo( [ - migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]), + migrations.CreateModel( + "Foo", [("name", models.CharField(max_length=255))] + ), migrations.AlterModelTable("Foo", "woohoo"), alter_foo, migrations.DeleteModel("Foo"), @@ -171,13 +183,19 @@ class OptimizerTests(SimpleTestCase): ) def test_create_alter_unique_delete_model(self): - self._test_create_alter_foo_delete_model(migrations.AlterUniqueTogether("Foo", [["a", "b"]])) + self._test_create_alter_foo_delete_model( + migrations.AlterUniqueTogether("Foo", [["a", "b"]]) + ) def test_create_alter_index_delete_model(self): - self._test_create_alter_foo_delete_model(migrations.AlterIndexTogether("Foo", [["a", "b"]])) + self._test_create_alter_foo_delete_model( + migrations.AlterIndexTogether("Foo", [["a", "b"]]) + ) def test_create_alter_owrt_delete_model(self): - self._test_create_alter_foo_delete_model(migrations.AlterOrderWithRespectTo("Foo", "a")) + self._test_create_alter_foo_delete_model( + migrations.AlterOrderWithRespectTo("Foo", "a") + ) def _test_alter_alter_model(self, alter_foo, alter_bar): """ @@ -227,7 +245,9 @@ class OptimizerTests(SimpleTestCase): # These should work self.assertOptimizesTo( [ - migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]), + migrations.CreateModel( + "Foo", [("name", models.CharField(max_length=255))] + ), migrations.CreateModel("Bar", [("size", models.IntegerField())]), migrations.DeleteModel("Foo"), ], @@ -237,7 +257,9 @@ class OptimizerTests(SimpleTestCase): ) self.assertOptimizesTo( [ - migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]), + migrations.CreateModel( + "Foo", [("name", models.CharField(max_length=255))] + ), migrations.CreateModel("Bar", [("size", models.IntegerField())]), migrations.DeleteModel("Bar"), migrations.DeleteModel("Foo"), @@ -246,7 +268,9 @@ class OptimizerTests(SimpleTestCase): ) self.assertOptimizesTo( [ - migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]), + migrations.CreateModel( + "Foo", [("name", models.CharField(max_length=255))] + ), migrations.CreateModel("Bar", [("size", models.IntegerField())]), migrations.DeleteModel("Foo"), migrations.DeleteModel("Bar"), @@ -257,12 +281,18 @@ class OptimizerTests(SimpleTestCase): # other app. self.assertOptimizesTo( [ - migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]), - migrations.CreateModel("Bar", [("other", models.ForeignKey("testapp.Foo", models.CASCADE))]), + migrations.CreateModel( + "Foo", [("name", models.CharField(max_length=255))] + ), + migrations.CreateModel( + "Bar", [("other", models.ForeignKey("testapp.Foo", models.CASCADE))] + ), migrations.DeleteModel("Foo"), ], [ - migrations.CreateModel("Bar", [("other", models.ForeignKey("testapp.Foo", models.CASCADE))]), + migrations.CreateModel( + "Bar", [("other", models.ForeignKey("testapp.Foo", models.CASCADE))] + ), ], app_label="otherapp", ) @@ -270,15 +300,23 @@ class OptimizerTests(SimpleTestCase): # app_label. self.assertDoesNotOptimize( [ - migrations.CreateModel('Foo', [('name', models.CharField(max_length=255))]), - migrations.CreateModel('Bar', [('other', models.ForeignKey('Foo', models.CASCADE))]), - migrations.DeleteModel('Foo'), + migrations.CreateModel( + "Foo", [("name", models.CharField(max_length=255))] + ), + migrations.CreateModel( + "Bar", [("other", models.ForeignKey("Foo", models.CASCADE))] + ), + migrations.DeleteModel("Foo"), ], ) self.assertDoesNotOptimize( [ - migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]), - migrations.CreateModel("Bar", [("other", models.ForeignKey("testapp.Foo", models.CASCADE))]), + migrations.CreateModel( + "Foo", [("name", models.CharField(max_length=255))] + ), + migrations.CreateModel( + "Bar", [("other", models.ForeignKey("testapp.Foo", models.CASCADE))] + ), migrations.DeleteModel("Foo"), ], app_label="testapp", @@ -286,37 +324,55 @@ class OptimizerTests(SimpleTestCase): # This should not work - bases should block it self.assertDoesNotOptimize( [ - migrations.CreateModel('Foo', [('name', models.CharField(max_length=255))]), - migrations.CreateModel('Bar', [('size', models.IntegerField())], bases=('Foo',)), - migrations.DeleteModel('Foo'), + migrations.CreateModel( + "Foo", [("name", models.CharField(max_length=255))] + ), + migrations.CreateModel( + "Bar", [("size", models.IntegerField())], bases=("Foo",) + ), + migrations.DeleteModel("Foo"), ], ) self.assertDoesNotOptimize( [ - migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]), - migrations.CreateModel("Bar", [("size", models.IntegerField())], bases=("testapp.Foo",)), + migrations.CreateModel( + "Foo", [("name", models.CharField(max_length=255))] + ), + migrations.CreateModel( + "Bar", [("size", models.IntegerField())], bases=("testapp.Foo",) + ), migrations.DeleteModel("Foo"), ], - app_label='testapp', + app_label="testapp", ) # The same operations should be optimized if app_label and none of # bases belong to that app. self.assertOptimizesTo( [ - migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]), - migrations.CreateModel("Bar", [("size", models.IntegerField())], bases=("testapp.Foo",)), + migrations.CreateModel( + "Foo", [("name", models.CharField(max_length=255))] + ), + migrations.CreateModel( + "Bar", [("size", models.IntegerField())], bases=("testapp.Foo",) + ), migrations.DeleteModel("Foo"), ], [ - migrations.CreateModel("Bar", [("size", models.IntegerField())], bases=("testapp.Foo",)), + migrations.CreateModel( + "Bar", [("size", models.IntegerField())], bases=("testapp.Foo",) + ), ], app_label="otherapp", ) # But it shouldn't work if some of bases belongs to the specified app. self.assertDoesNotOptimize( [ - migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]), - migrations.CreateModel("Bar", [("size", models.IntegerField())], bases=("testapp.Foo",)), + migrations.CreateModel( + "Foo", [("name", models.CharField(max_length=255))] + ), + migrations.CreateModel( + "Bar", [("size", models.IntegerField())], bases=("testapp.Foo",) + ), migrations.DeleteModel("Foo"), ], app_label="testapp", @@ -324,37 +380,64 @@ class OptimizerTests(SimpleTestCase): self.assertOptimizesTo( [ - migrations.CreateModel('Book', [('name', models.CharField(max_length=255))]), - migrations.CreateModel('Person', [('name', models.CharField(max_length=255))]), - migrations.AddField('book', 'author', models.ForeignKey('test_app.Person', models.CASCADE)), - migrations.CreateModel('Review', [('book', models.ForeignKey('test_app.Book', models.CASCADE))]), - migrations.CreateModel('Reviewer', [('name', models.CharField(max_length=255))]), - migrations.AddField('review', 'reviewer', models.ForeignKey('test_app.Reviewer', models.CASCADE)), - migrations.RemoveField('book', 'author'), - migrations.DeleteModel('Person'), + migrations.CreateModel( + "Book", [("name", models.CharField(max_length=255))] + ), + migrations.CreateModel( + "Person", [("name", models.CharField(max_length=255))] + ), + migrations.AddField( + "book", + "author", + models.ForeignKey("test_app.Person", models.CASCADE), + ), + migrations.CreateModel( + "Review", + [("book", models.ForeignKey("test_app.Book", models.CASCADE))], + ), + migrations.CreateModel( + "Reviewer", [("name", models.CharField(max_length=255))] + ), + migrations.AddField( + "review", + "reviewer", + models.ForeignKey("test_app.Reviewer", models.CASCADE), + ), + migrations.RemoveField("book", "author"), + migrations.DeleteModel("Person"), ], [ - migrations.CreateModel('Book', [('name', models.CharField(max_length=255))]), - migrations.CreateModel('Reviewer', [('name', models.CharField(max_length=255))]), - migrations.CreateModel('Review', [ - ('book', models.ForeignKey('test_app.Book', models.CASCADE)), - ('reviewer', models.ForeignKey('test_app.Reviewer', models.CASCADE)), - ]), + migrations.CreateModel( + "Book", [("name", models.CharField(max_length=255))] + ), + migrations.CreateModel( + "Reviewer", [("name", models.CharField(max_length=255))] + ), + migrations.CreateModel( + "Review", + [ + ("book", models.ForeignKey("test_app.Book", models.CASCADE)), + ( + "reviewer", + models.ForeignKey("test_app.Reviewer", models.CASCADE), + ), + ], + ), ], - app_label='test_app', + app_label="test_app", ) def test_create_model_add_field(self): """ AddField should optimize into CreateModel. """ - managers = [('objects', EmptyManager())] + managers = [("objects", EmptyManager())] self.assertOptimizesTo( [ migrations.CreateModel( name="Foo", fields=[("name", models.CharField(max_length=255))], - options={'verbose_name': 'Foo'}, + options={"verbose_name": "Foo"}, bases=(UnicodeModel,), managers=managers, ), @@ -367,7 +450,7 @@ class OptimizerTests(SimpleTestCase): ("name", models.CharField(max_length=255)), ("age", models.IntegerField()), ], - options={'verbose_name': 'Foo'}, + options={"verbose_name": "Foo"}, bases=(UnicodeModel,), managers=managers, ), @@ -382,16 +465,23 @@ class OptimizerTests(SimpleTestCase): """ self.assertOptimizesTo( [ - migrations.CreateModel('Foo', [('name', models.CharField(max_length=255))]), - migrations.CreateModel('Link', [('url', models.TextField())]), - migrations.AddField('Foo', 'link', models.ForeignKey('migrations.Link', models.CASCADE)), + migrations.CreateModel( + "Foo", [("name", models.CharField(max_length=255))] + ), + migrations.CreateModel("Link", [("url", models.TextField())]), + migrations.AddField( + "Foo", "link", models.ForeignKey("migrations.Link", models.CASCADE) + ), ], [ - migrations.CreateModel('Link', [('url', models.TextField())]), - migrations.CreateModel('Foo', [ - ('name', models.CharField(max_length=255)), - ('link', models.ForeignKey('migrations.Link', models.CASCADE)) - ]), + migrations.CreateModel("Link", [("url", models.TextField())]), + migrations.CreateModel( + "Foo", + [ + ("name", models.CharField(max_length=255)), + ("link", models.ForeignKey("migrations.Link", models.CASCADE)), + ], + ), ], ) @@ -402,18 +492,31 @@ class OptimizerTests(SimpleTestCase): """ self.assertOptimizesTo( [ - migrations.CreateModel('Bar', [('url', models.TextField())]), - migrations.CreateModel('Foo', [('name', models.CharField(max_length=255))]), - migrations.AddField('Bar', 'foo_fk', models.ForeignKey('migrations.Foo', models.CASCADE)), - migrations.AddField('Foo', 'bar_fk', models.ForeignKey('migrations.Bar', models.CASCADE)), + migrations.CreateModel("Bar", [("url", models.TextField())]), + migrations.CreateModel( + "Foo", [("name", models.CharField(max_length=255))] + ), + migrations.AddField( + "Bar", "foo_fk", models.ForeignKey("migrations.Foo", models.CASCADE) + ), + migrations.AddField( + "Foo", "bar_fk", models.ForeignKey("migrations.Bar", models.CASCADE) + ), ], [ - migrations.CreateModel('Foo', [('name', models.CharField(max_length=255))]), - migrations.CreateModel('Bar', [ - ('url', models.TextField()), - ('foo_fk', models.ForeignKey('migrations.Foo', models.CASCADE)), - ]), - migrations.AddField('Foo', 'bar_fk', models.ForeignKey('migrations.Bar', models.CASCADE)), + migrations.CreateModel( + "Foo", [("name", models.CharField(max_length=255))] + ), + migrations.CreateModel( + "Bar", + [ + ("url", models.TextField()), + ("foo_fk", models.ForeignKey("migrations.Foo", models.CASCADE)), + ], + ), + migrations.AddField( + "Foo", "bar_fk", models.ForeignKey("migrations.Bar", models.CASCADE) + ), ], ) @@ -424,9 +527,15 @@ class OptimizerTests(SimpleTestCase): """ self.assertDoesNotOptimize( [ - migrations.CreateModel('Foo', [('name', models.CharField(max_length=255))]), - migrations.CreateModel('Link', [('url', models.TextField())]), - migrations.AddField('Other', 'link', models.ForeignKey('migrations.Link', models.CASCADE)), + migrations.CreateModel( + "Foo", [("name", models.CharField(max_length=255))] + ), + migrations.CreateModel("Link", [("url", models.TextField())]), + migrations.AddField( + "Other", + "link", + models.ForeignKey("migrations.Link", models.CASCADE), + ), ], ) @@ -437,27 +546,41 @@ class OptimizerTests(SimpleTestCase): """ self.assertOptimizesTo( [ - migrations.CreateModel('Other', [('foo', models.CharField(max_length=255))]), - migrations.CreateModel('ParentModel', [('bar', models.CharField(max_length=255))]), migrations.CreateModel( - 'ChildModel', - [('baz', models.CharField(max_length=255))], - bases=('migrations.parentmodel',), + "Other", [("foo", models.CharField(max_length=255))] + ), + migrations.CreateModel( + "ParentModel", [("bar", models.CharField(max_length=255))] + ), + migrations.CreateModel( + "ChildModel", + [("baz", models.CharField(max_length=255))], + bases=("migrations.parentmodel",), + ), + migrations.AddField( + "Other", + "fk", + models.ForeignKey("migrations.ChildModel", models.CASCADE), ), - migrations.AddField('Other', 'fk', models.ForeignKey('migrations.ChildModel', models.CASCADE)), ], [ - migrations.CreateModel('ParentModel', [('bar', models.CharField(max_length=255))]), migrations.CreateModel( - 'ChildModel', - [('baz', models.CharField(max_length=255))], - bases=('migrations.parentmodel',), + "ParentModel", [("bar", models.CharField(max_length=255))] + ), + migrations.CreateModel( + "ChildModel", + [("baz", models.CharField(max_length=255))], + bases=("migrations.parentmodel",), ), migrations.CreateModel( - 'Other', [ - ('foo', models.CharField(max_length=255)), - ('fk', models.ForeignKey('migrations.ChildModel', models.CASCADE)), - ] + "Other", + [ + ("foo", models.CharField(max_length=255)), + ( + "fk", + models.ForeignKey("migrations.ChildModel", models.CASCADE), + ), + ], ), ], ) @@ -469,16 +592,28 @@ class OptimizerTests(SimpleTestCase): """ self.assertDoesNotOptimize( [ - migrations.CreateModel('Employee', []), - migrations.CreateModel('Employer', []), - migrations.CreateModel('Employment', [ - ('employee', models.ForeignKey('migrations.Employee', models.CASCADE)), - ('employment', models.ForeignKey('migrations.Employer', models.CASCADE)), - ]), + migrations.CreateModel("Employee", []), + migrations.CreateModel("Employer", []), + migrations.CreateModel( + "Employment", + [ + ( + "employee", + models.ForeignKey("migrations.Employee", models.CASCADE), + ), + ( + "employment", + models.ForeignKey("migrations.Employer", models.CASCADE), + ), + ], + ), migrations.AddField( - 'Employer', 'employees', models.ManyToManyField( - 'migrations.Employee', through='migrations.Employment', - ) + "Employer", + "employees", + models.ManyToManyField( + "migrations.Employee", + through="migrations.Employment", + ), ), ], ) @@ -487,13 +622,13 @@ class OptimizerTests(SimpleTestCase): """ AlterField should optimize into CreateModel. """ - managers = [('objects', EmptyManager())] + managers = [("objects", EmptyManager())] self.assertOptimizesTo( [ migrations.CreateModel( name="Foo", fields=[("name", models.CharField(max_length=255))], - options={'verbose_name': 'Foo'}, + options={"verbose_name": "Foo"}, bases=(UnicodeModel,), managers=managers, ), @@ -505,7 +640,7 @@ class OptimizerTests(SimpleTestCase): fields=[ ("name", models.IntegerField()), ], - options={'verbose_name': 'Foo'}, + options={"verbose_name": "Foo"}, bases=(UnicodeModel,), managers=managers, ), @@ -516,13 +651,13 @@ class OptimizerTests(SimpleTestCase): """ RenameField should optimize into CreateModel. """ - managers = [('objects', EmptyManager())] + managers = [("objects", EmptyManager())] self.assertOptimizesTo( [ migrations.CreateModel( name="Foo", fields=[("name", models.CharField(max_length=255))], - options={'verbose_name': 'Foo'}, + options={"verbose_name": "Foo"}, bases=(UnicodeModel,), managers=managers, ), @@ -534,7 +669,7 @@ class OptimizerTests(SimpleTestCase): fields=[ ("title", models.CharField(max_length=255)), ], - options={'verbose_name': 'Foo'}, + options={"verbose_name": "Foo"}, bases=(UnicodeModel,), managers=managers, ), @@ -576,16 +711,16 @@ class OptimizerTests(SimpleTestCase): self.assertDoesNotOptimize( [ migrations.CreateModel( - 'MyModel', + "MyModel", [ - ('field_a', models.IntegerField()), - ('field_b', models.IntegerField()), + ("field_a", models.IntegerField()), + ("field_b", models.IntegerField()), ], ), migrations.RunPython(migrations.RunPython.noop), - migrations.RenameField('MyModel', 'field_a', 'field_c'), - migrations.RenameField('MyModel', 'field_b', 'field_a'), - migrations.RenameField('MyModel', 'field_c', 'field_b'), + migrations.RenameField("MyModel", "field_a", "field_c"), + migrations.RenameField("MyModel", "field_b", "field_a"), + migrations.RenameField("MyModel", "field_c", "field_b"), ], ) @@ -593,7 +728,7 @@ class OptimizerTests(SimpleTestCase): """ RemoveField should optimize into CreateModel. """ - managers = [('objects', EmptyManager())] + managers = [("objects", EmptyManager())] self.assertOptimizesTo( [ migrations.CreateModel( @@ -602,7 +737,7 @@ class OptimizerTests(SimpleTestCase): ("name", models.CharField(max_length=255)), ("age", models.IntegerField()), ], - options={'verbose_name': 'Foo'}, + options={"verbose_name": "Foo"}, bases=(UnicodeModel,), managers=managers, ), @@ -614,7 +749,7 @@ class OptimizerTests(SimpleTestCase): fields=[ ("name", models.CharField(max_length=255)), ], - options={'verbose_name': 'Foo'}, + options={"verbose_name": "Foo"}, bases=(UnicodeModel,), managers=managers, ), @@ -631,7 +766,9 @@ class OptimizerTests(SimpleTestCase): migrations.AlterField("Foo", "age", models.FloatField(default=2.4)), ], [ - migrations.AddField("Foo", name="age", field=models.FloatField(default=2.4)), + migrations.AddField( + "Foo", name="age", field=models.FloatField(default=2.4) + ), ], ) @@ -672,119 +809,162 @@ class OptimizerTests(SimpleTestCase): # AddField self.assertOptimizesTo( [ - migrations.CreateModel("Foo", [ - ("a", models.IntegerField()), - ("b", models.IntegerField()), - ]), + migrations.CreateModel( + "Foo", + [ + ("a", models.IntegerField()), + ("b", models.IntegerField()), + ], + ), alter, migrations.AddField("Foo", "c", models.IntegerField()), ], [ - migrations.CreateModel("Foo", [ - ("a", models.IntegerField()), - ("b", models.IntegerField()), - ("c", models.IntegerField()), - ], options=options), + migrations.CreateModel( + "Foo", + [ + ("a", models.IntegerField()), + ("b", models.IntegerField()), + ("c", models.IntegerField()), + ], + options=options, + ), ], ) # AlterField self.assertOptimizesTo( [ - migrations.CreateModel("Foo", [ - ("a", models.IntegerField()), - ("b", models.IntegerField()), - ]), + migrations.CreateModel( + "Foo", + [ + ("a", models.IntegerField()), + ("b", models.IntegerField()), + ], + ), alter, migrations.AlterField("Foo", "b", models.CharField(max_length=255)), ], [ - migrations.CreateModel("Foo", [ - ("a", models.IntegerField()), - ("b", models.CharField(max_length=255)), - ], options=options), + migrations.CreateModel( + "Foo", + [ + ("a", models.IntegerField()), + ("b", models.CharField(max_length=255)), + ], + options=options, + ), ], ) self.assertOptimizesTo( [ - migrations.CreateModel("Foo", [ - ("a", models.IntegerField()), - ("b", models.IntegerField()), - ("c", models.IntegerField()), - ]), + migrations.CreateModel( + "Foo", + [ + ("a", models.IntegerField()), + ("b", models.IntegerField()), + ("c", models.IntegerField()), + ], + ), alter, migrations.AlterField("Foo", "c", models.CharField(max_length=255)), ], [ - migrations.CreateModel("Foo", [ - ("a", models.IntegerField()), - ("b", models.IntegerField()), - ("c", models.CharField(max_length=255)), - ], options=options), + migrations.CreateModel( + "Foo", + [ + ("a", models.IntegerField()), + ("b", models.IntegerField()), + ("c", models.CharField(max_length=255)), + ], + options=options, + ), ], ) # RenameField if isinstance(option_value, str): - renamed_options = {alter.option_name: 'c'} + renamed_options = {alter.option_name: "c"} else: renamed_options = { alter.option_name: { - tuple('c' if value == 'b' else value for value in item) for item in option_value + tuple("c" if value == "b" else value for value in item) + for item in option_value } } self.assertOptimizesTo( [ - migrations.CreateModel("Foo", [ - ("a", models.IntegerField()), - ("b", models.IntegerField()), - ]), + migrations.CreateModel( + "Foo", + [ + ("a", models.IntegerField()), + ("b", models.IntegerField()), + ], + ), alter, migrations.RenameField("Foo", "b", "c"), ], [ - migrations.CreateModel("Foo", [ - ("a", models.IntegerField()), - ("c", models.IntegerField()), - ], options=renamed_options), + migrations.CreateModel( + "Foo", + [ + ("a", models.IntegerField()), + ("c", models.IntegerField()), + ], + options=renamed_options, + ), ], ) self.assertOptimizesTo( [ - migrations.CreateModel("Foo", [ - ("a", models.IntegerField()), - ("b", models.IntegerField()), - ]), + migrations.CreateModel( + "Foo", + [ + ("a", models.IntegerField()), + ("b", models.IntegerField()), + ], + ), alter, migrations.RenameField("Foo", "b", "x"), migrations.RenameField("Foo", "x", "c"), ], [ - migrations.CreateModel("Foo", [ - ("a", models.IntegerField()), - ("c", models.IntegerField()), - ], options=renamed_options), + migrations.CreateModel( + "Foo", + [ + ("a", models.IntegerField()), + ("c", models.IntegerField()), + ], + options=renamed_options, + ), ], ) self.assertOptimizesTo( [ - migrations.CreateModel("Foo", [ - ("a", models.IntegerField()), - ("b", models.IntegerField()), - ("c", models.IntegerField()), - ]), + migrations.CreateModel( + "Foo", + [ + ("a", models.IntegerField()), + ("b", models.IntegerField()), + ("c", models.IntegerField()), + ], + ), alter, migrations.RenameField("Foo", "c", "d"), ], [ - migrations.CreateModel("Foo", [ - ("a", models.IntegerField()), - ("b", models.IntegerField()), - ("d", models.IntegerField()), - ], options=options), + migrations.CreateModel( + "Foo", + [ + ("a", models.IntegerField()), + ("b", models.IntegerField()), + ("d", models.IntegerField()), + ], + options=options, + ), ], ) @@ -794,51 +974,72 @@ class OptimizerTests(SimpleTestCase): else: removed_options = { alter.option_name: { - tuple(value for value in item if value != 'b') for item in option_value + tuple(value for value in item if value != "b") + for item in option_value } } self.assertOptimizesTo( [ - migrations.CreateModel("Foo", [ - ("a", models.IntegerField()), - ("b", models.IntegerField()), - ]), + migrations.CreateModel( + "Foo", + [ + ("a", models.IntegerField()), + ("b", models.IntegerField()), + ], + ), alter, migrations.RemoveField("Foo", "b"), ], [ - migrations.CreateModel("Foo", [ - ("a", models.IntegerField()), - ], options=removed_options), - ] + migrations.CreateModel( + "Foo", + [ + ("a", models.IntegerField()), + ], + options=removed_options, + ), + ], ) self.assertOptimizesTo( [ - migrations.CreateModel("Foo", [ - ("a", models.IntegerField()), - ("b", models.IntegerField()), - ("c", models.IntegerField()), - ]), + migrations.CreateModel( + "Foo", + [ + ("a", models.IntegerField()), + ("b", models.IntegerField()), + ("c", models.IntegerField()), + ], + ), alter, migrations.RemoveField("Foo", "c"), ], [ - migrations.CreateModel("Foo", [ - ("a", models.IntegerField()), - ("b", models.IntegerField()), - ], options=options), + migrations.CreateModel( + "Foo", + [ + ("a", models.IntegerField()), + ("b", models.IntegerField()), + ], + options=options, + ), ], ) def test_create_alter_unique_field(self): - self._test_create_alter_foo_field(migrations.AlterUniqueTogether("Foo", [["a", "b"]])) + self._test_create_alter_foo_field( + migrations.AlterUniqueTogether("Foo", [["a", "b"]]) + ) def test_create_alter_index_field(self): - self._test_create_alter_foo_field(migrations.AlterIndexTogether("Foo", [["a", "b"]])) + self._test_create_alter_foo_field( + migrations.AlterIndexTogether("Foo", [["a", "b"]]) + ) def test_create_alter_owrt_field(self): - self._test_create_alter_foo_field(migrations.AlterOrderWithRespectTo("Foo", "b")) + self._test_create_alter_foo_field( + migrations.AlterOrderWithRespectTo("Foo", "b") + ) def test_optimize_through_fields(self): """ @@ -848,7 +1049,9 @@ class OptimizerTests(SimpleTestCase): """ self.assertOptimizesTo( [ - migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]), + migrations.CreateModel( + "Foo", [("name", models.CharField(max_length=255))] + ), migrations.CreateModel("Bar", [("size", models.IntegerField())]), migrations.AddField("Foo", "age", models.IntegerField()), migrations.AddField("Bar", "width", models.IntegerField()), @@ -871,7 +1074,9 @@ class OptimizerTests(SimpleTestCase): self.assertOptimizesTo( [ elidable_operation, - migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]), + migrations.CreateModel( + "Foo", [("name", models.CharField(max_length=255))] + ), elidable_operation, migrations.CreateModel("Bar", [("size", models.IntegerField())]), elidable_operation, @@ -880,6 +1085,8 @@ class OptimizerTests(SimpleTestCase): elidable_operation, ], [ - migrations.CreateModel("Phou", [("name", models.CharField(max_length=255))]), + migrations.CreateModel( + "Phou", [("name", models.CharField(max_length=255))] + ), ], ) diff --git a/tests/migrations/test_questioner.py b/tests/migrations/test_questioner.py index 472a3f248f..c1aebcb224 100644 --- a/tests/migrations/test_questioner.py +++ b/tests/migrations/test_questioner.py @@ -4,7 +4,8 @@ from unittest import mock from django.core.management.base import OutputWrapper from django.db.migrations.questioner import ( - InteractiveMigrationQuestioner, MigrationQuestioner, + InteractiveMigrationQuestioner, + MigrationQuestioner, ) from django.db.models import NOT_PROVIDED from django.test import SimpleTestCase @@ -13,21 +14,25 @@ from django.test.utils import override_settings class QuestionerTests(SimpleTestCase): @override_settings( - INSTALLED_APPS=['migrations'], - MIGRATION_MODULES={'migrations': None}, + INSTALLED_APPS=["migrations"], + MIGRATION_MODULES={"migrations": None}, ) def test_ask_initial_with_disabled_migrations(self): questioner = MigrationQuestioner() - self.assertIs(False, questioner.ask_initial('migrations')) + self.assertIs(False, questioner.ask_initial("migrations")) def test_ask_not_null_alteration(self): questioner = MigrationQuestioner() - self.assertIsNone(questioner.ask_not_null_alteration('field_name', 'model_name')) + self.assertIsNone( + questioner.ask_not_null_alteration("field_name", "model_name") + ) - @mock.patch('builtins.input', return_value='2') + @mock.patch("builtins.input", return_value="2") def test_ask_not_null_alteration_not_provided(self, mock): - questioner = InteractiveMigrationQuestioner(prompt_output=OutputWrapper(StringIO())) - question = questioner.ask_not_null_alteration('field_name', 'model_name') + questioner = InteractiveMigrationQuestioner( + prompt_output=OutputWrapper(StringIO()) + ) + question = questioner.ask_not_null_alteration("field_name", "model_name") self.assertEqual(question, NOT_PROVIDED) @@ -36,17 +41,17 @@ class QuestionerHelperMethodsTests(SimpleTestCase): self.prompt = OutputWrapper(StringIO()) self.questioner = InteractiveMigrationQuestioner(prompt_output=self.prompt) - @mock.patch('builtins.input', return_value='datetime.timedelta(days=1)') + @mock.patch("builtins.input", return_value="datetime.timedelta(days=1)") def test_questioner_default_timedelta(self, mock_input): value = self.questioner._ask_default() self.assertEqual(value, datetime.timedelta(days=1)) - @mock.patch('builtins.input', return_value='') + @mock.patch("builtins.input", return_value="") def test_questioner_default_no_user_entry(self, mock_input): - value = self.questioner._ask_default(default='datetime.timedelta(days=1)') + value = self.questioner._ask_default(default="datetime.timedelta(days=1)") self.assertEqual(value, datetime.timedelta(days=1)) - @mock.patch('builtins.input', side_effect=['', 'exit']) + @mock.patch("builtins.input", side_effect=["", "exit"]) def test_questioner_no_default_no_user_entry(self, mock_input): with self.assertRaises(SystemExit): self.questioner._ask_default() @@ -55,31 +60,26 @@ class QuestionerHelperMethodsTests(SimpleTestCase): self.prompt.getvalue(), ) - @mock.patch('builtins.input', side_effect=['bad code', 'exit']) + @mock.patch("builtins.input", side_effect=["bad code", "exit"]) def test_questioner_no_default_bad_user_entry_code(self, mock_input): with self.assertRaises(SystemExit): self.questioner._ask_default() - self.assertIn('Invalid input: ', self.prompt.getvalue()) + self.assertIn("Invalid input: ", self.prompt.getvalue()) - @mock.patch('builtins.input', side_effect=['', 'n']) + @mock.patch("builtins.input", side_effect=["", "n"]) def test_questioner_no_default_no_user_entry_boolean(self, mock_input): - value = self.questioner._boolean_input('Proceed?') + value = self.questioner._boolean_input("Proceed?") self.assertIs(value, False) - @mock.patch('builtins.input', return_value='') + @mock.patch("builtins.input", return_value="") def test_questioner_default_no_user_entry_boolean(self, mock_input): - value = self.questioner._boolean_input('Proceed?', default=True) + value = self.questioner._boolean_input("Proceed?", default=True) self.assertIs(value, True) - @mock.patch('builtins.input', side_effect=[10, 'garbage', 1]) + @mock.patch("builtins.input", side_effect=[10, "garbage", 1]) def test_questioner_bad_user_choice(self, mock_input): - question = 'Make a choice:' - value = self.questioner._choice_input(question, choices='abc') - expected_msg = ( - f'{question}\n' - f' 1) a\n' - f' 2) b\n' - f' 3) c\n' - ) + question = "Make a choice:" + value = self.questioner._choice_input(question, choices="abc") + expected_msg = f"{question}\n" f" 1) a\n" f" 2) b\n" f" 3) c\n" self.assertIn(expected_msg, self.prompt.getvalue()) self.assertEqual(value, 1) diff --git a/tests/migrations/test_state.py b/tests/migrations/test_state.py index 9536f19e83..dfb17ae7d8 100644 --- a/tests/migrations/test_state.py +++ b/tests/migrations/test_state.py @@ -3,16 +3,24 @@ from django.contrib.contenttypes.fields import GenericForeignKey from django.db import models from django.db.migrations.exceptions import InvalidBasesError from django.db.migrations.operations import ( - AddField, AlterField, DeleteModel, RemoveField, + AddField, + AlterField, + DeleteModel, + RemoveField, ) from django.db.migrations.state import ( - ModelState, ProjectState, get_related_models_recursive, + ModelState, + ProjectState, + get_related_models_recursive, ) from django.test import SimpleTestCase, override_settings from django.test.utils import isolate_apps from .models import ( - FoodManager, FoodQuerySet, ModelWithCustomBase, NoMigrationFoodManager, + FoodManager, + FoodQuerySet, + ModelWithCustomBase, + NoMigrationFoodManager, UnicodeModel, ) @@ -64,42 +72,41 @@ class StateTests(SimpleTestCase): apps = new_apps verbose_name = "tome" db_table = "test_tome" - indexes = [models.Index(fields=['title'])] + indexes = [models.Index(fields=["title"])] class Food(models.Model): - food_mgr = FoodManager('a', 'b') + food_mgr = FoodManager("a", "b") food_qs = FoodQuerySet.as_manager() - food_no_mgr = NoMigrationFoodManager('x', 'y') + food_no_mgr = NoMigrationFoodManager("x", "y") class Meta: app_label = "migrations" apps = new_apps class FoodNoManagers(models.Model): - class Meta: app_label = "migrations" apps = new_apps class FoodNoDefaultManager(models.Model): - food_no_mgr = NoMigrationFoodManager('x', 'y') - food_mgr = FoodManager('a', 'b') + food_no_mgr = NoMigrationFoodManager("x", "y") + food_mgr = FoodManager("a", "b") food_qs = FoodQuerySet.as_manager() class Meta: app_label = "migrations" apps = new_apps - mgr1 = FoodManager('a', 'b') - mgr2 = FoodManager('x', 'y', c=3, d=4) + mgr1 = FoodManager("a", "b") + mgr2 = FoodManager("x", "y", c=3, d=4) class FoodOrderedManagers(models.Model): # The managers on this model should be ordered by their creation # counter and not by the order in model body - food_no_mgr = NoMigrationFoodManager('x', 'y') + food_no_mgr = NoMigrationFoodManager("x", "y") food_mgr2 = mgr2 food_mgr1 = mgr1 @@ -108,23 +115,27 @@ class StateTests(SimpleTestCase): apps = new_apps project_state = ProjectState.from_apps(new_apps) - author_state = project_state.models['migrations', 'author'] - author_proxy_state = project_state.models['migrations', 'authorproxy'] - sub_author_state = project_state.models['migrations', 'subauthor'] - book_state = project_state.models['migrations', 'book'] - food_state = project_state.models['migrations', 'food'] - food_no_managers_state = project_state.models['migrations', 'foodnomanagers'] - food_no_default_manager_state = project_state.models['migrations', 'foodnodefaultmanager'] - food_order_manager_state = project_state.models['migrations', 'foodorderedmanagers'] - book_index = models.Index(fields=['title']) + author_state = project_state.models["migrations", "author"] + author_proxy_state = project_state.models["migrations", "authorproxy"] + sub_author_state = project_state.models["migrations", "subauthor"] + book_state = project_state.models["migrations", "book"] + food_state = project_state.models["migrations", "food"] + food_no_managers_state = project_state.models["migrations", "foodnomanagers"] + food_no_default_manager_state = project_state.models[ + "migrations", "foodnodefaultmanager" + ] + food_order_manager_state = project_state.models[ + "migrations", "foodorderedmanagers" + ] + book_index = models.Index(fields=["title"]) book_index.set_name_with_model(Book) self.assertEqual(author_state.app_label, "migrations") self.assertEqual(author_state.name, "Author") self.assertEqual(list(author_state.fields), ["id", "name", "bio", "age"]) - self.assertEqual(author_state.fields['name'].max_length, 255) - self.assertIs(author_state.fields['bio'].null, False) - self.assertIs(author_state.fields['age'].null, True) + self.assertEqual(author_state.fields["name"].max_length, 255) + self.assertIs(author_state.fields["bio"].null, False) + self.assertIs(author_state.fields["age"].null, True) self.assertEqual( author_state.options, { @@ -132,19 +143,28 @@ class StateTests(SimpleTestCase): "index_together": {("bio", "age")}, "indexes": [], "constraints": [], - } + }, ) self.assertEqual(author_state.bases, (models.Model,)) self.assertEqual(book_state.app_label, "migrations") self.assertEqual(book_state.name, "Book") - self.assertEqual(list(book_state.fields), ["id", "title", "author", "contributors"]) - self.assertEqual(book_state.fields['title'].max_length, 1000) - self.assertIs(book_state.fields['author'].null, False) - self.assertEqual(book_state.fields['contributors'].__class__.__name__, 'ManyToManyField') + self.assertEqual( + list(book_state.fields), ["id", "title", "author", "contributors"] + ) + self.assertEqual(book_state.fields["title"].max_length, 1000) + self.assertIs(book_state.fields["author"].null, False) + self.assertEqual( + book_state.fields["contributors"].__class__.__name__, "ManyToManyField" + ) self.assertEqual( book_state.options, - {"verbose_name": "tome", "db_table": "test_tome", "indexes": [book_index], "constraints": []}, + { + "verbose_name": "tome", + "db_table": "test_tome", + "indexes": [book_index], + "constraints": [], + }, ) self.assertEqual(book_state.bases, (models.Model,)) @@ -163,33 +183,50 @@ class StateTests(SimpleTestCase): self.assertEqual(sub_author_state.bases, ("migrations.author",)) # The default manager is used in migrations - self.assertEqual([name for name, mgr in food_state.managers], ['food_mgr']) + self.assertEqual([name for name, mgr in food_state.managers], ["food_mgr"]) self.assertTrue(all(isinstance(name, str) for name, mgr in food_state.managers)) - self.assertEqual(food_state.managers[0][1].args, ('a', 'b', 1, 2)) + self.assertEqual(food_state.managers[0][1].args, ("a", "b", 1, 2)) # No explicit managers defined. Migrations will fall back to the default self.assertEqual(food_no_managers_state.managers, []) # food_mgr is used in migration but isn't the default mgr, hence add the # default - self.assertEqual([name for name, mgr in food_no_default_manager_state.managers], - ['food_no_mgr', 'food_mgr']) - self.assertTrue(all(isinstance(name, str) for name, mgr in food_no_default_manager_state.managers)) - self.assertEqual(food_no_default_manager_state.managers[0][1].__class__, models.Manager) + self.assertEqual( + [name for name, mgr in food_no_default_manager_state.managers], + ["food_no_mgr", "food_mgr"], + ) + self.assertTrue( + all( + isinstance(name, str) + for name, mgr in food_no_default_manager_state.managers + ) + ) + self.assertEqual( + food_no_default_manager_state.managers[0][1].__class__, models.Manager + ) self.assertIsInstance(food_no_default_manager_state.managers[1][1], FoodManager) - self.assertEqual([name for name, mgr in food_order_manager_state.managers], - ['food_mgr1', 'food_mgr2']) - self.assertTrue(all(isinstance(name, str) for name, mgr in food_order_manager_state.managers)) - self.assertEqual([mgr.args for name, mgr in food_order_manager_state.managers], - [('a', 'b', 1, 2), ('x', 'y', 3, 4)]) + self.assertEqual( + [name for name, mgr in food_order_manager_state.managers], + ["food_mgr1", "food_mgr2"], + ) + self.assertTrue( + all( + isinstance(name, str) for name, mgr in food_order_manager_state.managers + ) + ) + self.assertEqual( + [mgr.args for name, mgr in food_order_manager_state.managers], + [("a", "b", 1, 2), ("x", "y", 3, 4)], + ) def test_custom_default_manager_added_to_the_model_state(self): """ When the default manager of the model is a custom manager, it needs to be added to the model state. """ - new_apps = Apps(['migrations']) + new_apps = Apps(["migrations"]) custom_manager = models.Manager() class Author(models.Model): @@ -197,12 +234,12 @@ class StateTests(SimpleTestCase): authors = custom_manager class Meta: - app_label = 'migrations' + app_label = "migrations" apps = new_apps project_state = ProjectState.from_apps(new_apps) - author_state = project_state.models['migrations', 'author'] - self.assertEqual(author_state.managers, [('authors', custom_manager)]) + author_state = project_state.models["migrations", "author"] + self.assertEqual(author_state.managers, [("authors", custom_manager)]) def test_custom_default_manager_named_objects_with_false_migration_flag(self): """ @@ -210,17 +247,17 @@ class StateTests(SimpleTestCase): have `use_in_migrations = True`, no migration should be added to the model state (#26643). """ - new_apps = Apps(['migrations']) + new_apps = Apps(["migrations"]) class Author(models.Model): objects = models.Manager() class Meta: - app_label = 'migrations' + app_label = "migrations" apps = new_apps project_state = ProjectState.from_apps(new_apps) - author_state = project_state.models['migrations', 'author'] + author_state = project_state.models["migrations", "author"] self.assertEqual(author_state.managers, []) def test_no_duplicate_managers(self): @@ -229,7 +266,7 @@ class StateTests(SimpleTestCase): model had a manager with the same name and `use_in_migrations = True`, the parent's manager shouldn't appear in the model state (#26881). """ - new_apps = Apps(['migrations']) + new_apps = Apps(["migrations"]) class PersonManager(models.Manager): use_in_migrations = True @@ -247,65 +284,71 @@ class StateTests(SimpleTestCase): objects = BossManager() class Meta: - app_label = 'migrations' + app_label = "migrations" apps = new_apps project_state = ProjectState.from_apps(new_apps) - boss_state = project_state.models['migrations', 'boss'] - self.assertEqual(boss_state.managers, [('objects', Boss.objects)]) + boss_state = project_state.models["migrations", "boss"] + self.assertEqual(boss_state.managers, [("objects", Boss.objects)]) def test_custom_default_manager(self): - new_apps = Apps(['migrations']) + new_apps = Apps(["migrations"]) class Author(models.Model): manager1 = models.Manager() manager2 = models.Manager() class Meta: - app_label = 'migrations' + app_label = "migrations" apps = new_apps - default_manager_name = 'manager2' + default_manager_name = "manager2" project_state = ProjectState.from_apps(new_apps) - author_state = project_state.models['migrations', 'author'] - self.assertEqual(author_state.options['default_manager_name'], 'manager2') - self.assertEqual(author_state.managers, [('manager2', Author.manager1)]) + author_state = project_state.models["migrations", "author"] + self.assertEqual(author_state.options["default_manager_name"], "manager2") + self.assertEqual(author_state.managers, [("manager2", Author.manager1)]) def test_custom_base_manager(self): - new_apps = Apps(['migrations']) + new_apps = Apps(["migrations"]) class Author(models.Model): manager1 = models.Manager() manager2 = models.Manager() class Meta: - app_label = 'migrations' + app_label = "migrations" apps = new_apps - base_manager_name = 'manager2' + base_manager_name = "manager2" class Author2(models.Model): manager1 = models.Manager() manager2 = models.Manager() class Meta: - app_label = 'migrations' + app_label = "migrations" apps = new_apps - base_manager_name = 'manager1' + base_manager_name = "manager1" project_state = ProjectState.from_apps(new_apps) - author_state = project_state.models['migrations', 'author'] - self.assertEqual(author_state.options['base_manager_name'], 'manager2') - self.assertEqual(author_state.managers, [ - ('manager1', Author.manager1), - ('manager2', Author.manager2), - ]) + author_state = project_state.models["migrations", "author"] + self.assertEqual(author_state.options["base_manager_name"], "manager2") + self.assertEqual( + author_state.managers, + [ + ("manager1", Author.manager1), + ("manager2", Author.manager2), + ], + ) - author2_state = project_state.models['migrations', 'author2'] - self.assertEqual(author2_state.options['base_manager_name'], 'manager1') - self.assertEqual(author2_state.managers, [ - ('manager1', Author2.manager1), - ]) + author2_state = project_state.models["migrations", "author2"] + self.assertEqual(author2_state.options["base_manager_name"], "manager1") + self.assertEqual( + author2_state.managers, + [ + ("manager1", Author2.manager1), + ], + ) def test_apps_bulk_update(self): """ @@ -328,62 +371,83 @@ class StateTests(SimpleTestCase): Tests rendering a ProjectState into an Apps. """ project_state = ProjectState() - project_state.add_model(ModelState( - app_label="migrations", - name="Tag", - fields=[ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=100)), - ("hidden", models.BooleanField()), - ], - )) - project_state.add_model(ModelState( - app_label="migrations", - name="SubTag", - fields=[ - ('tag_ptr', models.OneToOneField( - 'migrations.Tag', - models.CASCADE, - auto_created=True, - parent_link=True, - primary_key=True, - to_field='id', - serialize=False, - )), - ("awesome", models.BooleanField()), - ], - bases=("migrations.Tag",), - )) + project_state.add_model( + ModelState( + app_label="migrations", + name="Tag", + fields=[ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=100)), + ("hidden", models.BooleanField()), + ], + ) + ) + project_state.add_model( + ModelState( + app_label="migrations", + name="SubTag", + fields=[ + ( + "tag_ptr", + models.OneToOneField( + "migrations.Tag", + models.CASCADE, + auto_created=True, + parent_link=True, + primary_key=True, + to_field="id", + serialize=False, + ), + ), + ("awesome", models.BooleanField()), + ], + bases=("migrations.Tag",), + ) + ) base_mgr = models.Manager() - mgr1 = FoodManager('a', 'b') - mgr2 = FoodManager('x', 'y', c=3, d=4) - project_state.add_model(ModelState( - app_label="migrations", - name="Food", - fields=[ - ("id", models.AutoField(primary_key=True)), - ], - managers=[ - # The ordering we really want is objects, mgr1, mgr2 - ('default', base_mgr), - ('food_mgr2', mgr2), - ('food_mgr1', mgr1), - ] - )) + mgr1 = FoodManager("a", "b") + mgr2 = FoodManager("x", "y", c=3, d=4) + project_state.add_model( + ModelState( + app_label="migrations", + name="Food", + fields=[ + ("id", models.AutoField(primary_key=True)), + ], + managers=[ + # The ordering we really want is objects, mgr1, mgr2 + ("default", base_mgr), + ("food_mgr2", mgr2), + ("food_mgr1", mgr1), + ], + ) + ) new_apps = project_state.apps - self.assertEqual(new_apps.get_model("migrations", "Tag")._meta.get_field("name").max_length, 100) - self.assertIs(new_apps.get_model("migrations", "Tag")._meta.get_field("hidden").null, False) + self.assertEqual( + new_apps.get_model("migrations", "Tag")._meta.get_field("name").max_length, + 100, + ) + self.assertIs( + new_apps.get_model("migrations", "Tag")._meta.get_field("hidden").null, + False, + ) - self.assertEqual(len(new_apps.get_model("migrations", "SubTag")._meta.local_fields), 2) + self.assertEqual( + len(new_apps.get_model("migrations", "SubTag")._meta.local_fields), 2 + ) Food = new_apps.get_model("migrations", "Food") - self.assertEqual([mgr.name for mgr in Food._meta.managers], - ['default', 'food_mgr1', 'food_mgr2']) + self.assertEqual( + [mgr.name for mgr in Food._meta.managers], + ["default", "food_mgr1", "food_mgr2"], + ) self.assertTrue(all(isinstance(mgr.name, str) for mgr in Food._meta.managers)) - self.assertEqual([mgr.__class__ for mgr in Food._meta.managers], - [models.Manager, FoodManager, FoodManager]) + self.assertEqual( + [mgr.__class__ for mgr in Food._meta.managers], + [models.Manager, FoodManager, FoodManager], + ) def test_render_model_inheritance(self): class Book(models.Model): @@ -449,9 +513,13 @@ class StateTests(SimpleTestCase): ModelState.from_model(Bar).render(apps) self.assertSequenceEqual(ModelState.from_model(Bar).bases, [models.Model]) ModelState.from_model(FooBar).render(apps) - self.assertSequenceEqual(ModelState.from_model(FooBar).bases, ['migrations.foo', 'migrations.bar']) + self.assertSequenceEqual( + ModelState.from_model(FooBar).bases, ["migrations.foo", "migrations.bar"] + ) ModelState.from_model(SubFooBar).render(apps) - self.assertSequenceEqual(ModelState.from_model(SubFooBar).bases, ['migrations.foobar']) + self.assertSequenceEqual( + ModelState.from_model(SubFooBar).bases, ["migrations.foobar"] + ) def test_render_project_dependencies(self): """ @@ -518,6 +586,7 @@ class StateTests(SimpleTestCase): ImproperlyConfigured exception about unique labels if two dotted app names have the same last part. """ + class A(models.Model): class Meta: app_label = "django.contrib.auth" @@ -539,50 +608,80 @@ class StateTests(SimpleTestCase): """ project_state = ProjectState() project_state.apps # Render project state. - project_state.add_model(ModelState('migrations', 'A', [])) - project_state.add_model(ModelState('migrations', 'B', [ - ('a', models.ForeignKey('A', models.CASCADE)), - ])) - project_state.add_model(ModelState('migrations', 'C', [ - ('b', models.ForeignKey('B', models.CASCADE)), - ('name', models.TextField()), - ])) - project_state.add_model(ModelState('migrations', 'D', [ - ('a', models.ForeignKey('A', models.CASCADE)), - ])) + project_state.add_model(ModelState("migrations", "A", [])) + project_state.add_model( + ModelState( + "migrations", + "B", + [ + ("a", models.ForeignKey("A", models.CASCADE)), + ], + ) + ) + project_state.add_model( + ModelState( + "migrations", + "C", + [ + ("b", models.ForeignKey("B", models.CASCADE)), + ("name", models.TextField()), + ], + ) + ) + project_state.add_model( + ModelState( + "migrations", + "D", + [ + ("a", models.ForeignKey("A", models.CASCADE)), + ], + ) + ) operation = AlterField( - model_name='C', - name='name', + model_name="C", + name="name", field=models.TextField(blank=True), ) - operation.state_forwards('migrations', project_state) - project_state.reload_model('migrations', 'a', delay=True) - A = project_state.apps.get_model('migrations.A') - B = project_state.apps.get_model('migrations.B') - D = project_state.apps.get_model('migrations.D') - self.assertIs(B._meta.get_field('a').related_model, A) - self.assertIs(D._meta.get_field('a').related_model, A) + operation.state_forwards("migrations", project_state) + project_state.reload_model("migrations", "a", delay=True) + A = project_state.apps.get_model("migrations.A") + B = project_state.apps.get_model("migrations.B") + D = project_state.apps.get_model("migrations.D") + self.assertIs(B._meta.get_field("a").related_model, A) + self.assertIs(D._meta.get_field("a").related_model, A) def test_reload_model_relationship_consistency(self): project_state = ProjectState() - project_state.add_model(ModelState('migrations', 'A', [])) - project_state.add_model(ModelState('migrations', 'B', [ - ('a', models.ForeignKey('A', models.CASCADE)), - ])) - project_state.add_model(ModelState('migrations', 'C', [ - ('b', models.ForeignKey('B', models.CASCADE)), - ])) - A = project_state.apps.get_model('migrations.A') - B = project_state.apps.get_model('migrations.B') - C = project_state.apps.get_model('migrations.C') + project_state.add_model(ModelState("migrations", "A", [])) + project_state.add_model( + ModelState( + "migrations", + "B", + [ + ("a", models.ForeignKey("A", models.CASCADE)), + ], + ) + ) + project_state.add_model( + ModelState( + "migrations", + "C", + [ + ("b", models.ForeignKey("B", models.CASCADE)), + ], + ) + ) + A = project_state.apps.get_model("migrations.A") + B = project_state.apps.get_model("migrations.B") + C = project_state.apps.get_model("migrations.C") self.assertEqual([r.related_model for r in A._meta.related_objects], [B]) self.assertEqual([r.related_model for r in B._meta.related_objects], [C]) self.assertEqual([r.related_model for r in C._meta.related_objects], []) - project_state.reload_model('migrations', 'a', delay=True) - A = project_state.apps.get_model('migrations.A') - B = project_state.apps.get_model('migrations.B') - C = project_state.apps.get_model('migrations.C') + project_state.reload_model("migrations", "a", delay=True) + A = project_state.apps.get_model("migrations.A") + B = project_state.apps.get_model("migrations.B") + C = project_state.apps.get_model("migrations.C") self.assertEqual([r.related_model for r in A._meta.related_objects], [B]) self.assertEqual([r.related_model for r in B._meta.related_objects], [C]) self.assertEqual([r.related_model for r in C._meta.related_objects], []) @@ -596,17 +695,17 @@ class StateTests(SimpleTestCase): class A(models.Model): class Meta: - app_label = 'something' + app_label = "something" apps = new_apps class B(A): class Meta: - app_label = 'something' + app_label = "something" apps = new_apps class C(models.Model): class Meta: - app_label = 'something' + app_label = "something" apps = new_apps project_state = ProjectState() @@ -617,35 +716,39 @@ class StateTests(SimpleTestCase): project_state.apps # We need to work with rendered models old_state = project_state.clone() - model_a_old = old_state.apps.get_model('something', 'A') - model_b_old = old_state.apps.get_model('something', 'B') - model_c_old = old_state.apps.get_model('something', 'C') + model_a_old = old_state.apps.get_model("something", "A") + model_b_old = old_state.apps.get_model("something", "B") + model_c_old = old_state.apps.get_model("something", "C") # The relations between the old models are correct - self.assertIs(model_a_old._meta.get_field('b').related_model, model_b_old) - self.assertIs(model_b_old._meta.get_field('a_ptr').related_model, model_a_old) + self.assertIs(model_a_old._meta.get_field("b").related_model, model_b_old) + self.assertIs(model_b_old._meta.get_field("a_ptr").related_model, model_a_old) - operation = AddField('c', 'to_a', models.OneToOneField( - 'something.A', - models.CASCADE, - related_name='from_c', - )) - operation.state_forwards('something', project_state) - model_a_new = project_state.apps.get_model('something', 'A') - model_b_new = project_state.apps.get_model('something', 'B') - model_c_new = project_state.apps.get_model('something', 'C') + operation = AddField( + "c", + "to_a", + models.OneToOneField( + "something.A", + models.CASCADE, + related_name="from_c", + ), + ) + operation.state_forwards("something", project_state) + model_a_new = project_state.apps.get_model("something", "A") + model_b_new = project_state.apps.get_model("something", "B") + model_c_new = project_state.apps.get_model("something", "C") # All models have changed self.assertIsNot(model_a_old, model_a_new) self.assertIsNot(model_b_old, model_b_new) self.assertIsNot(model_c_old, model_c_new) # The relations between the old models still hold - self.assertIs(model_a_old._meta.get_field('b').related_model, model_b_old) - self.assertIs(model_b_old._meta.get_field('a_ptr').related_model, model_a_old) + self.assertIs(model_a_old._meta.get_field("b").related_model, model_b_old) + self.assertIs(model_b_old._meta.get_field("a_ptr").related_model, model_a_old) # The relations between the new models correct - self.assertIs(model_a_new._meta.get_field('b').related_model, model_b_new) - self.assertIs(model_b_new._meta.get_field('a_ptr').related_model, model_a_new) - self.assertIs(model_a_new._meta.get_field('from_c').related_model, model_c_new) - self.assertIs(model_c_new._meta.get_field('to_a').related_model, model_a_new) + self.assertIs(model_a_new._meta.get_field("b").related_model, model_b_new) + self.assertIs(model_b_new._meta.get_field("a_ptr").related_model, model_a_new) + self.assertIs(model_a_new._meta.get_field("from_c").related_model, model_c_new) + self.assertIs(model_c_new._meta.get_field("to_a").related_model, model_a_new) def test_remove_relations(self): """ @@ -667,7 +770,9 @@ class StateTests(SimpleTestCase): apps = new_apps def get_model_a(state): - return [mod for mod in state.apps.get_models() if mod._meta.model_name == 'a'][0] + return [ + mod for mod in state.apps.get_models() if mod._meta.model_name == "a" + ][0] project_state = ProjectState() project_state.add_model(ModelState.from_model(A)) @@ -703,14 +808,17 @@ class StateTests(SimpleTestCase): #24513 - Modifying an object pointing to itself would cause it to be rendered twice and thus breaking its related M2M through objects. """ + class A(models.Model): - to_a = models.ManyToManyField('something.A', symmetrical=False) + to_a = models.ManyToManyField("something.A", symmetrical=False) class Meta: app_label = "something" def get_model_a(state): - return [mod for mod in state.apps.get_models() if mod._meta.model_name == 'a'][0] + return [ + mod for mod in state.apps.get_models() if mod._meta.model_name == "a" + ][0] project_state = ProjectState() project_state.add_model(ModelState.from_model(A)) @@ -720,7 +828,7 @@ class StateTests(SimpleTestCase): operation = AlterField( model_name="a", name="to_a", - field=models.ManyToManyField("something.A", symmetrical=False, blank=True) + field=models.ManyToManyField("something.A", symmetrical=False, blank=True), ) # At this point the model would be rendered twice causing its related # M2M through objects to point to an old copy and thus breaking their @@ -736,16 +844,28 @@ class StateTests(SimpleTestCase): self.assertEqual(field_to_a_old.m2m_field_name(), "from_a") self.assertEqual(field_to_a_old.m2m_reverse_field_name(), "to_a") self.assertIs(field_to_a_old.related_model, model_a_old) - self.assertIs(field_to_a_old.remote_field.through._meta.get_field('to_a').related_model, model_a_old) - self.assertIs(field_to_a_old.remote_field.through._meta.get_field('from_a').related_model, model_a_old) + self.assertIs( + field_to_a_old.remote_field.through._meta.get_field("to_a").related_model, + model_a_old, + ) + self.assertIs( + field_to_a_old.remote_field.through._meta.get_field("from_a").related_model, + model_a_old, + ) # The new model's _meta is still consistent field_to_a_new = model_a_new._meta.get_field("to_a") self.assertEqual(field_to_a_new.m2m_field_name(), "from_a") self.assertEqual(field_to_a_new.m2m_reverse_field_name(), "to_a") self.assertIs(field_to_a_new.related_model, model_a_new) - self.assertIs(field_to_a_new.remote_field.through._meta.get_field('to_a').related_model, model_a_new) - self.assertIs(field_to_a_new.remote_field.through._meta.get_field('from_a').related_model, model_a_new) + self.assertIs( + field_to_a_new.remote_field.through._meta.get_field("to_a").related_model, + model_a_new, + ) + self.assertIs( + field_to_a_new.remote_field.through._meta.get_field("from_a").related_model, + model_a_new, + ) def test_equality(self): """ @@ -753,17 +873,19 @@ class StateTests(SimpleTestCase): """ # Test two things that should be equal project_state = ProjectState() - project_state.add_model(ModelState( - "migrations", - "Tag", - [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=100)), - ("hidden", models.BooleanField()), - ], - {}, - None, - )) + project_state.add_model( + ModelState( + "migrations", + "Tag", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=100)), + ("hidden", models.BooleanField()), + ], + {}, + None, + ) + ) project_state.apps # Fill the apps cached property other_state = project_state.clone() self.assertEqual(project_state, project_state) @@ -774,17 +896,19 @@ class StateTests(SimpleTestCase): # Make a very small change (max_len 99) and see if that affects it project_state = ProjectState() - project_state.add_model(ModelState( - "migrations", - "Tag", - [ - ("id", models.AutoField(primary_key=True)), - ("name", models.CharField(max_length=99)), - ("hidden", models.BooleanField()), - ], - {}, - None, - )) + project_state.add_model( + ModelState( + "migrations", + "Tag", + [ + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=99)), + ("hidden", models.BooleanField()), + ], + {}, + None, + ) + ) self.assertNotEqual(project_state, other_state) self.assertIs(project_state == other_state, False) @@ -845,9 +969,9 @@ class StateTests(SimpleTestCase): project_state.add_model(ModelState.from_model(Magazine)) msg = ( "The field migrations.Magazine.authors was declared with a lazy reference " - "to 'migrations.author\', but app 'migrations' doesn't provide model 'author'.\n" + "to 'migrations.author', but app 'migrations' doesn't provide model 'author'.\n" "The field migrations.Magazine_authors.author was declared with a lazy reference " - "to \'migrations.author\', but app 'migrations' doesn't provide model 'author'." + "to 'migrations.author', but app 'migrations' doesn't provide model 'author'." ) with self.assertRaisesMessage(ValueError, msg): project_state.apps @@ -872,21 +996,21 @@ class StateTests(SimpleTestCase): class Author(models.Model): class Meta: - app_label = 'MiXedCase_migrations' + app_label = "MiXedCase_migrations" apps = new_apps class Book(models.Model): author = models.ForeignKey(Author, models.CASCADE) class Meta: - app_label = 'MiXedCase_migrations' + app_label = "MiXedCase_migrations" apps = new_apps class Magazine(models.Model): authors = models.ManyToManyField(Author) class Meta: - app_label = 'MiXedCase_migrations' + app_label = "MiXedCase_migrations" apps = new_apps project_state = ProjectState() @@ -916,17 +1040,23 @@ class StateTests(SimpleTestCase): project_state.apps # If we include the real app it should succeed - project_state = ProjectState(real_apps={'contenttypes'}) + project_state = ProjectState(real_apps={"contenttypes"}) project_state.add_model(ModelState.from_model(TestModel)) rendered_state = project_state.apps self.assertEqual( - len([x for x in rendered_state.get_models() if x._meta.app_label == "migrations"]), + len( + [ + x + for x in rendered_state.get_models() + if x._meta.app_label == "migrations" + ] + ), 1, ) def test_real_apps_non_set(self): with self.assertRaises(AssertionError): - ProjectState(real_apps=['contenttypes']) + ProjectState(real_apps=["contenttypes"]) def test_ignore_order_wrt(self): """ @@ -955,7 +1085,7 @@ class StateTests(SimpleTestCase): project_state.add_model(ModelState.from_model(Author)) project_state.add_model(ModelState.from_model(Book)) self.assertEqual( - list(project_state.models['migrations', 'book'].fields), + list(project_state.models["migrations", "book"].fields), ["id", "author"], ) @@ -966,21 +1096,21 @@ class StateTests(SimpleTestCase): name = models.TextField() class Meta: - app_label = 'migrations' + app_label = "migrations" apps = new_apps class Book(models.Model): author = models.ForeignKey(Author, models.CASCADE) class Meta: - app_label = 'migrations' + app_label = "migrations" apps = new_apps - order_with_respect_to = 'author' + order_with_respect_to = "author" model_state = ModelState.from_model(Book) - order_wrt_field = model_state.get_field('_order') + order_wrt_field = model_state.get_field("_order") self.assertIsInstance(order_wrt_field, models.ForeignKey) - self.assertEqual(order_wrt_field.related_model, 'migrations.author') + self.assertEqual(order_wrt_field.related_model, "migrations.author") def test_modelstate_get_field_no_order_wrt_order_field(self): new_apps = Apps() @@ -989,11 +1119,11 @@ class StateTests(SimpleTestCase): _order = models.PositiveSmallIntegerField() class Meta: - app_label = 'migrations' + app_label = "migrations" apps = new_apps model_state = ModelState.from_model(HistoricalRecord) - order_field = model_state.get_field('_order') + order_field = model_state.get_field("_order") self.assertIsNone(order_field.related_model) self.assertIsInstance(order_field, models.PositiveSmallIntegerField) @@ -1003,26 +1133,28 @@ class StateTests(SimpleTestCase): historical model """ project_state = ProjectState() - project_state.add_model(ModelState( - app_label="migrations", - name="Tag", - fields=[ - ("id", models.AutoField(primary_key=True)), - ("hidden", models.BooleanField()), - ], - managers=[ - ('food_mgr', FoodManager('a', 'b')), - ('food_qs', FoodQuerySet.as_manager()), - ] - )) + project_state.add_model( + ModelState( + app_label="migrations", + name="Tag", + fields=[ + ("id", models.AutoField(primary_key=True)), + ("hidden", models.BooleanField()), + ], + managers=[ + ("food_mgr", FoodManager("a", "b")), + ("food_qs", FoodQuerySet.as_manager()), + ], + ) + ) - old_model = project_state.apps.get_model('migrations', 'tag') + old_model = project_state.apps.get_model("migrations", "tag") new_state = project_state.clone() operation = RemoveField("tag", "hidden") operation.state_forwards("migrations", new_state) - new_model = new_state.apps.get_model('migrations', 'tag') + new_model = new_state.apps.get_model("migrations", "tag") self.assertIsNot(old_model, new_model) self.assertIs(old_model, old_model.food_mgr.model) @@ -1040,7 +1172,7 @@ class StateTests(SimpleTestCase): Field.choices iterators. """ new_apps = Apps(["migrations"]) - choices = [('a', 'A'), ('b', 'B')] + choices = [("a", "A"), ("b", "B")] class Author(models.Model): name = models.CharField(max_length=255) @@ -1051,7 +1183,7 @@ class StateTests(SimpleTestCase): apps = new_apps ProjectState.from_apps(new_apps) - choices_field = Author._meta.get_field('choice') + choices_field = Author._meta.get_field("choice") self.assertEqual(list(choices_field.choices), choices) @@ -1061,16 +1193,16 @@ class StateRelationsTests(SimpleTestCase): class User(models.Model): class Meta: - app_label = 'tests' + app_label = "tests" apps = new_apps class Comment(models.Model): text = models.TextField() user = models.ForeignKey(User, models.CASCADE) - comments = models.ManyToManyField('self') + comments = models.ManyToManyField("self") class Meta: - app_label = 'tests' + app_label = "tests" apps = new_apps class Post(models.Model): @@ -1078,7 +1210,7 @@ class StateRelationsTests(SimpleTestCase): authors = models.ManyToManyField(User) class Meta: - app_label = 'tests' + app_label = "tests" apps = new_apps project_state = ProjectState() @@ -1089,31 +1221,40 @@ class StateRelationsTests(SimpleTestCase): def test_relations_population(self): tests = [ - ('add_model', [ - ModelState( - app_label='migrations', - name='Tag', - fields=[('id', models.AutoField(primary_key=True))], - ), - ]), - ('remove_model', ['tests', 'comment']), - ('rename_model', ['tests', 'comment', 'opinion']), - ('add_field', [ - 'tests', - 'post', - 'next_post', - models.ForeignKey('self', models.CASCADE), - True, - ]), - ('remove_field', ['tests', 'post', 'text']), - ('rename_field', ['tests', 'comment', 'user', 'author']), - ('alter_field', [ - 'tests', - 'comment', - 'user', - models.IntegerField(), - True, - ]), + ( + "add_model", + [ + ModelState( + app_label="migrations", + name="Tag", + fields=[("id", models.AutoField(primary_key=True))], + ), + ], + ), + ("remove_model", ["tests", "comment"]), + ("rename_model", ["tests", "comment", "opinion"]), + ( + "add_field", + [ + "tests", + "post", + "next_post", + models.ForeignKey("self", models.CASCADE), + True, + ], + ), + ("remove_field", ["tests", "post", "text"]), + ("rename_field", ["tests", "comment", "user", "author"]), + ( + "alter_field", + [ + "tests", + "comment", + "user", + models.IntegerField(), + True, + ], + ), ] for method, args in tests: with self.subTest(method=method): @@ -1127,328 +1268,366 @@ class StateRelationsTests(SimpleTestCase): def test_add_model(self): project_state = self.get_base_project_state() self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'comment'), ('tests', 'post')], + list(project_state.relations["tests", "user"]), + [("tests", "comment"), ("tests", "post")], ) self.assertEqual( - list(project_state.relations['tests', 'comment']), - [('tests', 'comment')], + list(project_state.relations["tests", "comment"]), + [("tests", "comment")], ) - self.assertNotIn(('tests', 'post'), project_state.relations) + self.assertNotIn(("tests", "post"), project_state.relations) def test_add_model_no_relations(self): project_state = ProjectState() - project_state.add_model(ModelState( - app_label='migrations', - name='Tag', - fields=[('id', models.AutoField(primary_key=True))], - )) + project_state.add_model( + ModelState( + app_label="migrations", + name="Tag", + fields=[("id", models.AutoField(primary_key=True))], + ) + ) self.assertEqual(project_state.relations, {}) def test_add_model_other_app(self): project_state = self.get_base_project_state() self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'comment'), ('tests', 'post')], + list(project_state.relations["tests", "user"]), + [("tests", "comment"), ("tests", "post")], + ) + project_state.add_model( + ModelState( + app_label="tests_other", + name="comment", + fields=[ + ("id", models.AutoField(primary_key=True)), + ("user", models.ForeignKey("tests.user", models.CASCADE)), + ], + ) ) - project_state.add_model(ModelState( - app_label='tests_other', - name='comment', - fields=[ - ('id', models.AutoField(primary_key=True)), - ('user', models.ForeignKey('tests.user', models.CASCADE)), - ], - )) self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'comment'), ('tests', 'post'), ('tests_other', 'comment')], + list(project_state.relations["tests", "user"]), + [("tests", "comment"), ("tests", "post"), ("tests_other", "comment")], ) def test_remove_model(self): project_state = self.get_base_project_state() self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'comment'), ('tests', 'post')], + list(project_state.relations["tests", "user"]), + [("tests", "comment"), ("tests", "post")], ) self.assertEqual( - list(project_state.relations['tests', 'comment']), - [('tests', 'comment')], + list(project_state.relations["tests", "comment"]), + [("tests", "comment")], ) - project_state.remove_model('tests', 'comment') + project_state.remove_model("tests", "comment") self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'post')], + list(project_state.relations["tests", "user"]), + [("tests", "post")], ) - self.assertNotIn(('tests', 'comment'), project_state.relations) - project_state.remove_model('tests', 'post') + self.assertNotIn(("tests", "comment"), project_state.relations) + project_state.remove_model("tests", "post") self.assertEqual(project_state.relations, {}) - project_state.remove_model('tests', 'user') + project_state.remove_model("tests", "user") self.assertEqual(project_state.relations, {}) def test_rename_model(self): project_state = self.get_base_project_state() self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'comment'), ('tests', 'post')], + list(project_state.relations["tests", "user"]), + [("tests", "comment"), ("tests", "post")], ) self.assertEqual( - list(project_state.relations['tests', 'comment']), - [('tests', 'comment')], + list(project_state.relations["tests", "comment"]), + [("tests", "comment")], ) - related_field = project_state.relations['tests', 'user']['tests', 'comment'] - project_state.rename_model('tests', 'comment', 'opinion') + related_field = project_state.relations["tests", "user"]["tests", "comment"] + project_state.rename_model("tests", "comment", "opinion") self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'post'), ('tests', 'opinion')], + list(project_state.relations["tests", "user"]), + [("tests", "post"), ("tests", "opinion")], ) self.assertEqual( - list(project_state.relations['tests', 'opinion']), - [('tests', 'opinion')], + list(project_state.relations["tests", "opinion"]), + [("tests", "opinion")], ) - self.assertNotIn(('tests', 'comment'), project_state.relations) + self.assertNotIn(("tests", "comment"), project_state.relations) self.assertEqual( - project_state.relations['tests', 'user']['tests', 'opinion'], + project_state.relations["tests", "user"]["tests", "opinion"], related_field, ) - project_state.rename_model('tests', 'user', 'author') + project_state.rename_model("tests", "user", "author") self.assertEqual( - list(project_state.relations['tests', 'author']), - [('tests', 'post'), ('tests', 'opinion')], + list(project_state.relations["tests", "author"]), + [("tests", "post"), ("tests", "opinion")], ) - self.assertNotIn(('tests', 'user'), project_state.relations) + self.assertNotIn(("tests", "user"), project_state.relations) def test_rename_model_no_relations(self): project_state = self.get_base_project_state() self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'comment'), ('tests', 'post')], + list(project_state.relations["tests", "user"]), + [("tests", "comment"), ("tests", "post")], ) - related_field = project_state.relations['tests', 'user']['tests', 'post'] - self.assertNotIn(('tests', 'post'), project_state.relations) + related_field = project_state.relations["tests", "user"]["tests", "post"] + self.assertNotIn(("tests", "post"), project_state.relations) # Rename a model without relations. - project_state.rename_model('tests', 'post', 'blog') + project_state.rename_model("tests", "post", "blog") self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'comment'), ('tests', 'blog')], + list(project_state.relations["tests", "user"]), + [("tests", "comment"), ("tests", "blog")], ) - self.assertNotIn(('tests', 'blog'), project_state.relations) + self.assertNotIn(("tests", "blog"), project_state.relations) self.assertEqual( related_field, - project_state.relations['tests', 'user']['tests', 'blog'], + project_state.relations["tests", "user"]["tests", "blog"], ) def test_add_field(self): project_state = self.get_base_project_state() - self.assertNotIn(('tests', 'post'), project_state.relations) + self.assertNotIn(("tests", "post"), project_state.relations) # Add a self-referential foreign key. - new_field = models.ForeignKey('self', models.CASCADE) + new_field = models.ForeignKey("self", models.CASCADE) project_state.add_field( - 'tests', 'post', 'next_post', new_field, preserve_default=True, + "tests", + "post", + "next_post", + new_field, + preserve_default=True, ) self.assertEqual( - list(project_state.relations['tests', 'post']), - [('tests', 'post')], + list(project_state.relations["tests", "post"]), + [("tests", "post")], ) self.assertEqual( - project_state.relations['tests', 'post']['tests', 'post'], - {'next_post': new_field}, + project_state.relations["tests", "post"]["tests", "post"], + {"next_post": new_field}, ) # Add a foreign key. - new_field = models.ForeignKey('tests.post', models.CASCADE) + new_field = models.ForeignKey("tests.post", models.CASCADE) project_state.add_field( - 'tests', 'comment', 'post', new_field, preserve_default=True, + "tests", + "comment", + "post", + new_field, + preserve_default=True, ) self.assertEqual( - list(project_state.relations['tests', 'post']), - [('tests', 'post'), ('tests', 'comment')], + list(project_state.relations["tests", "post"]), + [("tests", "post"), ("tests", "comment")], ) self.assertEqual( - project_state.relations['tests', 'post']['tests', 'comment'], - {'post': new_field}, + project_state.relations["tests", "post"]["tests", "comment"], + {"post": new_field}, ) def test_add_field_m2m_with_through(self): project_state = self.get_base_project_state() - project_state.add_model(ModelState( - app_label='tests', - name='Tag', - fields=[('id', models.AutoField(primary_key=True))], - )) - project_state.add_model(ModelState( - app_label='tests', - name='PostTag', - fields=[ - ('id', models.AutoField(primary_key=True)), - ('post', models.ForeignKey('tests.post', models.CASCADE)), - ('tag', models.ForeignKey('tests.tag', models.CASCADE)), - ], - )) + project_state.add_model( + ModelState( + app_label="tests", + name="Tag", + fields=[("id", models.AutoField(primary_key=True))], + ) + ) + project_state.add_model( + ModelState( + app_label="tests", + name="PostTag", + fields=[ + ("id", models.AutoField(primary_key=True)), + ("post", models.ForeignKey("tests.post", models.CASCADE)), + ("tag", models.ForeignKey("tests.tag", models.CASCADE)), + ], + ) + ) self.assertEqual( - list(project_state.relations['tests', 'post']), - [('tests', 'posttag')], + list(project_state.relations["tests", "post"]), + [("tests", "posttag")], ) self.assertEqual( - list(project_state.relations['tests', 'tag']), - [('tests', 'posttag')], + list(project_state.relations["tests", "tag"]), + [("tests", "posttag")], ) # Add a many-to-many field with the through model. - new_field = models.ManyToManyField('tests.tag', through='tests.posttag') + new_field = models.ManyToManyField("tests.tag", through="tests.posttag") project_state.add_field( - 'tests', 'post', 'tags', new_field, preserve_default=True, + "tests", + "post", + "tags", + new_field, + preserve_default=True, ) self.assertEqual( - list(project_state.relations['tests', 'post']), - [('tests', 'posttag')], + list(project_state.relations["tests", "post"]), + [("tests", "posttag")], ) self.assertEqual( - list(project_state.relations['tests', 'tag']), - [('tests', 'posttag'), ('tests', 'post')], + list(project_state.relations["tests", "tag"]), + [("tests", "posttag"), ("tests", "post")], ) self.assertEqual( - project_state.relations['tests', 'tag']['tests', 'post'], - {'tags': new_field}, + project_state.relations["tests", "tag"]["tests", "post"], + {"tags": new_field}, ) def test_remove_field(self): project_state = self.get_base_project_state() self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'comment'), ('tests', 'post')], + list(project_state.relations["tests", "user"]), + [("tests", "comment"), ("tests", "post")], ) # Remove a many-to-many field. - project_state.remove_field('tests', 'post', 'authors') + project_state.remove_field("tests", "post", "authors") self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'comment')], + list(project_state.relations["tests", "user"]), + [("tests", "comment")], ) # Remove a foreign key. - project_state.remove_field('tests', 'comment', 'user') - self.assertEqual(project_state.relations['tests', 'user'], {}) + project_state.remove_field("tests", "comment", "user") + self.assertEqual(project_state.relations["tests", "user"], {}) def test_remove_field_no_relations(self): project_state = self.get_base_project_state() self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'comment'), ('tests', 'post')], + list(project_state.relations["tests", "user"]), + [("tests", "comment"), ("tests", "post")], ) # Remove a non-relation field. - project_state.remove_field('tests', 'post', 'text') + project_state.remove_field("tests", "post", "text") self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'comment'), ('tests', 'post')], + list(project_state.relations["tests", "user"]), + [("tests", "comment"), ("tests", "post")], ) def test_rename_field(self): project_state = self.get_base_project_state() - field = project_state.models['tests', 'comment'].fields['user'] + field = project_state.models["tests", "comment"].fields["user"] self.assertEqual( - project_state.relations['tests', 'user']['tests', 'comment'], - {'user': field}, + project_state.relations["tests", "user"]["tests", "comment"], + {"user": field}, ) - project_state.rename_field('tests', 'comment', 'user', 'author') - renamed_field = project_state.models['tests', 'comment'].fields['author'] + project_state.rename_field("tests", "comment", "user", "author") + renamed_field = project_state.models["tests", "comment"].fields["author"] self.assertEqual( - project_state.relations['tests', 'user']['tests', 'comment'], - {'author': renamed_field}, + project_state.relations["tests", "user"]["tests", "comment"], + {"author": renamed_field}, ) self.assertEqual(field, renamed_field) def test_rename_field_no_relations(self): project_state = self.get_base_project_state() self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'comment'), ('tests', 'post')], + list(project_state.relations["tests", "user"]), + [("tests", "comment"), ("tests", "post")], ) # Rename a non-relation field. - project_state.rename_field('tests', 'post', 'text', 'description') + project_state.rename_field("tests", "post", "text", "description") self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'comment'), ('tests', 'post')], + list(project_state.relations["tests", "user"]), + [("tests", "comment"), ("tests", "post")], ) def test_alter_field(self): project_state = self.get_base_project_state() self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'comment'), ('tests', 'post')], + list(project_state.relations["tests", "user"]), + [("tests", "comment"), ("tests", "post")], ) # Alter a foreign key to a non-relation field. project_state.alter_field( - 'tests', 'comment', 'user', models.IntegerField(), preserve_default=True, + "tests", + "comment", + "user", + models.IntegerField(), + preserve_default=True, ) self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'post')], + list(project_state.relations["tests", "user"]), + [("tests", "post")], ) # Alter a non-relation field to a many-to-many field. - m2m_field = models.ManyToManyField('tests.user') + m2m_field = models.ManyToManyField("tests.user") project_state.alter_field( - 'tests', 'comment', 'user', m2m_field, preserve_default=True, + "tests", + "comment", + "user", + m2m_field, + preserve_default=True, ) self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'post'), ('tests', 'comment')], + list(project_state.relations["tests", "user"]), + [("tests", "post"), ("tests", "comment")], ) self.assertEqual( - project_state.relations['tests', 'user']['tests', 'comment'], - {'user': m2m_field}, + project_state.relations["tests", "user"]["tests", "comment"], + {"user": m2m_field}, ) def test_alter_field_m2m_to_fk(self): project_state = self.get_base_project_state() - project_state.add_model(ModelState( - app_label='tests_other', - name='user_other', - fields=[('id', models.AutoField(primary_key=True))], - )) + project_state.add_model( + ModelState( + app_label="tests_other", + name="user_other", + fields=[("id", models.AutoField(primary_key=True))], + ) + ) self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'comment'), ('tests', 'post')], + list(project_state.relations["tests", "user"]), + [("tests", "comment"), ("tests", "post")], ) - self.assertNotIn(('tests_other', 'user_other'), project_state.relations) + self.assertNotIn(("tests_other", "user_other"), project_state.relations) # Alter a many-to-many field to a foreign key. - foreign_key = models.ForeignKey('tests_other.user_other', models.CASCADE) + foreign_key = models.ForeignKey("tests_other.user_other", models.CASCADE) project_state.alter_field( - 'tests', 'post', 'authors', foreign_key, preserve_default=True, + "tests", + "post", + "authors", + foreign_key, + preserve_default=True, ) self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'comment')], + list(project_state.relations["tests", "user"]), + [("tests", "comment")], ) self.assertEqual( - list(project_state.relations['tests_other', 'user_other']), - [('tests', 'post')], + list(project_state.relations["tests_other", "user_other"]), + [("tests", "post")], ) self.assertEqual( - project_state.relations['tests_other', 'user_other']['tests', 'post'], - {'authors': foreign_key}, + project_state.relations["tests_other", "user_other"]["tests", "post"], + {"authors": foreign_key}, ) def test_many_relations_to_same_model(self): project_state = self.get_base_project_state() - new_field = models.ForeignKey('tests.user', models.CASCADE) + new_field = models.ForeignKey("tests.user", models.CASCADE) project_state.add_field( - 'tests', 'comment', 'reviewer', new_field, preserve_default=True, + "tests", + "comment", + "reviewer", + new_field, + preserve_default=True, ) self.assertEqual( - list(project_state.relations['tests', 'user']), - [('tests', 'comment'), ('tests', 'post')], + list(project_state.relations["tests", "user"]), + [("tests", "comment"), ("tests", "post")], ) - comment_rels = project_state.relations['tests', 'user']['tests', 'comment'] + comment_rels = project_state.relations["tests", "user"]["tests", "comment"] # Two foreign keys to the same model. self.assertEqual(len(comment_rels), 2) - self.assertEqual(comment_rels['reviewer'], new_field) + self.assertEqual(comment_rels["reviewer"], new_field) # Rename the second foreign key. - project_state.rename_field('tests', 'comment', 'reviewer', 'supervisor') + project_state.rename_field("tests", "comment", "reviewer", "supervisor") self.assertEqual(len(comment_rels), 2) - self.assertEqual(comment_rels['supervisor'], new_field) + self.assertEqual(comment_rels["supervisor"], new_field) # Remove the first foreign key. - project_state.remove_field('tests', 'comment', 'user') - self.assertEqual(comment_rels, {'supervisor': new_field}) + project_state.remove_field("tests", "comment", "user") + self.assertEqual(comment_rels, {"supervisor": new_field}) class ModelStateTests(SimpleTestCase): @@ -1459,37 +1638,39 @@ class ModelStateTests(SimpleTestCase): def test_bound_field_sanity_check(self): field = models.CharField(max_length=1) field.model = models.Model - with self.assertRaisesMessage(ValueError, 'ModelState.fields cannot be bound to a model - "field" is.'): - ModelState('app', 'Model', [('field', field)]) + with self.assertRaisesMessage( + ValueError, 'ModelState.fields cannot be bound to a model - "field" is.' + ): + ModelState("app", "Model", [("field", field)]) def test_sanity_check_to(self): field = models.ForeignKey(UnicodeModel, models.CASCADE) with self.assertRaisesMessage( ValueError, 'ModelState.fields cannot refer to a model class - "field.to" does. ' - 'Use a string reference instead.' + "Use a string reference instead.", ): - ModelState('app', 'Model', [('field', field)]) + ModelState("app", "Model", [("field", field)]) def test_sanity_check_through(self): - field = models.ManyToManyField('UnicodeModel') + field = models.ManyToManyField("UnicodeModel") field.remote_field.through = UnicodeModel with self.assertRaisesMessage( ValueError, 'ModelState.fields cannot refer to a model class - "field.through" does. ' - 'Use a string reference instead.' + "Use a string reference instead.", ): - ModelState('app', 'Model', [('field', field)]) + ModelState("app", "Model", [("field", field)]) def test_sanity_index_name(self): field = models.IntegerField() - options = {'indexes': [models.Index(fields=['field'])]} + options = {"indexes": [models.Index(fields=["field"])]} msg = ( "Indexes passed to ModelState require a name attribute. <Index: " "fields=['field']> doesn't have one." ) with self.assertRaisesMessage(ValueError, msg): - ModelState('app', 'Model', [('field', field)], options=options) + ModelState("app", "Model", [("field", field)], options=options) def test_fields_immutability(self): """ @@ -1497,48 +1678,52 @@ class ModelStateTests(SimpleTestCase): """ apps = Apps() field = models.CharField(max_length=1) - state = ModelState('app', 'Model', [('name', field)]) + state = ModelState("app", "Model", [("name", field)]) Model = state.render(apps) - self.assertNotEqual(Model._meta.get_field('name'), field) + self.assertNotEqual(Model._meta.get_field("name"), field) def test_repr(self): field = models.CharField(max_length=1) - state = ModelState('app', 'Model', [('name', field)], bases=['app.A', 'app.B', 'app.C']) + state = ModelState( + "app", "Model", [("name", field)], bases=["app.A", "app.B", "app.C"] + ) self.assertEqual(repr(state), "<ModelState: 'app.Model'>") project_state = ProjectState() project_state.add_model(state) - with self.assertRaisesMessage(InvalidBasesError, "Cannot resolve bases for [<ModelState: 'app.Model'>]"): + with self.assertRaisesMessage( + InvalidBasesError, "Cannot resolve bases for [<ModelState: 'app.Model'>]" + ): project_state.apps def test_fields_ordering_equality(self): state = ModelState( - 'migrations', - 'Tag', + "migrations", + "Tag", [ - ('id', models.AutoField(primary_key=True)), - ('name', models.CharField(max_length=100)), - ('hidden', models.BooleanField()), + ("id", models.AutoField(primary_key=True)), + ("name", models.CharField(max_length=100)), + ("hidden", models.BooleanField()), ], ) reordered_state = ModelState( - 'migrations', - 'Tag', + "migrations", + "Tag", [ - ('id', models.AutoField(primary_key=True)), + ("id", models.AutoField(primary_key=True)), # Purposely re-ordered. - ('hidden', models.BooleanField()), - ('name', models.CharField(max_length=100)), + ("hidden", models.BooleanField()), + ("name", models.CharField(max_length=100)), ], ) self.assertEqual(state, reordered_state) - @override_settings(TEST_SWAPPABLE_MODEL='migrations.SomeFakeModel') + @override_settings(TEST_SWAPPABLE_MODEL="migrations.SomeFakeModel") def test_create_swappable(self): """ Tests making a ProjectState from an Apps with a swappable model """ - new_apps = Apps(['migrations']) + new_apps = Apps(["migrations"]) class Author(models.Model): name = models.CharField(max_length=255) @@ -1546,34 +1731,37 @@ class ModelStateTests(SimpleTestCase): age = models.IntegerField(blank=True, null=True) class Meta: - app_label = 'migrations' + app_label = "migrations" apps = new_apps - swappable = 'TEST_SWAPPABLE_MODEL' + swappable = "TEST_SWAPPABLE_MODEL" author_state = ModelState.from_model(Author) - self.assertEqual(author_state.app_label, 'migrations') - self.assertEqual(author_state.name, 'Author') - self.assertEqual(list(author_state.fields), ['id', 'name', 'bio', 'age']) - self.assertEqual(author_state.fields['name'].max_length, 255) - self.assertIs(author_state.fields['bio'].null, False) - self.assertIs(author_state.fields['age'].null, True) - self.assertEqual(author_state.options, {'swappable': 'TEST_SWAPPABLE_MODEL', 'indexes': [], "constraints": []}) + self.assertEqual(author_state.app_label, "migrations") + self.assertEqual(author_state.name, "Author") + self.assertEqual(list(author_state.fields), ["id", "name", "bio", "age"]) + self.assertEqual(author_state.fields["name"].max_length, 255) + self.assertIs(author_state.fields["bio"].null, False) + self.assertIs(author_state.fields["age"].null, True) + self.assertEqual( + author_state.options, + {"swappable": "TEST_SWAPPABLE_MODEL", "indexes": [], "constraints": []}, + ) self.assertEqual(author_state.bases, (models.Model,)) self.assertEqual(author_state.managers, []) - @override_settings(TEST_SWAPPABLE_MODEL='migrations.SomeFakeModel') + @override_settings(TEST_SWAPPABLE_MODEL="migrations.SomeFakeModel") def test_create_swappable_from_abstract(self): """ A swappable model inheriting from a hierarchy: concrete -> abstract -> concrete. """ - new_apps = Apps(['migrations']) + new_apps = Apps(["migrations"]) class SearchableLocation(models.Model): keywords = models.CharField(max_length=256) class Meta: - app_label = 'migrations' + app_label = "migrations" apps = new_apps class Station(SearchableLocation): @@ -1587,72 +1775,77 @@ class ModelStateTests(SimpleTestCase): inbound = models.BooleanField(default=False) class Meta(Station.Meta): - app_label = 'migrations' + app_label = "migrations" apps = new_apps - swappable = 'TEST_SWAPPABLE_MODEL' + swappable = "TEST_SWAPPABLE_MODEL" station_state = ModelState.from_model(BusStation) - self.assertEqual(station_state.app_label, 'migrations') - self.assertEqual(station_state.name, 'BusStation') + self.assertEqual(station_state.app_label, "migrations") + self.assertEqual(station_state.name, "BusStation") self.assertEqual( list(station_state.fields), - ['searchablelocation_ptr', 'name', 'bus_routes', 'inbound'] + ["searchablelocation_ptr", "name", "bus_routes", "inbound"], ) - self.assertEqual(station_state.fields['name'].max_length, 128) - self.assertIs(station_state.fields['bus_routes'].null, False) + self.assertEqual(station_state.fields["name"].max_length, 128) + self.assertIs(station_state.fields["bus_routes"].null, False) self.assertEqual( station_state.options, - {'abstract': False, 'swappable': 'TEST_SWAPPABLE_MODEL', 'indexes': [], 'constraints': []} + { + "abstract": False, + "swappable": "TEST_SWAPPABLE_MODEL", + "indexes": [], + "constraints": [], + }, ) - self.assertEqual(station_state.bases, ('migrations.searchablelocation',)) + self.assertEqual(station_state.bases, ("migrations.searchablelocation",)) self.assertEqual(station_state.managers, []) - @override_settings(TEST_SWAPPABLE_MODEL='migrations.SomeFakeModel') + @override_settings(TEST_SWAPPABLE_MODEL="migrations.SomeFakeModel") def test_custom_manager_swappable(self): """ Tests making a ProjectState from unused models with custom managers """ - new_apps = Apps(['migrations']) + new_apps = Apps(["migrations"]) class Food(models.Model): - food_mgr = FoodManager('a', 'b') + food_mgr = FoodManager("a", "b") food_qs = FoodQuerySet.as_manager() - food_no_mgr = NoMigrationFoodManager('x', 'y') + food_no_mgr = NoMigrationFoodManager("x", "y") class Meta: app_label = "migrations" apps = new_apps - swappable = 'TEST_SWAPPABLE_MODEL' + swappable = "TEST_SWAPPABLE_MODEL" food_state = ModelState.from_model(Food) # The default manager is used in migrations - self.assertEqual([name for name, mgr in food_state.managers], ['food_mgr']) - self.assertEqual(food_state.managers[0][1].args, ('a', 'b', 1, 2)) + self.assertEqual([name for name, mgr in food_state.managers], ["food_mgr"]) + self.assertEqual(food_state.managers[0][1].args, ("a", "b", 1, 2)) - @isolate_apps('migrations', 'django.contrib.contenttypes') + @isolate_apps("migrations", "django.contrib.contenttypes") def test_order_with_respect_to_private_field(self): class PrivateFieldModel(models.Model): - content_type = models.ForeignKey('contenttypes.ContentType', models.CASCADE) + content_type = models.ForeignKey("contenttypes.ContentType", models.CASCADE) object_id = models.PositiveIntegerField() private = GenericForeignKey() class Meta: - order_with_respect_to = 'private' + order_with_respect_to = "private" state = ModelState.from_model(PrivateFieldModel) - self.assertNotIn('order_with_respect_to', state.options) + self.assertNotIn("order_with_respect_to", state.options) - @isolate_apps('migrations') + @isolate_apps("migrations") def test_abstract_model_children_inherit_indexes(self): class Abstract(models.Model): name = models.CharField(max_length=50) class Meta: - app_label = 'migrations' + app_label = "migrations" abstract = True - indexes = [models.Index(fields=['name'])] + indexes = [models.Index(fields=["name"])] class Child1(Abstract): pass @@ -1662,66 +1855,69 @@ class ModelStateTests(SimpleTestCase): child1_state = ModelState.from_model(Child1) child2_state = ModelState.from_model(Child2) - index_names = [index.name for index in child1_state.options['indexes']] - self.assertEqual(index_names, ['migrations__name_b0afd7_idx']) - index_names = [index.name for index in child2_state.options['indexes']] - self.assertEqual(index_names, ['migrations__name_016466_idx']) + index_names = [index.name for index in child1_state.options["indexes"]] + self.assertEqual(index_names, ["migrations__name_b0afd7_idx"]) + index_names = [index.name for index in child2_state.options["indexes"]] + self.assertEqual(index_names, ["migrations__name_016466_idx"]) # Modifying the state doesn't modify the index on the model. - child1_state.options['indexes'][0].name = 'bar' - self.assertEqual(Child1._meta.indexes[0].name, 'migrations__name_b0afd7_idx') + child1_state.options["indexes"][0].name = "bar" + self.assertEqual(Child1._meta.indexes[0].name, "migrations__name_b0afd7_idx") - @isolate_apps('migrations') + @isolate_apps("migrations") def test_explicit_index_name(self): class TestModel(models.Model): name = models.CharField(max_length=50) class Meta: - app_label = 'migrations' - indexes = [models.Index(fields=['name'], name='foo_idx')] + app_label = "migrations" + indexes = [models.Index(fields=["name"], name="foo_idx")] model_state = ModelState.from_model(TestModel) - index_names = [index.name for index in model_state.options['indexes']] - self.assertEqual(index_names, ['foo_idx']) + index_names = [index.name for index in model_state.options["indexes"]] + self.assertEqual(index_names, ["foo_idx"]) - @isolate_apps('migrations') + @isolate_apps("migrations") def test_from_model_constraints(self): class ModelWithConstraints(models.Model): size = models.IntegerField() class Meta: - constraints = [models.CheckConstraint(check=models.Q(size__gt=1), name='size_gt_1')] + constraints = [ + models.CheckConstraint(check=models.Q(size__gt=1), name="size_gt_1") + ] state = ModelState.from_model(ModelWithConstraints) model_constraints = ModelWithConstraints._meta.constraints - state_constraints = state.options['constraints'] + state_constraints = state.options["constraints"] self.assertEqual(model_constraints, state_constraints) self.assertIsNot(model_constraints, state_constraints) self.assertIsNot(model_constraints[0], state_constraints[0]) class RelatedModelsTests(SimpleTestCase): - def setUp(self): - self.apps = Apps(['migrations.related_models_app']) + self.apps = Apps(["migrations.related_models_app"]) - def create_model(self, name, foreign_keys=[], bases=(), abstract=False, proxy=False): - test_name = 'related_models_app' + def create_model( + self, name, foreign_keys=[], bases=(), abstract=False, proxy=False + ): + test_name = "related_models_app" assert not (abstract and proxy) meta_contents = { - 'abstract': abstract, - 'app_label': test_name, - 'apps': self.apps, - 'proxy': proxy, + "abstract": abstract, + "app_label": test_name, + "apps": self.apps, + "proxy": proxy, } meta = type("Meta", (), meta_contents) if not bases: bases = (models.Model,) body = { - 'Meta': meta, - '__module__': "__fake__", + "Meta": meta, + "__module__": "__fake__", } - fname_base = fname = '%s_%%d' % name.lower() + fname_base = fname = "%s_%%d" % name.lower() for i, fk in enumerate(foreign_keys, 1): fname = fname_base % i body[fname] = fk @@ -1740,13 +1936,17 @@ class RelatedModelsTests(SimpleTestCase): self.assertRelated(B, []) def test_direct_fk(self): - A = self.create_model("A", foreign_keys=[models.ForeignKey('B', models.CASCADE)]) + A = self.create_model( + "A", foreign_keys=[models.ForeignKey("B", models.CASCADE)] + ) B = self.create_model("B") self.assertRelated(A, [B]) self.assertRelated(B, [A]) def test_direct_hidden_fk(self): - A = self.create_model("A", foreign_keys=[models.ForeignKey('B', models.CASCADE, related_name='+')]) + A = self.create_model( + "A", foreign_keys=[models.ForeignKey("B", models.CASCADE, related_name="+")] + ) B = self.create_model("B") self.assertRelated(A, [B]) self.assertRelated(B, [A]) @@ -1755,30 +1955,46 @@ class RelatedModelsTests(SimpleTestCase): A = self.create_model("A") B = self.create_model("B", bases=(A,), proxy=True) C = self.create_model("C", bases=(B,), proxy=True) - D = self.create_model("D", foreign_keys=[models.ForeignKey('C', models.CASCADE)]) + D = self.create_model( + "D", foreign_keys=[models.ForeignKey("C", models.CASCADE)] + ) self.assertRelated(A, [B, C, D]) self.assertRelated(B, [A, C, D]) self.assertRelated(C, [A, B, D]) self.assertRelated(D, [A, B, C]) def test_nested_fk(self): - A = self.create_model("A", foreign_keys=[models.ForeignKey('B', models.CASCADE)]) - B = self.create_model("B", foreign_keys=[models.ForeignKey('C', models.CASCADE)]) + A = self.create_model( + "A", foreign_keys=[models.ForeignKey("B", models.CASCADE)] + ) + B = self.create_model( + "B", foreign_keys=[models.ForeignKey("C", models.CASCADE)] + ) C = self.create_model("C") self.assertRelated(A, [B, C]) self.assertRelated(B, [A, C]) self.assertRelated(C, [A, B]) def test_two_sided(self): - A = self.create_model("A", foreign_keys=[models.ForeignKey('B', models.CASCADE)]) - B = self.create_model("B", foreign_keys=[models.ForeignKey('A', models.CASCADE)]) + A = self.create_model( + "A", foreign_keys=[models.ForeignKey("B", models.CASCADE)] + ) + B = self.create_model( + "B", foreign_keys=[models.ForeignKey("A", models.CASCADE)] + ) self.assertRelated(A, [B]) self.assertRelated(B, [A]) def test_circle(self): - A = self.create_model("A", foreign_keys=[models.ForeignKey('B', models.CASCADE)]) - B = self.create_model("B", foreign_keys=[models.ForeignKey('C', models.CASCADE)]) - C = self.create_model("C", foreign_keys=[models.ForeignKey('A', models.CASCADE)]) + A = self.create_model( + "A", foreign_keys=[models.ForeignKey("B", models.CASCADE)] + ) + B = self.create_model( + "B", foreign_keys=[models.ForeignKey("C", models.CASCADE)] + ) + C = self.create_model( + "C", foreign_keys=[models.ForeignKey("A", models.CASCADE)] + ) self.assertRelated(A, [B, C]) self.assertRelated(B, [A, C]) self.assertRelated(C, [A, B]) @@ -1800,7 +2016,13 @@ class RelatedModelsTests(SimpleTestCase): def test_multiple_bases(self): A = self.create_model("A") B = self.create_model("B") - C = self.create_model("C", bases=(A, B,)) + C = self.create_model( + "C", + bases=( + A, + B, + ), + ) self.assertRelated(A, [B, C]) self.assertRelated(B, [A, C]) self.assertRelated(C, [A, B]) @@ -1808,10 +2030,22 @@ class RelatedModelsTests(SimpleTestCase): def test_multiple_nested_bases(self): A = self.create_model("A") B = self.create_model("B") - C = self.create_model("C", bases=(A, B,)) + C = self.create_model( + "C", + bases=( + A, + B, + ), + ) D = self.create_model("D") E = self.create_model("E", bases=(D,)) - F = self.create_model("F", bases=(C, E,)) + F = self.create_model( + "F", + bases=( + C, + E, + ), + ) Y = self.create_model("Y") Z = self.create_model("Z", bases=(Y,)) self.assertRelated(A, [B, C, D, E, F]) @@ -1824,7 +2058,9 @@ class RelatedModelsTests(SimpleTestCase): self.assertRelated(Z, [Y]) def test_base_to_base_fk(self): - A = self.create_model("A", foreign_keys=[models.ForeignKey('Y', models.CASCADE)]) + A = self.create_model( + "A", foreign_keys=[models.ForeignKey("Y", models.CASCADE)] + ) B = self.create_model("B", bases=(A,)) Y = self.create_model("Y") Z = self.create_model("Z", bases=(Y,)) @@ -1834,7 +2070,9 @@ class RelatedModelsTests(SimpleTestCase): self.assertRelated(Z, [A, B, Y]) def test_base_to_subclass_fk(self): - A = self.create_model("A", foreign_keys=[models.ForeignKey('Z', models.CASCADE)]) + A = self.create_model( + "A", foreign_keys=[models.ForeignKey("Z", models.CASCADE)] + ) B = self.create_model("B", bases=(A,)) Y = self.create_model("Y") Z = self.create_model("Z", bases=(Y,)) @@ -1844,70 +2082,97 @@ class RelatedModelsTests(SimpleTestCase): self.assertRelated(Z, [A, B, Y]) def test_direct_m2m(self): - A = self.create_model("A", foreign_keys=[models.ManyToManyField('B')]) + A = self.create_model("A", foreign_keys=[models.ManyToManyField("B")]) B = self.create_model("B") self.assertRelated(A, [A.a_1.rel.through, B]) self.assertRelated(B, [A, A.a_1.rel.through]) def test_direct_m2m_self(self): - A = self.create_model("A", foreign_keys=[models.ManyToManyField('A')]) + A = self.create_model("A", foreign_keys=[models.ManyToManyField("A")]) self.assertRelated(A, [A.a_1.rel.through]) def test_intermediate_m2m_self(self): - A = self.create_model("A", foreign_keys=[models.ManyToManyField('A', through='T')]) - T = self.create_model("T", foreign_keys=[ - models.ForeignKey('A', models.CASCADE), - models.ForeignKey('A', models.CASCADE), - ]) + A = self.create_model( + "A", foreign_keys=[models.ManyToManyField("A", through="T")] + ) + T = self.create_model( + "T", + foreign_keys=[ + models.ForeignKey("A", models.CASCADE), + models.ForeignKey("A", models.CASCADE), + ], + ) self.assertRelated(A, [T]) self.assertRelated(T, [A]) def test_intermediate_m2m(self): - A = self.create_model("A", foreign_keys=[models.ManyToManyField('B', through='T')]) + A = self.create_model( + "A", foreign_keys=[models.ManyToManyField("B", through="T")] + ) B = self.create_model("B") - T = self.create_model("T", foreign_keys=[ - models.ForeignKey('A', models.CASCADE), - models.ForeignKey('B', models.CASCADE), - ]) + T = self.create_model( + "T", + foreign_keys=[ + models.ForeignKey("A", models.CASCADE), + models.ForeignKey("B", models.CASCADE), + ], + ) self.assertRelated(A, [B, T]) self.assertRelated(B, [A, T]) self.assertRelated(T, [A, B]) def test_intermediate_m2m_extern_fk(self): - A = self.create_model("A", foreign_keys=[models.ManyToManyField('B', through='T')]) + A = self.create_model( + "A", foreign_keys=[models.ManyToManyField("B", through="T")] + ) B = self.create_model("B") Z = self.create_model("Z") - T = self.create_model("T", foreign_keys=[ - models.ForeignKey('A', models.CASCADE), - models.ForeignKey('B', models.CASCADE), - models.ForeignKey('Z', models.CASCADE), - ]) + T = self.create_model( + "T", + foreign_keys=[ + models.ForeignKey("A", models.CASCADE), + models.ForeignKey("B", models.CASCADE), + models.ForeignKey("Z", models.CASCADE), + ], + ) self.assertRelated(A, [B, T, Z]) self.assertRelated(B, [A, T, Z]) self.assertRelated(T, [A, B, Z]) self.assertRelated(Z, [A, B, T]) def test_intermediate_m2m_base(self): - A = self.create_model("A", foreign_keys=[models.ManyToManyField('B', through='T')]) + A = self.create_model( + "A", foreign_keys=[models.ManyToManyField("B", through="T")] + ) B = self.create_model("B") S = self.create_model("S") - T = self.create_model("T", foreign_keys=[ - models.ForeignKey('A', models.CASCADE), - models.ForeignKey('B', models.CASCADE), - ], bases=(S,)) + T = self.create_model( + "T", + foreign_keys=[ + models.ForeignKey("A", models.CASCADE), + models.ForeignKey("B", models.CASCADE), + ], + bases=(S,), + ) self.assertRelated(A, [B, S, T]) self.assertRelated(B, [A, S, T]) self.assertRelated(S, [A, B, T]) self.assertRelated(T, [A, B, S]) def test_generic_fk(self): - A = self.create_model("A", foreign_keys=[ - models.ForeignKey('B', models.CASCADE), - GenericForeignKey(), - ]) - B = self.create_model("B", foreign_keys=[ - models.ForeignKey('C', models.CASCADE), - ]) + A = self.create_model( + "A", + foreign_keys=[ + models.ForeignKey("B", models.CASCADE), + GenericForeignKey(), + ], + ) + B = self.create_model( + "B", + foreign_keys=[ + models.ForeignKey("C", models.CASCADE), + ], + ) self.assertRelated(A, [B]) self.assertRelated(B, [A]) diff --git a/tests/migrations/test_writer.py b/tests/migrations/test_writer.py index f55c48a0d4..0b45247bc5 100644 --- a/tests/migrations/test_writer.py +++ b/tests/migrations/test_writer.py @@ -40,37 +40,38 @@ from .models import FoodManager, FoodQuerySet class DeconstructibleInstances: def deconstruct(self): - return ('DeconstructibleInstances', [], {}) + return ("DeconstructibleInstances", [], {}) class Money(decimal.Decimal): def deconstruct(self): return ( - '%s.%s' % (self.__class__.__module__, self.__class__.__name__), + "%s.%s" % (self.__class__.__module__, self.__class__.__name__), [str(self)], - {} + {}, ) class TestModel1: def upload_to(self): - return '/somewhere/dynamic/' + return "/somewhere/dynamic/" + thing = models.FileField(upload_to=upload_to) class TextEnum(enum.Enum): - A = 'a-value' - B = 'value-b' + A = "a-value" + B = "value-b" class TextTranslatedEnum(enum.Enum): - A = _('a-value') - B = _('value-b') + A = _("a-value") + B = _("value-b") class BinaryEnum(enum.Enum): - A = b'a-value' - B = b'value-b' + A = b"a-value" + B = b"value-b" class IntEnum(enum.IntEnum): @@ -79,97 +80,100 @@ class IntEnum(enum.IntEnum): class OperationWriterTests(SimpleTestCase): - def test_empty_signature(self): operation = custom_migration_operations.operations.TestOperation() buff, imports = OperationWriter(operation, indentation=0).serialize() - self.assertEqual(imports, {'import custom_migration_operations.operations'}) + self.assertEqual(imports, {"import custom_migration_operations.operations"}) self.assertEqual( buff, - 'custom_migration_operations.operations.TestOperation(\n),', + "custom_migration_operations.operations.TestOperation(\n),", ) def test_args_signature(self): operation = custom_migration_operations.operations.ArgsOperation(1, 2) buff, imports = OperationWriter(operation, indentation=0).serialize() - self.assertEqual(imports, {'import custom_migration_operations.operations'}) + self.assertEqual(imports, {"import custom_migration_operations.operations"}) self.assertEqual( buff, - 'custom_migration_operations.operations.ArgsOperation(\n' - ' arg1=1,\n' - ' arg2=2,\n' - '),' + "custom_migration_operations.operations.ArgsOperation(\n" + " arg1=1,\n" + " arg2=2,\n" + "),", ) def test_kwargs_signature(self): operation = custom_migration_operations.operations.KwargsOperation(kwarg1=1) buff, imports = OperationWriter(operation, indentation=0).serialize() - self.assertEqual(imports, {'import custom_migration_operations.operations'}) + self.assertEqual(imports, {"import custom_migration_operations.operations"}) self.assertEqual( buff, - 'custom_migration_operations.operations.KwargsOperation(\n' - ' kwarg1=1,\n' - '),' + "custom_migration_operations.operations.KwargsOperation(\n" + " kwarg1=1,\n" + "),", ) def test_args_kwargs_signature(self): - operation = custom_migration_operations.operations.ArgsKwargsOperation(1, 2, kwarg2=4) + operation = custom_migration_operations.operations.ArgsKwargsOperation( + 1, 2, kwarg2=4 + ) buff, imports = OperationWriter(operation, indentation=0).serialize() - self.assertEqual(imports, {'import custom_migration_operations.operations'}) + self.assertEqual(imports, {"import custom_migration_operations.operations"}) self.assertEqual( buff, - 'custom_migration_operations.operations.ArgsKwargsOperation(\n' - ' arg1=1,\n' - ' arg2=2,\n' - ' kwarg2=4,\n' - '),' + "custom_migration_operations.operations.ArgsKwargsOperation(\n" + " arg1=1,\n" + " arg2=2,\n" + " kwarg2=4,\n" + "),", ) def test_nested_args_signature(self): operation = custom_migration_operations.operations.ArgsOperation( custom_migration_operations.operations.ArgsOperation(1, 2), - custom_migration_operations.operations.KwargsOperation(kwarg1=3, kwarg2=4) + custom_migration_operations.operations.KwargsOperation(kwarg1=3, kwarg2=4), ) buff, imports = OperationWriter(operation, indentation=0).serialize() - self.assertEqual(imports, {'import custom_migration_operations.operations'}) + self.assertEqual(imports, {"import custom_migration_operations.operations"}) self.assertEqual( buff, - 'custom_migration_operations.operations.ArgsOperation(\n' - ' arg1=custom_migration_operations.operations.ArgsOperation(\n' - ' arg1=1,\n' - ' arg2=2,\n' - ' ),\n' - ' arg2=custom_migration_operations.operations.KwargsOperation(\n' - ' kwarg1=3,\n' - ' kwarg2=4,\n' - ' ),\n' - '),' + "custom_migration_operations.operations.ArgsOperation(\n" + " arg1=custom_migration_operations.operations.ArgsOperation(\n" + " arg1=1,\n" + " arg2=2,\n" + " ),\n" + " arg2=custom_migration_operations.operations.KwargsOperation(\n" + " kwarg1=3,\n" + " kwarg2=4,\n" + " ),\n" + "),", ) def test_multiline_args_signature(self): - operation = custom_migration_operations.operations.ArgsOperation("test\n arg1", "test\narg2") + operation = custom_migration_operations.operations.ArgsOperation( + "test\n arg1", "test\narg2" + ) buff, imports = OperationWriter(operation, indentation=0).serialize() - self.assertEqual(imports, {'import custom_migration_operations.operations'}) + self.assertEqual(imports, {"import custom_migration_operations.operations"}) self.assertEqual( buff, "custom_migration_operations.operations.ArgsOperation(\n" " arg1='test\\n arg1',\n" " arg2='test\\narg2',\n" - ")," + "),", ) def test_expand_args_signature(self): operation = custom_migration_operations.operations.ExpandArgsOperation([1, 2]) buff, imports = OperationWriter(operation, indentation=0).serialize() - self.assertEqual(imports, {'import custom_migration_operations.operations'}) + self.assertEqual(imports, {"import custom_migration_operations.operations"}) self.assertEqual( buff, - 'custom_migration_operations.operations.ExpandArgsOperation(\n' - ' arg=[\n' - ' 1,\n' - ' 2,\n' - ' ],\n' - '),' + "custom_migration_operations.operations.ExpandArgsOperation(\n" + " arg=[\n" + " 1,\n" + " 2,\n" + " ],\n" + "),", ) def test_nested_operation_expand_args_signature(self): @@ -182,17 +186,17 @@ class OperationWriterTests(SimpleTestCase): ] ) buff, imports = OperationWriter(operation, indentation=0).serialize() - self.assertEqual(imports, {'import custom_migration_operations.operations'}) + self.assertEqual(imports, {"import custom_migration_operations.operations"}) self.assertEqual( buff, - 'custom_migration_operations.operations.ExpandArgsOperation(\n' - ' arg=[\n' - ' custom_migration_operations.operations.KwargsOperation(\n' - ' kwarg1=1,\n' - ' kwarg2=2,\n' - ' ),\n' - ' ],\n' - '),' + "custom_migration_operations.operations.ExpandArgsOperation(\n" + " arg=[\n" + " custom_migration_operations.operations.KwargsOperation(\n" + " kwarg1=1,\n" + " kwarg2=2,\n" + " ),\n" + " ],\n" + "),", ) @@ -200,13 +204,14 @@ class WriterTests(SimpleTestCase): """ Tests the migration writer (makes migration files from Migration instances) """ + class NestedEnum(enum.IntEnum): A = 1 B = 2 class NestedChoices(models.TextChoices): - X = 'X', 'X value' - Y = 'Y', 'Y value' + X = "X", "X value" + Y = "Y", "Y value" def safe_exec(self, string, value=None): d = {} @@ -214,14 +219,18 @@ class WriterTests(SimpleTestCase): exec(string, globals(), d) except Exception as e: if value: - self.fail("Could not exec %r (from value %r): %s" % (string.strip(), value, e)) + self.fail( + "Could not exec %r (from value %r): %s" % (string.strip(), value, e) + ) else: self.fail("Could not exec %r: %s" % (string.strip(), e)) return d def serialize_round_trip(self, value): string, imports = MigrationWriter.serialize(value) - return self.safe_exec("%s\ntest_value_result = %s" % ("\n".join(imports), string), value)['test_value_result'] + return self.safe_exec( + "%s\ntest_value_result = %s" % ("\n".join(imports), string), value + )["test_value_result"] def assertSerializedEqual(self, value): self.assertEqual(self.serialize_round_trip(value), value) @@ -243,16 +252,15 @@ class WriterTests(SimpleTestCase): self.assertTrue(math.isinf(self.serialize_round_trip(float("-inf")))) self.assertTrue(math.isnan(self.serialize_round_trip(float("nan")))) - self.assertSerializedEqual(decimal.Decimal('1.3')) + self.assertSerializedEqual(decimal.Decimal("1.3")) self.assertSerializedResultEqual( - decimal.Decimal('1.3'), - ("Decimal('1.3')", {'from decimal import Decimal'}) + decimal.Decimal("1.3"), ("Decimal('1.3')", {"from decimal import Decimal"}) ) - self.assertSerializedEqual(Money('1.3')) + self.assertSerializedEqual(Money("1.3")) self.assertSerializedResultEqual( - Money('1.3'), - ("migrations.test_writer.Money('1.3')", {'import migrations.test_writer'}) + Money("1.3"), + ("migrations.test_writer.Money('1.3')", {"import migrations.test_writer"}), ) def test_serialize_constants(self): @@ -281,54 +289,62 @@ class WriterTests(SimpleTestCase): self.assertSerializedEqual(["a", 2, True, None]) self.assertSerializedEqual({2, 3, "eighty"}) self.assertSerializedEqual({"lalalala": ["yeah", "no", "maybe"]}) - self.assertSerializedEqual(_('Hello')) + self.assertSerializedEqual(_("Hello")) def test_serialize_builtin_types(self): self.assertSerializedEqual([list, tuple, dict, set, frozenset]) self.assertSerializedResultEqual( [list, tuple, dict, set, frozenset], - ("[list, tuple, dict, set, frozenset]", set()) + ("[list, tuple, dict, set, frozenset]", set()), ) def test_serialize_lazy_objects(self): - pattern = re.compile(r'^foo$') + pattern = re.compile(r"^foo$") lazy_pattern = SimpleLazyObject(lambda: pattern) self.assertEqual(self.serialize_round_trip(lazy_pattern), pattern) def test_serialize_enums(self): self.assertSerializedResultEqual( TextEnum.A, - ("migrations.test_writer.TextEnum['A']", {'import migrations.test_writer'}) + ("migrations.test_writer.TextEnum['A']", {"import migrations.test_writer"}), ) self.assertSerializedResultEqual( TextTranslatedEnum.A, - ("migrations.test_writer.TextTranslatedEnum['A']", {'import migrations.test_writer'}) + ( + "migrations.test_writer.TextTranslatedEnum['A']", + {"import migrations.test_writer"}, + ), ) self.assertSerializedResultEqual( BinaryEnum.A, - ("migrations.test_writer.BinaryEnum['A']", {'import migrations.test_writer'}) + ( + "migrations.test_writer.BinaryEnum['A']", + {"import migrations.test_writer"}, + ), ) self.assertSerializedResultEqual( IntEnum.B, - ("migrations.test_writer.IntEnum['B']", {'import migrations.test_writer'}) + ("migrations.test_writer.IntEnum['B']", {"import migrations.test_writer"}), ) self.assertSerializedResultEqual( self.NestedEnum.A, ( "migrations.test_writer.WriterTests.NestedEnum['A']", - {'import migrations.test_writer'}, + {"import migrations.test_writer"}, ), ) self.assertSerializedEqual(self.NestedEnum.A) - field = models.CharField(default=TextEnum.B, choices=[(m.value, m) for m in TextEnum]) + field = models.CharField( + default=TextEnum.B, choices=[(m.value, m) for m in TextEnum] + ) string = MigrationWriter.serialize(field)[0] self.assertEqual( string, "models.CharField(choices=[" "('a-value', migrations.test_writer.TextEnum['A']), " "('value-b', migrations.test_writer.TextEnum['B'])], " - "default=migrations.test_writer.TextEnum['B'])" + "default=migrations.test_writer.TextEnum['B'])", ) field = models.CharField( default=TextTranslatedEnum.A, @@ -340,45 +356,49 @@ class WriterTests(SimpleTestCase): "models.CharField(choices=[" "('a-value', migrations.test_writer.TextTranslatedEnum['A']), " "('value-b', migrations.test_writer.TextTranslatedEnum['B'])], " - "default=migrations.test_writer.TextTranslatedEnum['A'])" + "default=migrations.test_writer.TextTranslatedEnum['A'])", + ) + field = models.CharField( + default=BinaryEnum.B, choices=[(m.value, m) for m in BinaryEnum] ) - field = models.CharField(default=BinaryEnum.B, choices=[(m.value, m) for m in BinaryEnum]) string = MigrationWriter.serialize(field)[0] self.assertEqual( string, "models.CharField(choices=[" "(b'a-value', migrations.test_writer.BinaryEnum['A']), " "(b'value-b', migrations.test_writer.BinaryEnum['B'])], " - "default=migrations.test_writer.BinaryEnum['B'])" + "default=migrations.test_writer.BinaryEnum['B'])", + ) + field = models.IntegerField( + default=IntEnum.A, choices=[(m.value, m) for m in IntEnum] ) - field = models.IntegerField(default=IntEnum.A, choices=[(m.value, m) for m in IntEnum]) string = MigrationWriter.serialize(field)[0] self.assertEqual( string, "models.IntegerField(choices=[" "(1, migrations.test_writer.IntEnum['A']), " "(2, migrations.test_writer.IntEnum['B'])], " - "default=migrations.test_writer.IntEnum['A'])" + "default=migrations.test_writer.IntEnum['A'])", ) def test_serialize_choices(self): class TextChoices(models.TextChoices): - A = 'A', 'A value' - B = 'B', 'B value' + A = "A", "A value" + B = "B", "B value" class IntegerChoices(models.IntegerChoices): - A = 1, 'One' - B = 2, 'Two' + A = 1, "One" + B = 2, "Two" class DateChoices(datetime.date, models.Choices): - DATE_1 = 1969, 7, 20, 'First date' - DATE_2 = 1969, 11, 19, 'Second date' + DATE_1 = 1969, 7, 20, "First date" + DATE_2 = 1969, 11, 19, "Second date" self.assertSerializedResultEqual(TextChoices.A, ("'A'", set())) - self.assertSerializedResultEqual(IntegerChoices.A, ('1', set())) + self.assertSerializedResultEqual(IntegerChoices.A, ("1", set())) self.assertSerializedResultEqual( DateChoices.DATE_1, - ('datetime.date(1969, 7, 20)', {'import datetime'}), + ("datetime.date(1969, 7, 20)", {"import datetime"}), ) field = models.CharField(default=TextChoices.B, choices=TextChoices.choices) string = MigrationWriter.serialize(field)[0] @@ -387,20 +407,24 @@ class WriterTests(SimpleTestCase): "models.CharField(choices=[('A', 'A value'), ('B', 'B value')], " "default='B')", ) - field = models.IntegerField(default=IntegerChoices.B, choices=IntegerChoices.choices) + field = models.IntegerField( + default=IntegerChoices.B, choices=IntegerChoices.choices + ) string = MigrationWriter.serialize(field)[0] self.assertEqual( string, "models.IntegerField(choices=[(1, 'One'), (2, 'Two')], default=2)", ) - field = models.DateField(default=DateChoices.DATE_2, choices=DateChoices.choices) + field = models.DateField( + default=DateChoices.DATE_2, choices=DateChoices.choices + ) string = MigrationWriter.serialize(field)[0] self.assertEqual( string, "models.DateField(choices=[" "(datetime.date(1969, 7, 20), 'First date'), " "(datetime.date(1969, 11, 19), 'Second date')], " - "default=datetime.date(1969, 11, 19))" + "default=datetime.date(1969, 11, 19))", ) def test_serialize_nested_class(self): @@ -411,7 +435,7 @@ class WriterTests(SimpleTestCase): nested_cls, ( "migrations.test_writer.WriterTests.%s" % cls_name, - {'import migrations.test_writer'}, + {"import migrations.test_writer"}, ), ) @@ -419,56 +443,58 @@ class WriterTests(SimpleTestCase): self.assertSerializedEqual(uuid.uuid1()) self.assertSerializedEqual(uuid.uuid4()) - uuid_a = uuid.UUID('5c859437-d061-4847-b3f7-e6b78852f8c8') - uuid_b = uuid.UUID('c7853ec1-2ea3-4359-b02d-b54e8f1bcee2') + uuid_a = uuid.UUID("5c859437-d061-4847-b3f7-e6b78852f8c8") + uuid_b = uuid.UUID("c7853ec1-2ea3-4359-b02d-b54e8f1bcee2") self.assertSerializedResultEqual( uuid_a, - ("uuid.UUID('5c859437-d061-4847-b3f7-e6b78852f8c8')", {'import uuid'}) + ("uuid.UUID('5c859437-d061-4847-b3f7-e6b78852f8c8')", {"import uuid"}), ) self.assertSerializedResultEqual( uuid_b, - ("uuid.UUID('c7853ec1-2ea3-4359-b02d-b54e8f1bcee2')", {'import uuid'}) + ("uuid.UUID('c7853ec1-2ea3-4359-b02d-b54e8f1bcee2')", {"import uuid"}), ) - field = models.UUIDField(choices=((uuid_a, 'UUID A'), (uuid_b, 'UUID B')), default=uuid_a) + field = models.UUIDField( + choices=((uuid_a, "UUID A"), (uuid_b, "UUID B")), default=uuid_a + ) string = MigrationWriter.serialize(field)[0] self.assertEqual( string, "models.UUIDField(choices=[" "(uuid.UUID('5c859437-d061-4847-b3f7-e6b78852f8c8'), 'UUID A'), " "(uuid.UUID('c7853ec1-2ea3-4359-b02d-b54e8f1bcee2'), 'UUID B')], " - "default=uuid.UUID('5c859437-d061-4847-b3f7-e6b78852f8c8'))" + "default=uuid.UUID('5c859437-d061-4847-b3f7-e6b78852f8c8'))", ) def test_serialize_pathlib(self): # Pure path objects work in all platforms. self.assertSerializedEqual(pathlib.PurePosixPath()) self.assertSerializedEqual(pathlib.PureWindowsPath()) - path = pathlib.PurePosixPath('/path/file.txt') - expected = ("pathlib.PurePosixPath('/path/file.txt')", {'import pathlib'}) + path = pathlib.PurePosixPath("/path/file.txt") + expected = ("pathlib.PurePosixPath('/path/file.txt')", {"import pathlib"}) self.assertSerializedResultEqual(path, expected) - path = pathlib.PureWindowsPath('A:\\File.txt') - expected = ("pathlib.PureWindowsPath('A:/File.txt')", {'import pathlib'}) + path = pathlib.PureWindowsPath("A:\\File.txt") + expected = ("pathlib.PureWindowsPath('A:/File.txt')", {"import pathlib"}) self.assertSerializedResultEqual(path, expected) # Concrete path objects work on supported platforms. - if sys.platform == 'win32': + if sys.platform == "win32": self.assertSerializedEqual(pathlib.WindowsPath.cwd()) - path = pathlib.WindowsPath('A:\\File.txt') - expected = ("pathlib.PureWindowsPath('A:/File.txt')", {'import pathlib'}) + path = pathlib.WindowsPath("A:\\File.txt") + expected = ("pathlib.PureWindowsPath('A:/File.txt')", {"import pathlib"}) self.assertSerializedResultEqual(path, expected) else: self.assertSerializedEqual(pathlib.PosixPath.cwd()) - path = pathlib.PosixPath('/path/file.txt') - expected = ("pathlib.PurePosixPath('/path/file.txt')", {'import pathlib'}) + path = pathlib.PosixPath("/path/file.txt") + expected = ("pathlib.PurePosixPath('/path/file.txt')", {"import pathlib"}) self.assertSerializedResultEqual(path, expected) - field = models.FilePathField(path=pathlib.PurePosixPath('/home/user')) + field = models.FilePathField(path=pathlib.PurePosixPath("/home/user")) string, imports = MigrationWriter.serialize(field) self.assertEqual( string, "models.FilePathField(path=pathlib.PurePosixPath('/home/user'))", ) - self.assertIn('import pathlib', imports) + self.assertIn("import pathlib", imports) def test_serialize_path_like(self): with os.scandir(os.path.dirname(__file__)) as entries: @@ -478,14 +504,14 @@ class WriterTests(SimpleTestCase): field = models.FilePathField(path=path_like) string = MigrationWriter.serialize(field)[0] - self.assertEqual(string, 'models.FilePathField(path=%r)' % path_like.path) + self.assertEqual(string, "models.FilePathField(path=%r)" % path_like.path) def test_serialize_functions(self): - with self.assertRaisesMessage(ValueError, 'Cannot serialize function: lambda'): + with self.assertRaisesMessage(ValueError, "Cannot serialize function: lambda"): self.assertSerializedEqual(lambda x: 42) self.assertSerializedEqual(models.SET_NULL) string, imports = MigrationWriter.serialize(models.SET(42)) - self.assertEqual(string, 'models.SET(42)') + self.assertEqual(string, "models.SET(42)") self.serialize_round_trip(models.SET(42)) def test_serialize_datetime(self): @@ -496,11 +522,15 @@ class WriterTests(SimpleTestCase): self.assertSerializedEqual(datetime.date.today()) self.assertSerializedEqual(datetime.date.today) self.assertSerializedEqual(datetime.datetime.now().time()) - self.assertSerializedEqual(datetime.datetime(2014, 1, 1, 1, 1, tzinfo=get_default_timezone())) - self.assertSerializedEqual(datetime.datetime(2013, 12, 31, 22, 1, tzinfo=get_fixed_timezone(180))) + self.assertSerializedEqual( + datetime.datetime(2014, 1, 1, 1, 1, tzinfo=get_default_timezone()) + ) + self.assertSerializedEqual( + datetime.datetime(2013, 12, 31, 22, 1, tzinfo=get_fixed_timezone(180)) + ) self.assertSerializedResultEqual( datetime.datetime(2014, 1, 1, 1, 1), - ("datetime.datetime(2014, 1, 1, 1, 1)", {'import datetime'}) + ("datetime.datetime(2014, 1, 1, 1, 1)", {"import datetime"}), ) for tzinfo in (utc, datetime.timezone.utc): with self.subTest(tzinfo=tzinfo): @@ -508,56 +538,64 @@ class WriterTests(SimpleTestCase): datetime.datetime(2012, 1, 1, 1, 1, tzinfo=tzinfo), ( "datetime.datetime(2012, 1, 1, 1, 1, tzinfo=utc)", - {'import datetime', 'from django.utils.timezone import utc'}, - ) + {"import datetime", "from django.utils.timezone import utc"}, + ), ) self.assertSerializedResultEqual( - datetime.datetime(2012, 1, 1, 2, 1, tzinfo=zoneinfo.ZoneInfo('Europe/Paris')), + datetime.datetime( + 2012, 1, 1, 2, 1, tzinfo=zoneinfo.ZoneInfo("Europe/Paris") + ), ( "datetime.datetime(2012, 1, 1, 1, 1, tzinfo=utc)", - {'import datetime', 'from django.utils.timezone import utc'}, - ) + {"import datetime", "from django.utils.timezone import utc"}, + ), ) if pytz: self.assertSerializedResultEqual( - pytz.timezone('Europe/Paris').localize(datetime.datetime(2012, 1, 1, 2, 1)), + pytz.timezone("Europe/Paris").localize( + datetime.datetime(2012, 1, 1, 2, 1) + ), ( "datetime.datetime(2012, 1, 1, 1, 1, tzinfo=utc)", - {'import datetime', 'from django.utils.timezone import utc'}, - ) + {"import datetime", "from django.utils.timezone import utc"}, + ), ) def test_serialize_fields(self): self.assertSerializedFieldEqual(models.CharField(max_length=255)) self.assertSerializedResultEqual( models.CharField(max_length=255), - ("models.CharField(max_length=255)", {"from django.db import models"}) + ("models.CharField(max_length=255)", {"from django.db import models"}), ) self.assertSerializedFieldEqual(models.TextField(null=True, blank=True)) self.assertSerializedResultEqual( models.TextField(null=True, blank=True), - ("models.TextField(blank=True, null=True)", {'from django.db import models'}) + ( + "models.TextField(blank=True, null=True)", + {"from django.db import models"}, + ), ) def test_serialize_settings(self): - self.assertSerializedEqual(SettingsReference(settings.AUTH_USER_MODEL, "AUTH_USER_MODEL")) + self.assertSerializedEqual( + SettingsReference(settings.AUTH_USER_MODEL, "AUTH_USER_MODEL") + ) self.assertSerializedResultEqual( SettingsReference("someapp.model", "AUTH_USER_MODEL"), - ("settings.AUTH_USER_MODEL", {"from django.conf import settings"}) + ("settings.AUTH_USER_MODEL", {"from django.conf import settings"}), ) def test_serialize_iterators(self): self.assertSerializedResultEqual( - ((x, x * x) for x in range(3)), - ("((0, 0), (1, 1), (2, 4))", set()) + ((x, x * x) for x in range(3)), ("((0, 0), (1, 1), (2, 4))", set()) ) def test_serialize_compiled_regex(self): """ Make sure compiled regex can be serialized. """ - regex = re.compile(r'^\w+$') + regex = re.compile(r"^\w+$") self.assertSerializedEqual(regex) def test_serialize_class_based_validators(self): @@ -567,58 +605,82 @@ class WriterTests(SimpleTestCase): """ validator = RegexValidator(message="hello") string = MigrationWriter.serialize(validator)[0] - self.assertEqual(string, "django.core.validators.RegexValidator(message='hello')") + self.assertEqual( + string, "django.core.validators.RegexValidator(message='hello')" + ) self.serialize_round_trip(validator) # Test with a compiled regex. - validator = RegexValidator(regex=re.compile(r'^\w+$')) + validator = RegexValidator(regex=re.compile(r"^\w+$")) string = MigrationWriter.serialize(validator)[0] - self.assertEqual(string, "django.core.validators.RegexValidator(regex=re.compile('^\\\\w+$'))") + self.assertEqual( + string, + "django.core.validators.RegexValidator(regex=re.compile('^\\\\w+$'))", + ) self.serialize_round_trip(validator) # Test a string regex with flag - validator = RegexValidator(r'^[0-9]+$', flags=re.S) + validator = RegexValidator(r"^[0-9]+$", flags=re.S) string = MigrationWriter.serialize(validator)[0] - self.assertEqual(string, "django.core.validators.RegexValidator('^[0-9]+$', flags=re.RegexFlag['DOTALL'])") + self.assertEqual( + string, + "django.core.validators.RegexValidator('^[0-9]+$', flags=re.RegexFlag['DOTALL'])", + ) self.serialize_round_trip(validator) # Test message and code - validator = RegexValidator('^[-a-zA-Z0-9_]+$', 'Invalid', 'invalid') + validator = RegexValidator("^[-a-zA-Z0-9_]+$", "Invalid", "invalid") string = MigrationWriter.serialize(validator)[0] - self.assertEqual(string, "django.core.validators.RegexValidator('^[-a-zA-Z0-9_]+$', 'Invalid', 'invalid')") + self.assertEqual( + string, + "django.core.validators.RegexValidator('^[-a-zA-Z0-9_]+$', 'Invalid', 'invalid')", + ) self.serialize_round_trip(validator) # Test with a subclass. validator = EmailValidator(message="hello") string = MigrationWriter.serialize(validator)[0] - self.assertEqual(string, "django.core.validators.EmailValidator(message='hello')") + self.assertEqual( + string, "django.core.validators.EmailValidator(message='hello')" + ) self.serialize_round_trip(validator) - validator = deconstructible(path="migrations.test_writer.EmailValidator")(EmailValidator)(message="hello") + validator = deconstructible(path="migrations.test_writer.EmailValidator")( + EmailValidator + )(message="hello") string = MigrationWriter.serialize(validator)[0] - self.assertEqual(string, "migrations.test_writer.EmailValidator(message='hello')") + self.assertEqual( + string, "migrations.test_writer.EmailValidator(message='hello')" + ) - validator = deconstructible(path="custom.EmailValidator")(EmailValidator)(message="hello") + validator = deconstructible(path="custom.EmailValidator")(EmailValidator)( + message="hello" + ) with self.assertRaisesMessage(ImportError, "No module named 'custom'"): MigrationWriter.serialize(validator) - validator = deconstructible(path="django.core.validators.EmailValidator2")(EmailValidator)(message="hello") - with self.assertRaisesMessage(ValueError, "Could not find object EmailValidator2 in django.core.validators."): + validator = deconstructible(path="django.core.validators.EmailValidator2")( + EmailValidator + )(message="hello") + with self.assertRaisesMessage( + ValueError, + "Could not find object EmailValidator2 in django.core.validators.", + ): MigrationWriter.serialize(validator) def test_serialize_complex_func_index(self): index = models.Index( - models.Func('rating', function='ABS'), + models.Func("rating", function="ABS"), models.Case( - models.When(name='special', then=models.Value('X')), - default=models.Value('other'), + models.When(name="special", then=models.Value("X")), + default=models.Value("other"), ), models.ExpressionWrapper( - models.F('pages'), + models.F("pages"), output_field=models.IntegerField(), ), - models.OrderBy(models.F('name').desc()), - name='complex_func_index', + models.OrderBy(models.F("name").desc()), + name="complex_func_index", ) string, imports = MigrationWriter.serialize(index) self.assertEqual( @@ -629,9 +691,9 @@ class WriterTests(SimpleTestCase): "models.ExpressionWrapper(" "models.F('pages'), output_field=models.IntegerField()), " "models.OrderBy(models.OrderBy(models.F('name'), descending=True)), " - "name='complex_func_index')" + "name='complex_func_index')", ) - self.assertEqual(imports, {'from django.db import models'}) + self.assertEqual(imports, {"from django.db import models"}) def test_serialize_empty_nonempty_tuple(self): """ @@ -639,20 +701,20 @@ class WriterTests(SimpleTestCase): tuple) default_permissions = () """ empty_tuple = () - one_item_tuple = ('a',) - many_items_tuple = ('a', 'b', 'c') + one_item_tuple = ("a",) + many_items_tuple = ("a", "b", "c") self.assertSerializedEqual(empty_tuple) self.assertSerializedEqual(one_item_tuple) self.assertSerializedEqual(many_items_tuple) def test_serialize_range(self): string, imports = MigrationWriter.serialize(range(1, 5)) - self.assertEqual(string, 'range(1, 5)') + self.assertEqual(string, "range(1, 5)") self.assertEqual(imports, set()) def test_serialize_builtins(self): string, imports = MigrationWriter.serialize(range) - self.assertEqual(string, 'range') + self.assertEqual(string, "range") self.assertEqual(imports, set()) def test_serialize_unbound_method_reference(self): @@ -661,22 +723,29 @@ class WriterTests(SimpleTestCase): def test_serialize_local_function_reference(self): """A reference in a local scope can't be serialized.""" + class TestModel2: def upload_to(self): return "somewhere dynamic" + thing = models.FileField(upload_to=upload_to) - with self.assertRaisesMessage(ValueError, 'Could not find function upload_to in migrations.test_writer'): + with self.assertRaisesMessage( + ValueError, "Could not find function upload_to in migrations.test_writer" + ): self.serialize_round_trip(TestModel2.thing) def test_serialize_managers(self): self.assertSerializedEqual(models.Manager()) self.assertSerializedResultEqual( FoodQuerySet.as_manager(), - ('migrations.models.FoodQuerySet.as_manager()', {'import migrations.models'}) + ( + "migrations.models.FoodQuerySet.as_manager()", + {"import migrations.models"}, + ), ) - self.assertSerializedEqual(FoodManager('a', 'b')) - self.assertSerializedEqual(FoodManager('x', 'y', c=3, d=4)) + self.assertSerializedEqual(FoodManager("a", "b")) + self.assertSerializedEqual(FoodManager("x", "y", c=3, d=4)) def test_serialize_frozensets(self): self.assertSerializedEqual(frozenset()) @@ -684,9 +753,9 @@ class WriterTests(SimpleTestCase): def test_serialize_set(self): self.assertSerializedEqual(set()) - self.assertSerializedResultEqual(set(), ('set()', set())) - self.assertSerializedEqual({'a'}) - self.assertSerializedResultEqual({'a'}, ("{'a'}", set())) + self.assertSerializedResultEqual(set(), ("set()", set())) + self.assertSerializedEqual({"a"}) + self.assertSerializedResultEqual({"a"}, ("{'a'}", set())) def test_serialize_timedelta(self): self.assertSerializedEqual(datetime.timedelta()) @@ -722,27 +791,40 @@ class WriterTests(SimpleTestCase): Tests serializing a simple migration. """ fields = { - 'charfield': models.DateTimeField(default=datetime.datetime.now), - 'datetimefield': models.DateTimeField(default=datetime.datetime.now), + "charfield": models.DateTimeField(default=datetime.datetime.now), + "datetimefield": models.DateTimeField(default=datetime.datetime.now), } options = { - 'verbose_name': 'My model', - 'verbose_name_plural': 'My models', + "verbose_name": "My model", + "verbose_name_plural": "My models", } - migration = type("Migration", (migrations.Migration,), { - "operations": [ - migrations.CreateModel("MyModel", tuple(fields.items()), options, (models.Model,)), - migrations.CreateModel("MyModel2", tuple(fields.items()), bases=(models.Model,)), - migrations.CreateModel( - name="MyModel3", fields=tuple(fields.items()), options=options, bases=(models.Model,) - ), - migrations.DeleteModel("MyModel"), - migrations.AddField("OtherModel", "datetimefield", fields["datetimefield"]), - ], - "dependencies": [("testapp", "some_other_one")], - }) + migration = type( + "Migration", + (migrations.Migration,), + { + "operations": [ + migrations.CreateModel( + "MyModel", tuple(fields.items()), options, (models.Model,) + ), + migrations.CreateModel( + "MyModel2", tuple(fields.items()), bases=(models.Model,) + ), + migrations.CreateModel( + name="MyModel3", + fields=tuple(fields.items()), + options=options, + bases=(models.Model,), + ), + migrations.DeleteModel("MyModel"), + migrations.AddField( + "OtherModel", "datetimefield", fields["datetimefield"] + ), + ], + "dependencies": [("testapp", "some_other_one")], + }, + ) writer = MigrationWriter(migration) output = writer.as_string() # We don't test the output formatting - that's too fragile. @@ -752,68 +834,80 @@ class WriterTests(SimpleTestCase): def test_migration_path(self): test_apps = [ - 'migrations.migrations_test_apps.normal', - 'migrations.migrations_test_apps.with_package_model', - 'migrations.migrations_test_apps.without_init_file', + "migrations.migrations_test_apps.normal", + "migrations.migrations_test_apps.with_package_model", + "migrations.migrations_test_apps.without_init_file", ] base_dir = os.path.dirname(os.path.dirname(__file__)) for app in test_apps: - with self.modify_settings(INSTALLED_APPS={'append': app}): - migration = migrations.Migration('0001_initial', app.split('.')[-1]) - expected_path = os.path.join(base_dir, *(app.split('.') + ['migrations', '0001_initial.py'])) + with self.modify_settings(INSTALLED_APPS={"append": app}): + migration = migrations.Migration("0001_initial", app.split(".")[-1]) + expected_path = os.path.join( + base_dir, *(app.split(".") + ["migrations", "0001_initial.py"]) + ) writer = MigrationWriter(migration) self.assertEqual(writer.path, expected_path) def test_custom_operation(self): - migration = type("Migration", (migrations.Migration,), { - "operations": [ - custom_migration_operations.operations.TestOperation(), - custom_migration_operations.operations.CreateModel(), - migrations.CreateModel("MyModel", (), {}, (models.Model,)), - custom_migration_operations.more_operations.TestOperation() - ], - "dependencies": [] - }) + migration = type( + "Migration", + (migrations.Migration,), + { + "operations": [ + custom_migration_operations.operations.TestOperation(), + custom_migration_operations.operations.CreateModel(), + migrations.CreateModel("MyModel", (), {}, (models.Model,)), + custom_migration_operations.more_operations.TestOperation(), + ], + "dependencies": [], + }, + ) writer = MigrationWriter(migration) output = writer.as_string() result = self.safe_exec(output) self.assertIn("custom_migration_operations", result) self.assertNotEqual( - result['custom_migration_operations'].operations.TestOperation, - result['custom_migration_operations'].more_operations.TestOperation + result["custom_migration_operations"].operations.TestOperation, + result["custom_migration_operations"].more_operations.TestOperation, ) def test_sorted_imports(self): """ #24155 - Tests ordering of imports. """ - migration = type("Migration", (migrations.Migration,), { - "operations": [ - migrations.AddField("mymodel", "myfield", models.DateTimeField( - default=datetime.datetime(2012, 1, 1, 1, 1, tzinfo=utc), - )), - ] - }) + migration = type( + "Migration", + (migrations.Migration,), + { + "operations": [ + migrations.AddField( + "mymodel", + "myfield", + models.DateTimeField( + default=datetime.datetime(2012, 1, 1, 1, 1, tzinfo=utc), + ), + ), + ] + }, + ) writer = MigrationWriter(migration) output = writer.as_string() self.assertIn( "import datetime\n" "from django.db import migrations, models\n" "from django.utils.timezone import utc\n", - output + output, ) def test_migration_file_header_comments(self): """ Test comments at top of file. """ - migration = type("Migration", (migrations.Migration,), { - "operations": [] - }) + migration = type("Migration", (migrations.Migration,), {"operations": []}) dt = datetime.datetime(2015, 7, 31, 4, 40, 0, 0, tzinfo=utc) - with mock.patch('django.db.migrations.writer.now', lambda: dt): + with mock.patch("django.db.migrations.writer.now", lambda: dt): for include_header in (True, False): with self.subTest(include_header=include_header): writer = MigrationWriter(migration, include_header) @@ -822,26 +916,36 @@ class WriterTests(SimpleTestCase): self.assertEqual( include_header, output.startswith( - "# Generated by Django %s on 2015-07-31 04:40\n\n" % get_version() - ) + "# Generated by Django %s on 2015-07-31 04:40\n\n" + % get_version() + ), ) if not include_header: # Make sure the output starts with something that's not # a comment or indentation or blank line - self.assertRegex(output.splitlines(keepends=True)[0], r"^[^#\s]+") + self.assertRegex( + output.splitlines(keepends=True)[0], r"^[^#\s]+" + ) def test_models_import_omitted(self): """ django.db.models shouldn't be imported if unused. """ - migration = type("Migration", (migrations.Migration,), { - "operations": [ - migrations.AlterModelOptions( - name='model', - options={'verbose_name': 'model', 'verbose_name_plural': 'models'}, - ), - ] - }) + migration = type( + "Migration", + (migrations.Migration,), + { + "operations": [ + migrations.AlterModelOptions( + name="model", + options={ + "verbose_name": "model", + "verbose_name_plural": "models", + }, + ), + ] + }, + ) writer = MigrationWriter(migration) output = writer.as_string() self.assertIn("from django.db import migrations\n", output) @@ -850,20 +954,27 @@ class WriterTests(SimpleTestCase): # Yes, it doesn't make sense to use a class as a default for a # CharField. It does make sense for custom fields though, for example # an enumfield that takes the enum class as an argument. - string = MigrationWriter.serialize(models.CharField(default=DeconstructibleInstances))[0] - self.assertEqual(string, "models.CharField(default=migrations.test_writer.DeconstructibleInstances)") + string = MigrationWriter.serialize( + models.CharField(default=DeconstructibleInstances) + )[0] + self.assertEqual( + string, + "models.CharField(default=migrations.test_writer.DeconstructibleInstances)", + ) def test_register_serializer(self): class ComplexSerializer(BaseSerializer): def serialize(self): - return 'complex(%r)' % self.value, {} + return "complex(%r)" % self.value, {} MigrationWriter.register_serializer(complex, ComplexSerializer) self.assertSerializedEqual(complex(1, 2)) MigrationWriter.unregister_serializer(complex) - with self.assertRaisesMessage(ValueError, 'Cannot serialize: (1+2j)'): + with self.assertRaisesMessage(ValueError, "Cannot serialize: (1+2j)"): self.assertSerializedEqual(complex(1, 2)) def test_register_non_serializer(self): - with self.assertRaisesMessage(ValueError, "'TestModel1' must inherit from 'BaseSerializer'."): + with self.assertRaisesMessage( + ValueError, "'TestModel1' must inherit from 'BaseSerializer'." + ): MigrationWriter.register_serializer(complex, TestModel1) |
