Fixed #25185 -- Added support for functools.partial serialization in migrations

This commit is contained in:
Piper Merriam 2015-07-28 10:51:25 -06:00 committed by Tim Graham
parent b1e552debf
commit 537818af87
4 changed files with 33 additions and 0 deletions

View File

@ -3,6 +3,7 @@ from __future__ import unicode_literals
import collections import collections
import datetime import datetime
import decimal import decimal
import functools
import math import math
import os import os
import re import re
@ -439,6 +440,22 @@ class MigrationWriter(object):
string, imports = OperationWriter(value, indentation=0).serialize() string, imports = OperationWriter(value, indentation=0).serialize()
# Nested operation, trailing comma is handled in upper OperationWriter._write() # Nested operation, trailing comma is handled in upper OperationWriter._write()
return string.rstrip(','), imports return string.rstrip(','), imports
elif isinstance(value, functools.partial):
imports = {'import functools'}
# Serialize functools.partial() arguments
func_string, func_imports = cls.serialize(value.func)
args_string, args_imports = cls.serialize(value.args)
keywords_string, keywords_imports = cls.serialize(value.keywords)
# Add any imports needed by arguments
imports.update(func_imports)
imports.update(args_imports)
imports.update(keywords_imports)
return (
"functools.partial(%s, *%s, **%s)" % (
func_string, args_string, keywords_string,
),
imports,
)
# Anything that knows how to deconstruct itself. # Anything that knows how to deconstruct itself.
elif hasattr(value, 'deconstruct'): elif hasattr(value, 'deconstruct'):
return cls.serialize_deconstructed(*value.deconstruct()) return cls.serialize_deconstructed(*value.deconstruct())

View File

@ -385,6 +385,8 @@ Migrations
:djadminopt:`migrate --fake-initial <--fake-initial>` to more easily detect :djadminopt:`migrate --fake-initial <--fake-initial>` to more easily detect
initial migrations. initial migrations.
* Added support for serialization of ``functools.partial`` objects.
Models Models
^^^^^^ ^^^^^^

View File

@ -652,11 +652,17 @@ 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
- ``functools.partial`` instances which have serializable ``func``, ``args``,
and ``keywords`` values.
- Any Django field - Any Django field
- Any function or method reference (e.g. ``datetime.datetime.today``) (must be in module's top-level scope) - Any function or method reference (e.g. ``datetime.datetime.today``) (must be in module's top-level scope)
- Any class reference (must be in module's top-level scope) - Any class reference (must be in module's top-level scope)
- Anything with a custom ``deconstruct()`` method (:ref:`see below <custom-deconstruct-method>`) - Anything with a custom ``deconstruct()`` method (:ref:`see below <custom-deconstruct-method>`)
.. versionchanged:: 1.9
Serialization support for `functools.partial` 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)

View File

@ -2,6 +2,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import datetime import datetime
import functools
import math import math
import os import os
import re import re
@ -414,6 +415,13 @@ class WriterTests(SimpleTestCase):
self.assertSerializedEqual(datetime.timedelta()) self.assertSerializedEqual(datetime.timedelta())
self.assertSerializedEqual(datetime.timedelta(minutes=42)) self.assertSerializedEqual(datetime.timedelta(minutes=42))
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)
def test_simple_migration(self): def test_simple_migration(self):
""" """
Tests serializing a simple migration. Tests serializing a simple migration.