Kaydet (Commit) 998894e1 authored tarafından Andrei Fokau's avatar Andrei Fokau Kaydeden (comit) Tim Graham

Fixed #25764 -- Added support for serialization of enum.Enum in migrations.

Thanks Tim Graham for the review.
üst 65764a93
...@@ -25,6 +25,12 @@ from django.utils.module_loading import module_dir ...@@ -25,6 +25,12 @@ from django.utils.module_loading import module_dir
from django.utils.timezone import now, utc from django.utils.timezone import now, utc
from django.utils.version import get_docs_version from django.utils.version import get_docs_version
try:
import enum
except ImportError:
# No support on Python 2 if enum34 isn't installed.
enum = None
class SettingsReference(str): class SettingsReference(str):
""" """
...@@ -376,6 +382,14 @@ class MigrationWriter(object): ...@@ -376,6 +382,14 @@ class MigrationWriter(object):
imports.update(v_imports) imports.update(v_imports)
strings.append((k_string, v_string)) strings.append((k_string, v_string))
return "{%s}" % (", ".join("%s: %s" % (k, v) for k, v in strings)), imports return "{%s}" % (", ".join("%s: %s" % (k, v) for k, v in strings)), imports
# Enums
elif enum and isinstance(value, enum.Enum):
enum_class = value.__class__
module = enum_class.__module__
imports = {"import %s" % module}
v_string, v_imports = cls.serialize(value.value)
imports.update(v_imports)
return "%s.%s(%s)" % (module, enum_class.__name__, v_string), imports
# Datetimes # Datetimes
elif isinstance(value, datetime.datetime): elif isinstance(value, datetime.datetime):
value_repr = cls.serialize_datetime(value) value_repr = cls.serialize_datetime(value)
......
...@@ -138,6 +138,7 @@ dependencies: ...@@ -138,6 +138,7 @@ dependencies:
* bcrypt_ * bcrypt_
* docutils_ * docutils_
* enum34_ (Python 2 only)
* geoip2_ * geoip2_
* jinja2_ 2.7+ * jinja2_ 2.7+
* numpy_ * numpy_
...@@ -171,6 +172,7 @@ associated tests will be skipped. ...@@ -171,6 +172,7 @@ associated tests will be skipped.
.. _bcrypt: https://pypi.python.org/pypi/bcrypt .. _bcrypt: https://pypi.python.org/pypi/bcrypt
.. _docutils: https://pypi.python.org/pypi/docutils .. _docutils: https://pypi.python.org/pypi/docutils
.. _enum34: https://pypi.python.org/pypi/enum34
.. _geoip2: https://pypi.python.org/pypi/geoip2 .. _geoip2: https://pypi.python.org/pypi/geoip2
.. _jinja2: https://pypi.python.org/pypi/jinja2 .. _jinja2: https://pypi.python.org/pypi/jinja2
.. _numpy: https://pypi.python.org/pypi/numpy .. _numpy: https://pypi.python.org/pypi/numpy
......
...@@ -174,7 +174,7 @@ Management Commands ...@@ -174,7 +174,7 @@ Management Commands
Migrations Migrations
^^^^^^^^^^ ^^^^^^^^^^
* ... * Added support for serialization of ``enum.Enum`` objects.
Models Models
^^^^^^ ^^^^^^
......
...@@ -645,6 +645,7 @@ Django can serialize the following: ...@@ -645,6 +645,7 @@ Django can serialize the following:
- ``datetime.date``, ``datetime.time``, and ``datetime.datetime`` instances - ``datetime.date``, ``datetime.time``, and ``datetime.datetime`` instances
(include those that are timezone-aware) (include those that are timezone-aware)
- ``decimal.Decimal`` instances - ``decimal.Decimal`` instances
- ``enum.Enum`` instances
- ``functools.partial`` instances which have serializable ``func``, ``args``, - ``functools.partial`` instances which have serializable ``func``, ``args``,
and ``keywords`` values. and ``keywords`` values.
- Any Django field - Any Django field
...@@ -656,6 +657,10 @@ Django can serialize the following: ...@@ -656,6 +657,10 @@ Django can serialize the following:
Serialization support for `functools.partial` was added. Serialization support for `functools.partial` was added.
.. versionchanged:: 1.10
Serialization support for ``enum.Enum`` was added.
Django can serialize the following on Python 3 only: Django can serialize the following on Python 3 only:
- Unbound methods used from within the class body (see below) - Unbound methods used from within the class body (see below)
......
...@@ -28,6 +28,11 @@ from django.utils.translation import ugettext_lazy as _ ...@@ -28,6 +28,11 @@ from django.utils.translation import ugettext_lazy as _
from .models import FoodManager, FoodQuerySet from .models import FoodManager, FoodQuerySet
try:
import enum
except ImportError:
enum = None
class TestModel1(object): class TestModel1(object):
def upload_to(self): def upload_to(self):
...@@ -229,6 +234,61 @@ class WriterTests(SimpleTestCase): ...@@ -229,6 +234,61 @@ class WriterTests(SimpleTestCase):
("[list, tuple, dict, set, frozenset]", set()) ("[list, tuple, dict, set, frozenset]", set())
) )
@unittest.skipUnless(enum, "enum34 is required on Python 2")
def test_serialize_enums(self):
class TextEnum(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
self.assertSerializedResultEqual(
TextEnum.A,
("migrations.test_writer.TextEnum('a-value')", {'import migrations.test_writer'})
)
self.assertSerializedResultEqual(
BinaryEnum.A,
("migrations.test_writer.BinaryEnum(b'a-value')", {'import migrations.test_writer'})
)
self.assertSerializedResultEqual(
IntEnum.B,
("migrations.test_writer.IntEnum(2)", {'import migrations.test_writer'})
)
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')), "
"('value-b', migrations.test_writer.TextEnum('value-b'))], "
"default=migrations.test_writer.TextEnum('value-b'))"
)
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(b'a-value')), "
"(b'value-b', migrations.test_writer.BinaryEnum(b'value-b'))], "
"default=migrations.test_writer.BinaryEnum(b'value-b'))"
)
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(1)), "
"(2, migrations.test_writer.IntEnum(2))], "
"default=migrations.test_writer.IntEnum(1))"
)
def test_serialize_functions(self): def test_serialize_functions(self):
with six.assertRaisesRegex(self, ValueError, 'Cannot serialize function: lambda'): with six.assertRaisesRegex(self, ValueError, 'Cannot serialize function: lambda'):
self.assertSerializedEqual(lambda x: 42) self.assertSerializedEqual(lambda x: 42)
......
-r base.txt -r base.txt
enum34
# Due to https://github.com/linsomniac/python-memcached/issues/79 in newer versions. # Due to https://github.com/linsomniac/python-memcached/issues/79 in newer versions.
python-memcached <= 1.53 python-memcached <= 1.53
mock mock
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment