Fixed #29595 -- Allowed using timedelta in migrations questioner.

Refs #29600 -- Removed usage of django.utils.datetime_safe in migrations.
This commit is contained in:
Tim Graham 2018-07-26 15:04:58 -04:00
parent 3af695eda2
commit c72dde41e6
4 changed files with 29 additions and 53 deletions

View File

@ -1,10 +1,11 @@
import datetime
import importlib
import os
import sys
from django.apps import apps
from django.db.models.fields import NOT_PROVIDED
from django.utils import datetime_safe, timezone
from django.utils import timezone
from .loader import MigrationLoader
@ -135,7 +136,7 @@ class InteractiveMigrationQuestioner(MigrationQuestioner):
sys.exit(1)
else:
try:
return eval(code, {}, {"datetime": datetime_safe, "timezone": timezone})
return eval(code, {}, {'datetime': datetime, 'timezone': timezone})
except (SyntaxError, NameError) as e:
print("Invalid input: %s" % e)

View File

@ -12,7 +12,6 @@ import uuid
from django.db import models
from django.db.migrations.operations.base import Operation
from django.db.migrations.utils import COMPILED_REGEX_TYPE, RegexObject
from django.utils import datetime_safe
from django.utils.functional import LazyObject, Promise
from django.utils.timezone import utc
from django.utils.version import get_docs_version
@ -46,25 +45,21 @@ class BaseSimpleSerializer(BaseSerializer):
return repr(self.value), set()
class DatetimeSerializer(BaseSerializer):
class DateTimeSerializer(BaseSerializer):
"""For datetime.*, except datetime.datetime."""
def serialize(self):
return repr(self.value), {'import datetime'}
class DatetimeDatetimeSerializer(BaseSerializer):
"""For datetime.datetime."""
def serialize(self):
if self.value.tzinfo is not None and self.value.tzinfo != utc:
self.value = self.value.astimezone(utc)
value_repr = repr(self.value).replace("<UTC>", "utc")
if isinstance(self.value, datetime_safe.datetime):
value_repr = "datetime.%s" % value_repr
imports = ["import datetime"]
if self.value.tzinfo is not None:
imports.append("from django.utils.timezone import utc")
return value_repr, set(imports)
class DateSerializer(BaseSerializer):
def serialize(self):
value_repr = repr(self.value)
if isinstance(self.value, datetime_safe.date):
value_repr = "datetime.%s" % value_repr
return value_repr, {"import datetime"}
return repr(self.value).replace('<UTC>', 'utc'), set(imports)
class DecimalSerializer(BaseSerializer):
@ -246,19 +241,6 @@ class SettingsReferenceSerializer(BaseSerializer):
return "settings.%s" % self.value.setting_name, {"from django.conf import settings"}
class TimedeltaSerializer(BaseSerializer):
def serialize(self):
return repr(self.value), {"import datetime"}
class TimeSerializer(BaseSerializer):
def serialize(self):
value_repr = repr(self.value)
if isinstance(self.value, datetime_safe.time):
value_repr = "datetime.%s" % value_repr
return value_repr, {"import datetime"}
class TupleSerializer(BaseSequenceSerializer):
def _format(self):
# When len(value)==0, the empty tuple should be serialized as "()",
@ -322,13 +304,9 @@ def serializer_factory(value):
if isinstance(value, enum.Enum):
return EnumSerializer(value)
if isinstance(value, datetime.datetime):
return DatetimeSerializer(value)
if isinstance(value, datetime.date):
return DateSerializer(value)
if isinstance(value, datetime.time):
return TimeSerializer(value)
if isinstance(value, datetime.timedelta):
return TimedeltaSerializer(value)
return DatetimeDatetimeSerializer(value)
if isinstance(value, (datetime.date, datetime.timedelta, datetime.time)):
return DateTimeSerializer(value)
if isinstance(value, SettingsReference):
return SettingsReferenceSerializer(value)
if isinstance(value, float):

View File

@ -1,6 +1,11 @@
from django.db.migrations.questioner import MigrationQuestioner
import datetime
from unittest import mock
from django.db.migrations.questioner import (
InteractiveMigrationQuestioner, MigrationQuestioner,
)
from django.test import SimpleTestCase
from django.test.utils import override_settings
from django.test.utils import captured_stdout, override_settings
class QuestionerTests(SimpleTestCase):
@ -11,3 +16,10 @@ class QuestionerTests(SimpleTestCase):
def test_ask_initial_with_disabled_migrations(self):
questioner = MigrationQuestioner()
self.assertIs(False, questioner.ask_initial('migrations'))
@mock.patch('builtins.input', return_value='datetime.timedelta(days=1)')
def test_timedelta_default(self, mock):
questioner = InteractiveMigrationQuestioner()
with captured_stdout():
value = questioner._ask_default()
self.assertEqual(value, datetime.timedelta(days=1))

View File

@ -19,7 +19,6 @@ from django.db.migrations.writer import (
MigrationWriter, OperationWriter, SettingsReference,
)
from django.test import SimpleTestCase
from django.utils import datetime_safe
from django.utils.deconstruct import deconstructible
from django.utils.functional import SimpleLazyObject
from django.utils.timezone import get_default_timezone, get_fixed_timezone, utc
@ -364,20 +363,6 @@ class WriterTests(SimpleTestCase):
)
)
def test_serialize_datetime_safe(self):
self.assertSerializedResultEqual(
datetime_safe.date(2014, 3, 31),
("datetime.date(2014, 3, 31)", {'import datetime'})
)
self.assertSerializedResultEqual(
datetime_safe.time(10, 25),
("datetime.time(10, 25)", {'import datetime'})
)
self.assertSerializedResultEqual(
datetime_safe.datetime(2014, 3, 31, 16, 4, 31),
("datetime.datetime(2014, 3, 31, 16, 4, 31)", {'import datetime'})
)
def test_serialize_fields(self):
self.assertSerializedFieldEqual(models.CharField(max_length=255))
self.assertSerializedResultEqual(