Loading django/db/migrations/writer.py +15 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ import decimal import collections from importlib import import_module import os import re import sys import types Loading @@ -17,6 +18,9 @@ from django.utils.encoding import force_text from django.utils.functional import Promise COMPILED_REGEX_TYPE = type(re.compile('')) class SettingsReference(str): """ Special subclass of string which actually references a current settings Loading Loading @@ -344,6 +348,17 @@ class MigrationWriter(object): # "()", not "(,)" because (,) is invalid Python syntax. format = "(%s)" if len(strings) != 1 else "(%s,)" return format % (", ".join(strings)), imports # Compiled regex elif isinstance(value, COMPILED_REGEX_TYPE): imports = set(["import re"]) regex_pattern, pattern_imports = cls.serialize(value.pattern) regex_flags, flag_imports = cls.serialize(value.flags) imports.update(pattern_imports) imports.update(flag_imports) args = [regex_pattern] if value.flags: args.append(regex_flags) return "re.compile(%s)" % ', '.join(args), imports # Uh oh. else: raise ValueError("Cannot serialize: %r\nThere are some values Django cannot serialize into migration files.\nFor more, see https://docs.djangoproject.com/en/dev/topics/migrations/#migration-serializing" % value) Loading docs/releases/1.7.txt +0 −7 Original line number Diff line number Diff line Loading @@ -1390,13 +1390,6 @@ Miscellaneous a relation from the related object back to the content type for filtering, ordering and other query operations. * When a model field's :attr:`~django.db.models.Field.validators` contains a :class:`~django.core.validators.RegexValidator`, the regular expression must now be passed as a regular expression string. You can no longer use a pre-compiled regular expression in this case, as it is not serializable. The :attr:`~django.core.validators.RegexValidator.flags` attribute was added to :class:`~django.core.validators.RegexValidator` to simplify this change. * When running tests on PostgreSQL, the :setting:`USER` will need read access to the built-in ``postgres`` database. This is in lieu of the previous behavior of connecting to the actual non-test database. Loading tests/migrations/test_writer.py +46 −12 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ from __future__ import unicode_literals import datetime import os import re import tokenize import unittest Loading Loading @@ -103,18 +104,6 @@ class WriterTests(TestCase): string, imports = MigrationWriter.serialize(safe_datetime) self.assertEqual(string, repr(datetime.datetime(2014, 3, 31, 16, 4, 31))) self.assertEqual(imports, {'import datetime'}) # Classes validator = RegexValidator(message="hello") string, imports = MigrationWriter.serialize(validator) self.assertEqual(string, "django.core.validators.RegexValidator(message='hello')") self.serialize_round_trip(validator) validator = EmailValidator(message="hello") # Test with a subclass. string, imports = MigrationWriter.serialize(validator) self.assertEqual(string, "django.core.validators.EmailValidator(message='hello')") self.serialize_round_trip(validator) validator = deconstructible(path="custom.EmailValidator")(EmailValidator)(message="hello") string, imports = MigrationWriter.serialize(validator) self.assertEqual(string, "custom.EmailValidator(message='hello')") # Django fields self.assertSerializedFieldEqual(models.CharField(max_length=255)) self.assertSerializedFieldEqual(models.TextField(null=True, blank=True)) Loading @@ -135,6 +124,51 @@ class WriterTests(TestCase): ) ) def test_serialize_compiled_regex(self): """ Make sure compiled regex can be serialized. """ regex = re.compile(r'^\w+$', re.U) 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. validator = RegexValidator(regex=re.compile(r'^\w+$', re.U)) string = MigrationWriter.serialize(validator)[0] self.assertEqual(string, "django.core.validators.RegexValidator(regex=re.compile('^\\\\w+$', 32))") self.serialize_round_trip(validator) # Test a string regex with flag validator = RegexValidator(r'^[0-9]+$', flags=re.U) string = MigrationWriter.serialize(validator)[0] self.assertEqual(string, "django.core.validators.RegexValidator('^[0-9]+$', flags=32)") 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) validator = deconstructible(path="custom.EmailValidator")(EmailValidator)(message="hello") string = MigrationWriter.serialize(validator)[0] self.assertEqual(string, "custom.EmailValidator(message='hello')") def test_serialize_empty_nonempty_tuple(self): """ Ticket #22679: makemigrations generates invalid code for (an empty Loading Loading
django/db/migrations/writer.py +15 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ import decimal import collections from importlib import import_module import os import re import sys import types Loading @@ -17,6 +18,9 @@ from django.utils.encoding import force_text from django.utils.functional import Promise COMPILED_REGEX_TYPE = type(re.compile('')) class SettingsReference(str): """ Special subclass of string which actually references a current settings Loading Loading @@ -344,6 +348,17 @@ class MigrationWriter(object): # "()", not "(,)" because (,) is invalid Python syntax. format = "(%s)" if len(strings) != 1 else "(%s,)" return format % (", ".join(strings)), imports # Compiled regex elif isinstance(value, COMPILED_REGEX_TYPE): imports = set(["import re"]) regex_pattern, pattern_imports = cls.serialize(value.pattern) regex_flags, flag_imports = cls.serialize(value.flags) imports.update(pattern_imports) imports.update(flag_imports) args = [regex_pattern] if value.flags: args.append(regex_flags) return "re.compile(%s)" % ', '.join(args), imports # Uh oh. else: raise ValueError("Cannot serialize: %r\nThere are some values Django cannot serialize into migration files.\nFor more, see https://docs.djangoproject.com/en/dev/topics/migrations/#migration-serializing" % value) Loading
docs/releases/1.7.txt +0 −7 Original line number Diff line number Diff line Loading @@ -1390,13 +1390,6 @@ Miscellaneous a relation from the related object back to the content type for filtering, ordering and other query operations. * When a model field's :attr:`~django.db.models.Field.validators` contains a :class:`~django.core.validators.RegexValidator`, the regular expression must now be passed as a regular expression string. You can no longer use a pre-compiled regular expression in this case, as it is not serializable. The :attr:`~django.core.validators.RegexValidator.flags` attribute was added to :class:`~django.core.validators.RegexValidator` to simplify this change. * When running tests on PostgreSQL, the :setting:`USER` will need read access to the built-in ``postgres`` database. This is in lieu of the previous behavior of connecting to the actual non-test database. Loading
tests/migrations/test_writer.py +46 −12 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ from __future__ import unicode_literals import datetime import os import re import tokenize import unittest Loading Loading @@ -103,18 +104,6 @@ class WriterTests(TestCase): string, imports = MigrationWriter.serialize(safe_datetime) self.assertEqual(string, repr(datetime.datetime(2014, 3, 31, 16, 4, 31))) self.assertEqual(imports, {'import datetime'}) # Classes validator = RegexValidator(message="hello") string, imports = MigrationWriter.serialize(validator) self.assertEqual(string, "django.core.validators.RegexValidator(message='hello')") self.serialize_round_trip(validator) validator = EmailValidator(message="hello") # Test with a subclass. string, imports = MigrationWriter.serialize(validator) self.assertEqual(string, "django.core.validators.EmailValidator(message='hello')") self.serialize_round_trip(validator) validator = deconstructible(path="custom.EmailValidator")(EmailValidator)(message="hello") string, imports = MigrationWriter.serialize(validator) self.assertEqual(string, "custom.EmailValidator(message='hello')") # Django fields self.assertSerializedFieldEqual(models.CharField(max_length=255)) self.assertSerializedFieldEqual(models.TextField(null=True, blank=True)) Loading @@ -135,6 +124,51 @@ class WriterTests(TestCase): ) ) def test_serialize_compiled_regex(self): """ Make sure compiled regex can be serialized. """ regex = re.compile(r'^\w+$', re.U) 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. validator = RegexValidator(regex=re.compile(r'^\w+$', re.U)) string = MigrationWriter.serialize(validator)[0] self.assertEqual(string, "django.core.validators.RegexValidator(regex=re.compile('^\\\\w+$', 32))") self.serialize_round_trip(validator) # Test a string regex with flag validator = RegexValidator(r'^[0-9]+$', flags=re.U) string = MigrationWriter.serialize(validator)[0] self.assertEqual(string, "django.core.validators.RegexValidator('^[0-9]+$', flags=32)") 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) validator = deconstructible(path="custom.EmailValidator")(EmailValidator)(message="hello") string = MigrationWriter.serialize(validator)[0] self.assertEqual(string, "custom.EmailValidator(message='hello')") def test_serialize_empty_nonempty_tuple(self): """ Ticket #22679: makemigrations generates invalid code for (an empty Loading