2013-06-07 22:28:38 +08:00
|
|
|
import datetime
|
2016-05-05 04:05:11 +08:00
|
|
|
import decimal
|
2017-01-20 02:55:20 +08:00
|
|
|
import enum
|
2015-07-29 00:51:25 +08:00
|
|
|
import functools
|
2014-11-06 19:29:43 +08:00
|
|
|
import math
|
2013-10-19 08:24:38 +08:00
|
|
|
import os
|
2020-05-01 22:05:20 +08:00
|
|
|
import pathlib
|
2014-07-05 00:48:13 +08:00
|
|
|
import re
|
2020-05-01 22:05:20 +08:00
|
|
|
import sys
|
2016-11-06 20:53:00 +08:00
|
|
|
import uuid
|
2017-01-20 01:16:04 +08:00
|
|
|
from unittest import mock
|
2013-08-23 19:56:37 +08:00
|
|
|
|
2021-09-09 21:15:44 +08:00
|
|
|
try:
|
|
|
|
import zoneinfo
|
|
|
|
except ImportError:
|
|
|
|
from backports import zoneinfo
|
|
|
|
|
|
|
|
try:
|
|
|
|
import pytz
|
|
|
|
except ImportError:
|
|
|
|
pytz = None
|
|
|
|
|
2015-01-28 20:35:27 +08:00
|
|
|
import custom_migration_operations.more_operations
|
|
|
|
import custom_migration_operations.operations
|
|
|
|
|
2015-08-11 15:51:01 +08:00
|
|
|
from django import get_version
|
2019-01-12 04:28:22 +08:00
|
|
|
from django.conf import SettingsReference, settings
|
2015-01-28 20:35:27 +08:00
|
|
|
from django.core.validators import EmailValidator, RegexValidator
|
|
|
|
from django.db import migrations, models
|
2019-01-11 02:05:19 +08:00
|
|
|
from django.db.migrations.serializer import BaseSerializer
|
2019-01-12 04:28:22 +08:00
|
|
|
from django.db.migrations.writer import MigrationWriter, OperationWriter
|
2022-03-24 18:09:55 +08:00
|
|
|
from django.test import SimpleTestCase, ignore_warnings
|
2013-10-22 01:33:57 +08:00
|
|
|
from django.utils.deconstruct import deconstructible
|
2022-03-24 18:09:55 +08:00
|
|
|
from django.utils.deprecation import RemovedInDjango50Warning
|
2015-11-26 01:31:23 +08:00
|
|
|
from django.utils.functional import SimpleLazyObject
|
2022-03-24 18:09:55 +08:00
|
|
|
from django.utils.timezone import get_default_timezone, get_fixed_timezone
|
2017-01-27 03:58:33 +08:00
|
|
|
from django.utils.translation import gettext_lazy as _
|
2014-06-11 21:00:52 +08:00
|
|
|
|
2015-01-28 20:35:27 +08:00
|
|
|
from .models import FoodManager, FoodQuerySet
|
2014-12-16 05:42:17 +08:00
|
|
|
|
2013-06-07 22:28:38 +08:00
|
|
|
|
2019-11-23 03:41:56 +08:00
|
|
|
class DeconstructibleInstances:
|
|
|
|
def deconstruct(self):
|
|
|
|
return ("DeconstructibleInstances", [], {})
|
|
|
|
|
|
|
|
|
2016-05-05 04:05:11 +08:00
|
|
|
class Money(decimal.Decimal):
|
|
|
|
def deconstruct(self):
|
|
|
|
return (
|
|
|
|
"%s.%s" % (self.__class__.__module__, self.__class__.__name__),
|
2016-12-29 23:27:49 +08:00
|
|
|
[str(self)],
|
2016-05-05 04:05:11 +08:00
|
|
|
{},
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2017-06-26 22:30:31 +08:00
|
|
|
class TestModel1:
|
2017-01-26 02:59:25 +08:00
|
|
|
def upload_to(self):
|
|
|
|
return "/somewhere/dynamic/"
|
2022-02-04 03:24:19 +08:00
|
|
|
|
2017-01-26 02:59:25 +08:00
|
|
|
thing = models.FileField(upload_to=upload_to)
|
|
|
|
|
|
|
|
|
2019-10-02 21:12:14 +08:00
|
|
|
class TextEnum(enum.Enum):
|
|
|
|
A = "a-value"
|
|
|
|
B = "value-b"
|
|
|
|
|
|
|
|
|
|
|
|
class TextTranslatedEnum(enum.Enum):
|
|
|
|
A = _("a-value")
|
|
|
|
B = _("value-b")
|
|
|
|
|
|
|
|
|
|
|
|
class BinaryEnum(enum.Enum):
|
|
|
|
A = b"a-value"
|
|
|
|
B = b"value-b"
|
|
|
|
|
|
|
|
|
|
|
|
class IntEnum(enum.IntEnum):
|
|
|
|
A = 1
|
|
|
|
B = 2
|
|
|
|
|
|
|
|
|
2015-01-08 04:10:56 +08:00
|
|
|
class OperationWriterTests(SimpleTestCase):
|
|
|
|
def test_empty_signature(self):
|
|
|
|
operation = custom_migration_operations.operations.TestOperation()
|
2015-02-07 08:52:26 +08:00
|
|
|
buff, imports = OperationWriter(operation, indentation=0).serialize()
|
2015-01-08 04:10:56 +08:00
|
|
|
self.assertEqual(imports, {"import custom_migration_operations.operations"})
|
|
|
|
self.assertEqual(
|
|
|
|
buff,
|
|
|
|
"custom_migration_operations.operations.TestOperation(\n),",
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_args_signature(self):
|
|
|
|
operation = custom_migration_operations.operations.ArgsOperation(1, 2)
|
2015-02-07 08:52:26 +08:00
|
|
|
buff, imports = OperationWriter(operation, indentation=0).serialize()
|
2015-01-08 04:10:56 +08:00
|
|
|
self.assertEqual(imports, {"import custom_migration_operations.operations"})
|
|
|
|
self.assertEqual(
|
|
|
|
buff,
|
|
|
|
"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)
|
2015-02-07 08:52:26 +08:00
|
|
|
buff, imports = OperationWriter(operation, indentation=0).serialize()
|
2015-01-08 04:10:56 +08:00
|
|
|
self.assertEqual(imports, {"import custom_migration_operations.operations"})
|
|
|
|
self.assertEqual(
|
|
|
|
buff,
|
|
|
|
"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
|
|
|
|
)
|
2015-02-07 08:52:26 +08:00
|
|
|
buff, imports = OperationWriter(operation, indentation=0).serialize()
|
2015-01-08 04:10:56 +08:00
|
|
|
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"
|
|
|
|
"),",
|
|
|
|
)
|
|
|
|
|
2015-04-05 21:59:23 +08:00
|
|
|
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),
|
|
|
|
)
|
|
|
|
buff, imports = OperationWriter(operation, indentation=0).serialize()
|
|
|
|
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"
|
|
|
|
"),",
|
|
|
|
)
|
|
|
|
|
2015-02-07 08:52:26 +08:00
|
|
|
def test_multiline_args_signature(self):
|
|
|
|
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(
|
|
|
|
buff,
|
|
|
|
"custom_migration_operations.operations.ArgsOperation(\n"
|
|
|
|
" arg1='test\\n arg1',\n"
|
|
|
|
" arg2='test\\narg2',\n"
|
|
|
|
"),",
|
|
|
|
)
|
|
|
|
|
2015-01-08 04:10:56 +08:00
|
|
|
def test_expand_args_signature(self):
|
|
|
|
operation = custom_migration_operations.operations.ExpandArgsOperation([1, 2])
|
2015-02-07 08:52:26 +08:00
|
|
|
buff, imports = OperationWriter(operation, indentation=0).serialize()
|
2015-01-08 04:10:56 +08:00
|
|
|
self.assertEqual(imports, {"import custom_migration_operations.operations"})
|
|
|
|
self.assertEqual(
|
|
|
|
buff,
|
|
|
|
"custom_migration_operations.operations.ExpandArgsOperation(\n"
|
|
|
|
" arg=[\n"
|
|
|
|
" 1,\n"
|
|
|
|
" 2,\n"
|
|
|
|
" ],\n"
|
|
|
|
"),",
|
|
|
|
)
|
|
|
|
|
2015-04-05 21:59:23 +08:00
|
|
|
def test_nested_operation_expand_args_signature(self):
|
|
|
|
operation = custom_migration_operations.operations.ExpandArgsOperation(
|
|
|
|
arg=[
|
|
|
|
custom_migration_operations.operations.KwargsOperation(
|
|
|
|
kwarg1=1,
|
|
|
|
kwarg2=2,
|
|
|
|
),
|
|
|
|
]
|
|
|
|
)
|
|
|
|
buff, imports = OperationWriter(operation, indentation=0).serialize()
|
|
|
|
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"
|
|
|
|
"),",
|
|
|
|
)
|
|
|
|
|
2015-01-08 04:10:56 +08:00
|
|
|
|
2015-04-18 05:38:20 +08:00
|
|
|
class WriterTests(SimpleTestCase):
|
2013-06-07 22:28:38 +08:00
|
|
|
"""
|
|
|
|
Tests the migration writer (makes migration files from Migration instances)
|
|
|
|
"""
|
2022-02-04 03:24:19 +08:00
|
|
|
|
2019-10-02 21:19:22 +08:00
|
|
|
class NestedEnum(enum.IntEnum):
|
|
|
|
A = 1
|
|
|
|
B = 2
|
2013-06-07 22:28:38 +08:00
|
|
|
|
2019-11-22 20:43:03 +08:00
|
|
|
class NestedChoices(models.TextChoices):
|
|
|
|
X = "X", "X value"
|
|
|
|
Y = "Y", "Y value"
|
|
|
|
|
2013-06-08 00:56:43 +08:00
|
|
|
def safe_exec(self, string, value=None):
|
2016-11-15 06:40:28 +08:00
|
|
|
d = {}
|
2013-06-07 22:28:38 +08:00
|
|
|
try:
|
2017-01-12 06:17:25 +08:00
|
|
|
exec(string, globals(), d)
|
2013-06-08 00:56:43 +08:00
|
|
|
except Exception as e:
|
|
|
|
if value:
|
|
|
|
self.fail(
|
|
|
|
"Could not exec %r (from value %r): %s" % (string.strip(), value, e)
|
2022-02-04 03:24:19 +08:00
|
|
|
)
|
2013-06-08 00:56:43 +08:00
|
|
|
else:
|
|
|
|
self.fail("Could not exec %r: %s" % (string.strip(), e))
|
2016-11-15 06:40:28 +08:00
|
|
|
return d
|
2013-06-07 22:28:38 +08:00
|
|
|
|
2013-06-08 00:56:43 +08:00
|
|
|
def serialize_round_trip(self, value):
|
2013-06-07 22:28:38 +08:00
|
|
|
string, imports = MigrationWriter.serialize(value)
|
2013-06-08 00:56:43 +08:00
|
|
|
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)
|
2013-06-07 22:28:38 +08:00
|
|
|
|
2014-01-15 22:20:47 +08:00
|
|
|
def assertSerializedResultEqual(self, value, target):
|
|
|
|
self.assertEqual(MigrationWriter.serialize(value), target)
|
2013-06-08 00:56:43 +08:00
|
|
|
|
|
|
|
def assertSerializedFieldEqual(self, value):
|
|
|
|
new_value = self.serialize_round_trip(value)
|
|
|
|
self.assertEqual(value.__class__, new_value.__class__)
|
|
|
|
self.assertEqual(value.max_length, new_value.max_length)
|
|
|
|
self.assertEqual(value.null, new_value.null)
|
|
|
|
self.assertEqual(value.unique, new_value.unique)
|
2013-06-07 22:28:38 +08:00
|
|
|
|
2015-01-17 07:51:31 +08:00
|
|
|
def test_serialize_numbers(self):
|
2013-06-07 22:28:38 +08:00
|
|
|
self.assertSerializedEqual(1)
|
2014-11-06 19:29:43 +08:00
|
|
|
self.assertSerializedEqual(1.2)
|
|
|
|
self.assertTrue(math.isinf(self.serialize_round_trip(float("inf"))))
|
|
|
|
self.assertTrue(math.isinf(self.serialize_round_trip(float("-inf"))))
|
|
|
|
self.assertTrue(math.isnan(self.serialize_round_trip(float("nan"))))
|
2015-01-17 07:51:31 +08:00
|
|
|
|
2016-05-05 04:05:11 +08:00
|
|
|
self.assertSerializedEqual(decimal.Decimal("1.3"))
|
|
|
|
self.assertSerializedResultEqual(
|
|
|
|
decimal.Decimal("1.3"), ("Decimal('1.3')", {"from decimal import Decimal"})
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertSerializedEqual(Money("1.3"))
|
|
|
|
self.assertSerializedResultEqual(
|
|
|
|
Money("1.3"),
|
|
|
|
("migrations.test_writer.Money('1.3')", {"import migrations.test_writer"}),
|
|
|
|
)
|
|
|
|
|
2015-01-17 07:51:31 +08:00
|
|
|
def test_serialize_constants(self):
|
2013-06-07 22:28:38 +08:00
|
|
|
self.assertSerializedEqual(None)
|
2015-01-17 07:51:31 +08:00
|
|
|
self.assertSerializedEqual(True)
|
|
|
|
self.assertSerializedEqual(False)
|
|
|
|
|
|
|
|
def test_serialize_strings(self):
|
2013-08-23 19:56:37 +08:00
|
|
|
self.assertSerializedEqual(b"foobar")
|
2014-04-01 03:25:08 +08:00
|
|
|
string, imports = MigrationWriter.serialize(b"foobar")
|
|
|
|
self.assertEqual(string, "b'foobar'")
|
2013-08-23 19:56:37 +08:00
|
|
|
self.assertSerializedEqual("föobár")
|
2014-04-01 03:25:08 +08:00
|
|
|
string, imports = MigrationWriter.serialize("foobar")
|
|
|
|
self.assertEqual(string, "'foobar'")
|
2015-01-17 07:51:31 +08:00
|
|
|
|
2015-02-07 08:52:26 +08:00
|
|
|
def test_serialize_multiline_strings(self):
|
|
|
|
self.assertSerializedEqual(b"foo\nbar")
|
|
|
|
string, imports = MigrationWriter.serialize(b"foo\nbar")
|
|
|
|
self.assertEqual(string, "b'foo\\nbar'")
|
|
|
|
self.assertSerializedEqual("föo\nbár")
|
|
|
|
string, imports = MigrationWriter.serialize("foo\nbar")
|
|
|
|
self.assertEqual(string, "'foo\\nbar'")
|
|
|
|
|
2015-01-17 07:51:31 +08:00
|
|
|
def test_serialize_collections(self):
|
2013-06-07 22:28:38 +08:00
|
|
|
self.assertSerializedEqual({1: 2})
|
|
|
|
self.assertSerializedEqual(["a", 2, True, None])
|
2014-09-26 20:31:50 +08:00
|
|
|
self.assertSerializedEqual({2, 3, "eighty"})
|
2013-06-07 22:28:38 +08:00
|
|
|
self.assertSerializedEqual({"lalalala": ["yeah", "no", "maybe"]})
|
2013-09-01 03:11:37 +08:00
|
|
|
self.assertSerializedEqual(_("Hello"))
|
2015-01-17 07:51:31 +08:00
|
|
|
|
|
|
|
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()),
|
|
|
|
)
|
|
|
|
|
2015-11-26 01:31:23 +08:00
|
|
|
def test_serialize_lazy_objects(self):
|
2017-01-19 05:52:25 +08:00
|
|
|
pattern = re.compile(r"^foo$")
|
2015-11-26 01:31:23 +08:00
|
|
|
lazy_pattern = SimpleLazyObject(lambda: pattern)
|
|
|
|
self.assertEqual(self.serialize_round_trip(lazy_pattern), pattern)
|
|
|
|
|
2015-11-17 05:41:46 +08:00
|
|
|
def test_serialize_enums(self):
|
|
|
|
self.assertSerializedResultEqual(
|
|
|
|
TextEnum.A,
|
2019-09-25 05:42:35 +08:00
|
|
|
("migrations.test_writer.TextEnum['A']", {"import migrations.test_writer"}),
|
|
|
|
)
|
|
|
|
self.assertSerializedResultEqual(
|
|
|
|
TextTranslatedEnum.A,
|
|
|
|
(
|
|
|
|
"migrations.test_writer.TextTranslatedEnum['A']",
|
|
|
|
{"import migrations.test_writer"},
|
2022-02-04 03:24:19 +08:00
|
|
|
),
|
2015-11-17 05:41:46 +08:00
|
|
|
)
|
|
|
|
self.assertSerializedResultEqual(
|
|
|
|
BinaryEnum.A,
|
2019-09-25 05:42:35 +08:00
|
|
|
(
|
|
|
|
"migrations.test_writer.BinaryEnum['A']",
|
|
|
|
{"import migrations.test_writer"},
|
2022-02-04 03:24:19 +08:00
|
|
|
),
|
2015-11-17 05:41:46 +08:00
|
|
|
)
|
|
|
|
self.assertSerializedResultEqual(
|
|
|
|
IntEnum.B,
|
2019-09-25 05:42:35 +08:00
|
|
|
("migrations.test_writer.IntEnum['B']", {"import migrations.test_writer"}),
|
2015-11-17 05:41:46 +08:00
|
|
|
)
|
2019-10-02 21:19:22 +08:00
|
|
|
self.assertSerializedResultEqual(
|
|
|
|
self.NestedEnum.A,
|
|
|
|
(
|
|
|
|
"migrations.test_writer.WriterTests.NestedEnum['A']",
|
|
|
|
{"import migrations.test_writer"},
|
|
|
|
),
|
|
|
|
)
|
|
|
|
self.assertSerializedEqual(self.NestedEnum.A)
|
2015-11-17 05:41:46 +08:00
|
|
|
|
|
|
|
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=["
|
2019-09-25 05:42:35 +08:00
|
|
|
"('a-value', migrations.test_writer.TextEnum['A']), "
|
|
|
|
"('value-b', migrations.test_writer.TextEnum['B'])], "
|
|
|
|
"default=migrations.test_writer.TextEnum['B'])",
|
|
|
|
)
|
|
|
|
field = models.CharField(
|
|
|
|
default=TextTranslatedEnum.A,
|
|
|
|
choices=[(m.value, m) for m in TextTranslatedEnum],
|
|
|
|
)
|
|
|
|
string = MigrationWriter.serialize(field)[0]
|
|
|
|
self.assertEqual(
|
|
|
|
string,
|
|
|
|
"models.CharField(choices=["
|
|
|
|
"('a-value', migrations.test_writer.TextTranslatedEnum['A']), "
|
|
|
|
"('value-b', migrations.test_writer.TextTranslatedEnum['B'])], "
|
|
|
|
"default=migrations.test_writer.TextTranslatedEnum['A'])",
|
2022-02-04 03:24:19 +08:00
|
|
|
)
|
2019-09-25 05:42:35 +08:00
|
|
|
field = models.CharField(
|
2015-11-17 05:41:46 +08:00
|
|
|
default=BinaryEnum.B, choices=[(m.value, m) for m in BinaryEnum]
|
|
|
|
)
|
|
|
|
string = MigrationWriter.serialize(field)[0]
|
|
|
|
self.assertEqual(
|
|
|
|
string,
|
|
|
|
"models.CharField(choices=["
|
2019-09-25 05:42:35 +08:00
|
|
|
"(b'a-value', migrations.test_writer.BinaryEnum['A']), "
|
|
|
|
"(b'value-b', migrations.test_writer.BinaryEnum['B'])], "
|
|
|
|
"default=migrations.test_writer.BinaryEnum['B'])",
|
2022-02-04 03:24:19 +08:00
|
|
|
)
|
2019-01-01 01:57:35 +08:00
|
|
|
field = models.IntegerField(
|
2015-11-17 05:41:46 +08:00
|
|
|
default=IntEnum.A, choices=[(m.value, m) for m in IntEnum]
|
|
|
|
)
|
|
|
|
string = MigrationWriter.serialize(field)[0]
|
|
|
|
self.assertEqual(
|
|
|
|
string,
|
|
|
|
"models.IntegerField(choices=["
|
2019-09-25 05:42:35 +08:00
|
|
|
"(1, migrations.test_writer.IntEnum['A']), "
|
|
|
|
"(2, migrations.test_writer.IntEnum['B'])], "
|
|
|
|
"default=migrations.test_writer.IntEnum['A'])",
|
2015-11-17 05:41:46 +08:00
|
|
|
)
|
|
|
|
|
2019-01-01 01:57:35 +08:00
|
|
|
def test_serialize_choices(self):
|
|
|
|
class TextChoices(models.TextChoices):
|
|
|
|
A = "A", "A value"
|
|
|
|
B = "B", "B value"
|
|
|
|
|
|
|
|
class IntegerChoices(models.IntegerChoices):
|
|
|
|
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"
|
|
|
|
|
|
|
|
self.assertSerializedResultEqual(TextChoices.A, ("'A'", set()))
|
|
|
|
self.assertSerializedResultEqual(IntegerChoices.A, ("1", set()))
|
|
|
|
self.assertSerializedResultEqual(
|
|
|
|
DateChoices.DATE_1,
|
|
|
|
("datetime.date(1969, 7, 20)", {"import datetime"}),
|
|
|
|
)
|
|
|
|
field = models.CharField(default=TextChoices.B, choices=TextChoices.choices)
|
|
|
|
string = MigrationWriter.serialize(field)[0]
|
|
|
|
self.assertEqual(
|
|
|
|
string,
|
|
|
|
"models.CharField(choices=[('A', 'A value'), ('B', 'B value')], "
|
|
|
|
"default='B')",
|
|
|
|
)
|
|
|
|
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
|
|
|
|
)
|
|
|
|
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))",
|
|
|
|
)
|
|
|
|
|
2019-11-22 20:43:03 +08:00
|
|
|
def test_serialize_nested_class(self):
|
|
|
|
for nested_cls in [self.NestedEnum, self.NestedChoices]:
|
|
|
|
cls_name = nested_cls.__name__
|
|
|
|
with self.subTest(cls_name):
|
|
|
|
self.assertSerializedResultEqual(
|
|
|
|
nested_cls,
|
|
|
|
(
|
|
|
|
"migrations.test_writer.WriterTests.%s" % cls_name,
|
|
|
|
{"import migrations.test_writer"},
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
2016-11-06 20:53:00 +08:00
|
|
|
def test_serialize_uuid(self):
|
|
|
|
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")
|
|
|
|
self.assertSerializedResultEqual(
|
|
|
|
uuid_a,
|
|
|
|
("uuid.UUID('5c859437-d061-4847-b3f7-e6b78852f8c8')", {"import uuid"}),
|
|
|
|
)
|
|
|
|
self.assertSerializedResultEqual(
|
|
|
|
uuid_b,
|
|
|
|
("uuid.UUID('c7853ec1-2ea3-4359-b02d-b54e8f1bcee2')", {"import uuid"}),
|
|
|
|
)
|
|
|
|
|
|
|
|
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'))",
|
|
|
|
)
|
|
|
|
|
2020-05-01 22:05:20 +08:00
|
|
|
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"})
|
|
|
|
self.assertSerializedResultEqual(path, expected)
|
|
|
|
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":
|
|
|
|
self.assertSerializedEqual(pathlib.WindowsPath.cwd())
|
|
|
|
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"})
|
|
|
|
self.assertSerializedResultEqual(path, expected)
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
def test_serialize_path_like(self):
|
2021-06-06 14:56:34 +08:00
|
|
|
with os.scandir(os.path.dirname(__file__)) as entries:
|
|
|
|
path_like = list(entries)[0]
|
2020-05-01 22:05:20 +08:00
|
|
|
expected = (repr(path_like.path), {})
|
|
|
|
self.assertSerializedResultEqual(path_like, expected)
|
|
|
|
|
|
|
|
field = models.FilePathField(path=path_like)
|
|
|
|
string = MigrationWriter.serialize(field)[0]
|
|
|
|
self.assertEqual(string, "models.FilePathField(path=%r)" % path_like.path)
|
|
|
|
|
2015-01-17 07:51:31 +08:00
|
|
|
def test_serialize_functions(self):
|
2016-01-18 16:45:45 +08:00
|
|
|
with self.assertRaisesMessage(ValueError, "Cannot serialize function: lambda"):
|
2013-09-05 11:36:31 +08:00
|
|
|
self.assertSerializedEqual(lambda x: 42)
|
2013-09-02 14:02:07 +08:00
|
|
|
self.assertSerializedEqual(models.SET_NULL)
|
|
|
|
string, imports = MigrationWriter.serialize(models.SET(42))
|
|
|
|
self.assertEqual(string, "models.SET(42)")
|
|
|
|
self.serialize_round_trip(models.SET(42))
|
2015-01-17 07:51:31 +08:00
|
|
|
|
|
|
|
def test_serialize_datetime(self):
|
2021-05-07 17:42:59 +08:00
|
|
|
self.assertSerializedEqual(datetime.datetime.now())
|
|
|
|
self.assertSerializedEqual(datetime.datetime.now)
|
2013-10-19 01:14:01 +08:00
|
|
|
self.assertSerializedEqual(datetime.datetime.today())
|
|
|
|
self.assertSerializedEqual(datetime.datetime.today)
|
2013-06-07 22:28:38 +08:00
|
|
|
self.assertSerializedEqual(datetime.date.today())
|
|
|
|
self.assertSerializedEqual(datetime.date.today)
|
2014-08-19 21:23:29 +08:00
|
|
|
self.assertSerializedEqual(datetime.datetime.now().time())
|
2014-09-07 04:42:36 +08:00
|
|
|
self.assertSerializedEqual(
|
|
|
|
datetime.datetime(2014, 1, 1, 1, 1, tzinfo=get_default_timezone())
|
2022-02-04 03:24:19 +08:00
|
|
|
)
|
2018-07-10 04:33:36 +08:00
|
|
|
self.assertSerializedEqual(
|
|
|
|
datetime.datetime(2013, 12, 31, 22, 1, tzinfo=get_fixed_timezone(180))
|
2022-02-04 03:24:19 +08:00
|
|
|
)
|
2015-01-17 07:51:31 +08:00
|
|
|
self.assertSerializedResultEqual(
|
|
|
|
datetime.datetime(2014, 1, 1, 1, 1),
|
|
|
|
("datetime.datetime(2014, 1, 1, 1, 1)", {"import datetime"}),
|
|
|
|
)
|
2022-03-24 18:09:55 +08:00
|
|
|
with ignore_warnings(category=RemovedInDjango50Warning):
|
|
|
|
from django.utils.timezone import utc
|
2021-05-07 20:56:57 +08:00
|
|
|
for tzinfo in (utc, datetime.timezone.utc):
|
|
|
|
with self.subTest(tzinfo=tzinfo):
|
|
|
|
self.assertSerializedResultEqual(
|
|
|
|
datetime.datetime(2012, 1, 1, 1, 1, tzinfo=tzinfo),
|
|
|
|
(
|
2022-03-23 18:48:52 +08:00
|
|
|
"datetime.datetime"
|
|
|
|
"(2012, 1, 1, 1, 1, tzinfo=datetime.timezone.utc)",
|
|
|
|
{"import datetime"},
|
2021-05-07 20:56:57 +08:00
|
|
|
),
|
|
|
|
)
|
2015-01-17 07:51:31 +08:00
|
|
|
|
2021-09-09 21:15:44 +08:00
|
|
|
self.assertSerializedResultEqual(
|
|
|
|
datetime.datetime(
|
|
|
|
2012, 1, 1, 2, 1, tzinfo=zoneinfo.ZoneInfo("Europe/Paris")
|
|
|
|
),
|
|
|
|
(
|
2022-03-23 18:48:52 +08:00
|
|
|
"datetime.datetime(2012, 1, 1, 1, 1, tzinfo=datetime.timezone.utc)",
|
|
|
|
{"import datetime"},
|
2021-09-09 21:15:44 +08:00
|
|
|
),
|
|
|
|
)
|
|
|
|
if pytz:
|
|
|
|
self.assertSerializedResultEqual(
|
|
|
|
pytz.timezone("Europe/Paris").localize(
|
|
|
|
datetime.datetime(2012, 1, 1, 2, 1)
|
|
|
|
),
|
|
|
|
(
|
2022-03-23 18:48:52 +08:00
|
|
|
"datetime.datetime(2012, 1, 1, 1, 1, tzinfo=datetime.timezone.utc)",
|
|
|
|
{"import datetime"},
|
2021-09-09 21:15:44 +08:00
|
|
|
),
|
|
|
|
)
|
|
|
|
|
2015-01-17 07:51:31 +08:00
|
|
|
def test_serialize_fields(self):
|
2013-06-08 00:56:43 +08:00
|
|
|
self.assertSerializedFieldEqual(models.CharField(max_length=255))
|
2015-01-17 07:55:41 +08:00
|
|
|
self.assertSerializedResultEqual(
|
|
|
|
models.CharField(max_length=255),
|
|
|
|
("models.CharField(max_length=255)", {"from django.db import models"}),
|
|
|
|
)
|
2013-06-08 00:56:43 +08:00
|
|
|
self.assertSerializedFieldEqual(models.TextField(null=True, blank=True))
|
2015-01-17 07:55:41 +08:00
|
|
|
self.assertSerializedResultEqual(
|
|
|
|
models.TextField(null=True, blank=True),
|
|
|
|
(
|
|
|
|
"models.TextField(blank=True, null=True)",
|
|
|
|
{"from django.db import models"},
|
2022-02-04 03:24:19 +08:00
|
|
|
),
|
2015-01-17 07:55:41 +08:00
|
|
|
)
|
2015-01-17 07:51:31 +08:00
|
|
|
|
|
|
|
def test_serialize_settings(self):
|
2014-01-15 22:20:47 +08:00
|
|
|
self.assertSerializedEqual(
|
|
|
|
SettingsReference(settings.AUTH_USER_MODEL, "AUTH_USER_MODEL")
|
2022-02-04 03:24:19 +08:00
|
|
|
)
|
2014-01-15 22:20:47 +08:00
|
|
|
self.assertSerializedResultEqual(
|
|
|
|
SettingsReference("someapp.model", "AUTH_USER_MODEL"),
|
2015-01-17 07:51:31 +08:00
|
|
|
("settings.AUTH_USER_MODEL", {"from django.conf import settings"}),
|
2014-01-15 22:20:47 +08:00
|
|
|
)
|
2016-01-28 20:06:53 +08:00
|
|
|
|
|
|
|
def test_serialize_iterators(self):
|
2014-01-22 16:06:06 +08:00
|
|
|
self.assertSerializedResultEqual(
|
2015-01-17 07:51:31 +08:00
|
|
|
((x, x * x) for x in range(3)), ("((0, 0), (1, 1), (2, 4))", set())
|
2014-01-22 16:06:06 +08:00
|
|
|
)
|
2013-06-07 22:28:38 +08:00
|
|
|
|
2014-07-05 00:48:13 +08:00
|
|
|
def test_serialize_compiled_regex(self):
|
|
|
|
"""
|
|
|
|
Make sure compiled regex can be serialized.
|
|
|
|
"""
|
2017-01-19 05:52:25 +08:00
|
|
|
regex = re.compile(r"^\w+$")
|
2014-07-05 00:48:13 +08:00
|
|
|
self.assertSerializedEqual(regex)
|
|
|
|
|
|
|
|
def test_serialize_class_based_validators(self):
|
|
|
|
"""
|
|
|
|
Ticket #22943: Test serialization of class-based validators, including
|
|
|
|
compiled regexes.
|
|
|
|
"""
|
|
|
|
validator = RegexValidator(message="hello")
|
|
|
|
string = MigrationWriter.serialize(validator)[0]
|
|
|
|
self.assertEqual(
|
|
|
|
string, "django.core.validators.RegexValidator(message='hello')"
|
|
|
|
)
|
|
|
|
self.serialize_round_trip(validator)
|
|
|
|
|
|
|
|
# Test with a compiled regex.
|
2017-01-19 05:52:25 +08:00
|
|
|
validator = RegexValidator(regex=re.compile(r"^\w+$"))
|
2014-07-05 00:48:13 +08:00
|
|
|
string = MigrationWriter.serialize(validator)[0]
|
2017-01-19 05:52:25 +08:00
|
|
|
self.assertEqual(
|
|
|
|
string,
|
|
|
|
"django.core.validators.RegexValidator(regex=re.compile('^\\\\w+$'))",
|
|
|
|
)
|
2014-07-05 00:48:13 +08:00
|
|
|
self.serialize_round_trip(validator)
|
|
|
|
|
|
|
|
# Test a string regex with flag
|
2017-01-19 05:52:25 +08:00
|
|
|
validator = RegexValidator(r"^[0-9]+$", flags=re.S)
|
2014-07-05 00:48:13 +08:00
|
|
|
string = MigrationWriter.serialize(validator)[0]
|
2019-09-25 05:42:35 +08:00
|
|
|
self.assertEqual(
|
|
|
|
string,
|
|
|
|
"django.core.validators.RegexValidator('^[0-9]+$', "
|
|
|
|
"flags=re.RegexFlag['DOTALL'])",
|
|
|
|
)
|
2014-07-05 00:48:13 +08:00
|
|
|
self.serialize_round_trip(validator)
|
|
|
|
|
|
|
|
# Test message and code
|
|
|
|
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.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.serialize_round_trip(validator)
|
|
|
|
|
2014-09-08 09:01:42 +08:00
|
|
|
validator = deconstructible(path="migrations.test_writer.EmailValidator")(
|
|
|
|
EmailValidator
|
|
|
|
)(message="hello")
|
2014-07-05 00:48:13 +08:00
|
|
|
string = MigrationWriter.serialize(validator)[0]
|
2014-09-08 09:01:42 +08:00
|
|
|
self.assertEqual(
|
|
|
|
string, "migrations.test_writer.EmailValidator(message='hello')"
|
|
|
|
)
|
|
|
|
|
|
|
|
validator = deconstructible(path="custom.EmailValidator")(EmailValidator)(
|
|
|
|
message="hello"
|
|
|
|
)
|
2017-01-20 10:10:33 +08:00
|
|
|
with self.assertRaisesMessage(ImportError, "No module named 'custom'"):
|
2014-09-08 09:01:42 +08:00
|
|
|
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.",
|
|
|
|
):
|
|
|
|
MigrationWriter.serialize(validator)
|
2014-07-05 00:48:13 +08:00
|
|
|
|
2021-12-06 16:47:22 +08:00
|
|
|
def test_serialize_complex_func_index(self):
|
|
|
|
index = models.Index(
|
|
|
|
models.Func("rating", function="ABS"),
|
|
|
|
models.Case(
|
|
|
|
models.When(name="special", then=models.Value("X")),
|
|
|
|
default=models.Value("other"),
|
|
|
|
),
|
|
|
|
models.ExpressionWrapper(
|
|
|
|
models.F("pages"),
|
|
|
|
output_field=models.IntegerField(),
|
|
|
|
),
|
|
|
|
models.OrderBy(models.F("name").desc()),
|
|
|
|
name="complex_func_index",
|
|
|
|
)
|
|
|
|
string, imports = MigrationWriter.serialize(index)
|
|
|
|
self.assertEqual(
|
|
|
|
string,
|
|
|
|
"models.Index(models.Func('rating', function='ABS'), "
|
|
|
|
"models.Case(models.When(name='special', then=models.Value('X')), "
|
|
|
|
"default=models.Value('other')), "
|
|
|
|
"models.ExpressionWrapper("
|
|
|
|
"models.F('pages'), output_field=models.IntegerField()), "
|
|
|
|
"models.OrderBy(models.OrderBy(models.F('name'), descending=True)), "
|
|
|
|
"name='complex_func_index')",
|
|
|
|
)
|
|
|
|
self.assertEqual(imports, {"from django.db import models"})
|
|
|
|
|
2014-05-22 19:29:30 +08:00
|
|
|
def test_serialize_empty_nonempty_tuple(self):
|
|
|
|
"""
|
|
|
|
Ticket #22679: makemigrations generates invalid code for (an empty
|
|
|
|
tuple) default_permissions = ()
|
|
|
|
"""
|
|
|
|
empty_tuple = ()
|
2014-05-23 20:50:10 +08:00
|
|
|
one_item_tuple = ("a",)
|
2014-05-22 19:29:30 +08:00
|
|
|
many_items_tuple = ("a", "b", "c")
|
|
|
|
self.assertSerializedEqual(empty_tuple)
|
|
|
|
self.assertSerializedEqual(one_item_tuple)
|
|
|
|
self.assertSerializedEqual(many_items_tuple)
|
|
|
|
|
2019-04-13 21:03:26 +08:00
|
|
|
def test_serialize_range(self):
|
|
|
|
string, imports = MigrationWriter.serialize(range(1, 5))
|
|
|
|
self.assertEqual(string, "range(1, 5)")
|
|
|
|
self.assertEqual(imports, set())
|
|
|
|
|
2015-07-29 04:08:28 +08:00
|
|
|
def test_serialize_builtins(self):
|
|
|
|
string, imports = MigrationWriter.serialize(range)
|
|
|
|
self.assertEqual(string, "range")
|
|
|
|
self.assertEqual(imports, set())
|
|
|
|
|
2017-01-26 02:59:25 +08:00
|
|
|
def test_serialize_unbound_method_reference(self):
|
|
|
|
"""An unbound method used within a class body can be serialized."""
|
|
|
|
self.serialize_round_trip(TestModel1.thing)
|
2014-06-08 08:04:58 +08:00
|
|
|
|
2017-01-26 02:59:25 +08:00
|
|
|
def test_serialize_local_function_reference(self):
|
|
|
|
"""A reference in a local scope can't be serialized."""
|
2022-02-04 03:24:19 +08:00
|
|
|
|
2017-01-19 15:39:46 +08:00
|
|
|
class TestModel2:
|
2014-07-02 04:42:25 +08:00
|
|
|
def upload_to(self):
|
|
|
|
return "somewhere dynamic"
|
2022-02-04 03:24:19 +08:00
|
|
|
|
2014-07-02 04:42:25 +08:00
|
|
|
thing = models.FileField(upload_to=upload_to)
|
|
|
|
|
2016-01-18 16:45:45 +08:00
|
|
|
with self.assertRaisesMessage(
|
|
|
|
ValueError, "Could not find function upload_to in migrations.test_writer"
|
|
|
|
):
|
2014-07-02 04:42:25 +08:00
|
|
|
self.serialize_round_trip(TestModel2.thing)
|
|
|
|
|
2015-01-17 07:51:31 +08:00
|
|
|
def test_serialize_managers(self):
|
|
|
|
self.assertSerializedEqual(models.Manager())
|
|
|
|
self.assertSerializedResultEqual(
|
|
|
|
FoodQuerySet.as_manager(),
|
|
|
|
(
|
|
|
|
"migrations.models.FoodQuerySet.as_manager()",
|
|
|
|
{"import migrations.models"},
|
2022-02-04 03:24:19 +08:00
|
|
|
),
|
2015-01-17 07:51:31 +08:00
|
|
|
)
|
|
|
|
self.assertSerializedEqual(FoodManager("a", "b"))
|
|
|
|
self.assertSerializedEqual(FoodManager("x", "y", c=3, d=4))
|
|
|
|
|
2015-03-23 22:38:25 +08:00
|
|
|
def test_serialize_frozensets(self):
|
|
|
|
self.assertSerializedEqual(frozenset())
|
|
|
|
self.assertSerializedEqual(frozenset("let it go"))
|
|
|
|
|
2017-05-18 21:33:40 +08:00
|
|
|
def test_serialize_set(self):
|
|
|
|
self.assertSerializedEqual(set())
|
|
|
|
self.assertSerializedResultEqual(set(), ("set()", set()))
|
|
|
|
self.assertSerializedEqual({"a"})
|
|
|
|
self.assertSerializedResultEqual({"a"}, ("{'a'}", set()))
|
|
|
|
|
2015-04-02 22:49:41 +08:00
|
|
|
def test_serialize_timedelta(self):
|
|
|
|
self.assertSerializedEqual(datetime.timedelta())
|
|
|
|
self.assertSerializedEqual(datetime.timedelta(minutes=42))
|
|
|
|
|
2015-07-29 00:51:25 +08:00
|
|
|
def test_serialize_functools_partial(self):
|
|
|
|
value = functools.partial(datetime.timedelta, 1, seconds=2)
|
|
|
|
result = self.serialize_round_trip(value)
|
|
|
|
self.assertEqual(result.func, value.func)
|
|
|
|
self.assertEqual(result.args, value.args)
|
|
|
|
self.assertEqual(result.keywords, value.keywords)
|
|
|
|
|
2017-12-01 22:24:56 +08:00
|
|
|
def test_serialize_functools_partialmethod(self):
|
|
|
|
value = functools.partialmethod(datetime.timedelta, 1, seconds=2)
|
|
|
|
result = self.serialize_round_trip(value)
|
|
|
|
self.assertIsInstance(result, functools.partialmethod)
|
|
|
|
self.assertEqual(result.func, value.func)
|
|
|
|
self.assertEqual(result.args, value.args)
|
|
|
|
self.assertEqual(result.keywords, value.keywords)
|
|
|
|
|
2018-10-11 19:54:37 +08:00
|
|
|
def test_serialize_type_none(self):
|
|
|
|
self.assertSerializedEqual(type(None))
|
|
|
|
|
2021-07-01 15:28:02 +08:00
|
|
|
def test_serialize_type_model(self):
|
|
|
|
self.assertSerializedEqual(models.Model)
|
|
|
|
self.assertSerializedResultEqual(
|
|
|
|
MigrationWriter.serialize(models.Model),
|
|
|
|
("('models.Model', {'from django.db import models'})", set()),
|
|
|
|
)
|
|
|
|
|
2013-06-07 22:28:38 +08:00
|
|
|
def test_simple_migration(self):
|
|
|
|
"""
|
|
|
|
Tests serializing a simple migration.
|
|
|
|
"""
|
2013-09-26 15:25:35 +08:00
|
|
|
fields = {
|
2021-05-07 17:42:59 +08:00
|
|
|
"charfield": models.DateTimeField(default=datetime.datetime.now),
|
|
|
|
"datetimefield": models.DateTimeField(default=datetime.datetime.now),
|
2013-09-26 15:25:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
options = {
|
|
|
|
"verbose_name": "My model",
|
|
|
|
"verbose_name_plural": "My models",
|
|
|
|
}
|
|
|
|
|
2017-01-19 22:48:01 +08:00
|
|
|
migration = type(
|
|
|
|
"Migration",
|
|
|
|
(migrations.Migration,),
|
|
|
|
{
|
2013-06-07 22:28:38 +08:00
|
|
|
"operations": [
|
2013-09-26 15:25:35 +08:00
|
|
|
migrations.CreateModel(
|
|
|
|
"MyModel", tuple(fields.items()), options, (models.Model,)
|
|
|
|
),
|
|
|
|
migrations.CreateModel(
|
|
|
|
"MyModel2", tuple(fields.items()), bases=(models.Model,)
|
2022-02-04 03:24:19 +08:00
|
|
|
),
|
2015-09-12 07:33:12 +08:00
|
|
|
migrations.CreateModel(
|
|
|
|
name="MyModel3",
|
|
|
|
fields=tuple(fields.items()),
|
|
|
|
options=options,
|
|
|
|
bases=(models.Model,),
|
|
|
|
),
|
2013-06-07 22:28:38 +08:00
|
|
|
migrations.DeleteModel("MyModel"),
|
2013-09-26 15:25:35 +08:00
|
|
|
migrations.AddField(
|
|
|
|
"OtherModel", "datetimefield", fields["datetimefield"]
|
|
|
|
),
|
2013-06-07 22:28:38 +08:00
|
|
|
],
|
|
|
|
"dependencies": [("testapp", "some_other_one")],
|
|
|
|
},
|
|
|
|
)
|
|
|
|
writer = MigrationWriter(migration)
|
|
|
|
output = writer.as_string()
|
2013-06-08 00:56:43 +08:00
|
|
|
# We don't test the output formatting - that's too fragile.
|
|
|
|
# Just make sure it runs for now, and that things look alright.
|
|
|
|
result = self.safe_exec(output)
|
|
|
|
self.assertIn("Migration", result)
|
2017-01-20 17:20:53 +08:00
|
|
|
|
2013-10-19 08:24:38 +08:00
|
|
|
def test_migration_path(self):
|
|
|
|
test_apps = [
|
|
|
|
"migrations.migrations_test_apps.normal",
|
|
|
|
"migrations.migrations_test_apps.with_package_model",
|
2014-06-17 23:50:31 +08:00
|
|
|
"migrations.migrations_test_apps.without_init_file",
|
2013-10-19 08:24:38 +08:00
|
|
|
]
|
|
|
|
|
2017-01-20 21:01:02 +08:00
|
|
|
base_dir = os.path.dirname(os.path.dirname(__file__))
|
2013-10-19 08:24:38 +08:00
|
|
|
|
2013-12-20 05:33:46 +08:00
|
|
|
for app in test_apps:
|
2013-12-23 17:37:34 +08:00
|
|
|
with self.modify_settings(INSTALLED_APPS={"append": app}):
|
2013-12-20 05:33:46 +08:00
|
|
|
migration = migrations.Migration("0001_initial", app.split(".")[-1])
|
|
|
|
expected_path = os.path.join(
|
|
|
|
base_dir, *(app.split(".") + ["migrations", "0001_initial.py"])
|
2022-02-04 03:24:19 +08:00
|
|
|
)
|
2013-12-20 05:33:46 +08:00
|
|
|
writer = MigrationWriter(migration)
|
2014-12-22 04:19:05 +08:00
|
|
|
self.assertEqual(writer.path, expected_path)
|
2014-06-11 21:00:52 +08:00
|
|
|
|
|
|
|
def test_custom_operation(self):
|
2017-01-19 22:48:01 +08:00
|
|
|
migration = type(
|
|
|
|
"Migration",
|
|
|
|
(migrations.Migration,),
|
|
|
|
{
|
2014-06-11 21:00:52 +08:00
|
|
|
"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,
|
|
|
|
)
|
2014-09-07 04:42:36 +08:00
|
|
|
|
2015-01-17 07:55:41 +08:00
|
|
|
def test_sorted_imports(self):
|
|
|
|
"""
|
|
|
|
#24155 - Tests ordering of imports.
|
|
|
|
"""
|
2017-01-19 22:48:01 +08:00
|
|
|
migration = type(
|
|
|
|
"Migration",
|
|
|
|
(migrations.Migration,),
|
|
|
|
{
|
2015-01-17 07:55:41 +08:00
|
|
|
"operations": [
|
|
|
|
migrations.AddField(
|
|
|
|
"mymodel",
|
|
|
|
"myfield",
|
|
|
|
models.DateTimeField(
|
2022-03-23 18:48:52 +08:00
|
|
|
default=datetime.datetime(
|
|
|
|
2012, 1, 1, 1, 1, tzinfo=datetime.timezone.utc
|
|
|
|
),
|
2015-01-17 07:55:41 +08:00
|
|
|
),
|
2022-02-04 03:24:19 +08:00
|
|
|
),
|
2015-01-17 07:55:41 +08:00
|
|
|
]
|
|
|
|
},
|
|
|
|
)
|
|
|
|
writer = MigrationWriter(migration)
|
2016-10-01 00:28:48 +08:00
|
|
|
output = writer.as_string()
|
2015-01-17 07:55:41 +08:00
|
|
|
self.assertIn(
|
2022-03-23 18:48:52 +08:00
|
|
|
"import datetime\nfrom django.db import migrations, models\n",
|
2015-01-17 07:55:41 +08:00
|
|
|
output,
|
|
|
|
)
|
|
|
|
|
2015-08-11 15:51:01 +08:00
|
|
|
def test_migration_file_header_comments(self):
|
|
|
|
"""
|
|
|
|
Test comments at top of file.
|
|
|
|
"""
|
2017-01-19 22:48:01 +08:00
|
|
|
migration = type("Migration", (migrations.Migration,), {"operations": []})
|
2022-03-23 19:15:36 +08:00
|
|
|
dt = datetime.datetime(2015, 7, 31, 4, 40, 0, 0, tzinfo=datetime.timezone.utc)
|
2015-08-11 15:51:01 +08:00
|
|
|
with mock.patch("django.db.migrations.writer.now", lambda: dt):
|
2018-12-19 19:41:31 +08:00
|
|
|
for include_header in (True, False):
|
|
|
|
with self.subTest(include_header=include_header):
|
|
|
|
writer = MigrationWriter(migration, include_header)
|
|
|
|
output = writer.as_string()
|
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
include_header,
|
|
|
|
output.startswith(
|
|
|
|
"# 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]+"
|
|
|
|
)
|
2015-08-11 15:51:01 +08:00
|
|
|
|
2015-03-29 08:09:44 +08:00
|
|
|
def test_models_import_omitted(self):
|
|
|
|
"""
|
|
|
|
django.db.models shouldn't be imported if unused.
|
|
|
|
"""
|
2017-01-19 22:48:01 +08:00
|
|
|
migration = type(
|
|
|
|
"Migration",
|
|
|
|
(migrations.Migration,),
|
|
|
|
{
|
2015-03-29 08:09:44 +08:00
|
|
|
"operations": [
|
|
|
|
migrations.AlterModelOptions(
|
|
|
|
name="model",
|
|
|
|
options={
|
|
|
|
"verbose_name": "model",
|
|
|
|
"verbose_name_plural": "models",
|
|
|
|
},
|
2016-02-06 02:53:03 +08:00
|
|
|
),
|
2015-03-29 08:09:44 +08:00
|
|
|
]
|
|
|
|
},
|
|
|
|
)
|
|
|
|
writer = MigrationWriter(migration)
|
2016-10-01 00:28:48 +08:00
|
|
|
output = writer.as_string()
|
2015-03-29 08:09:44 +08:00
|
|
|
self.assertIn("from django.db import migrations\n", output)
|
|
|
|
|
2014-12-03 09:52:58 +08:00
|
|
|
def test_deconstruct_class_arguments(self):
|
|
|
|
# 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.
|
2015-12-03 07:55:50 +08:00
|
|
|
string = MigrationWriter.serialize(
|
|
|
|
models.CharField(default=DeconstructibleInstances)
|
|
|
|
)[0]
|
|
|
|
self.assertEqual(
|
|
|
|
string,
|
|
|
|
"models.CharField(default=migrations.test_writer.DeconstructibleInstances)",
|
|
|
|
)
|
2019-01-11 02:05:19 +08:00
|
|
|
|
|
|
|
def test_register_serializer(self):
|
|
|
|
class ComplexSerializer(BaseSerializer):
|
|
|
|
def serialize(self):
|
|
|
|
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)"):
|
|
|
|
self.assertSerializedEqual(complex(1, 2))
|
|
|
|
|
|
|
|
def test_register_non_serializer(self):
|
|
|
|
with self.assertRaisesMessage(
|
|
|
|
ValueError, "'TestModel1' must inherit from 'BaseSerializer'."
|
|
|
|
):
|
|
|
|
MigrationWriter.register_serializer(complex, TestModel1)
|