diff --git a/django/utils/translation/__init__.py b/django/utils/translation/__init__.py index 7311a6145c..9b6649319c 100644 --- a/django/utils/translation/__init__.py +++ b/django/utils/translation/__init__.py @@ -106,6 +106,8 @@ def lazy_number(func, resultclass, number=None, **kwargs): kwargs['number'] = number proxy = lazy(func, resultclass)(**kwargs) else: + original_kwargs = kwargs.copy() + class NumberAwareString(resultclass): def __mod__(self, rhs): if isinstance(rhs, dict) and number: @@ -128,9 +130,14 @@ def lazy_number(func, resultclass, number=None, **kwargs): return translated proxy = lazy(lambda **kwargs: NumberAwareString(), NumberAwareString)(**kwargs) + proxy.__reduce__ = lambda: (_lazy_number_unpickle, (func, resultclass, number, original_kwargs)) return proxy +def _lazy_number_unpickle(func, resultclass, number, kwargs): + return lazy_number(func, resultclass, number=number, **kwargs) + + def ngettext_lazy(singular, plural, number=None): return lazy_number(ngettext, str, singular=singular, plural=plural, number=number) diff --git a/docs/releases/1.8.10.txt b/docs/releases/1.8.10.txt index 1ceada6f54..4eea5a3b7b 100644 --- a/docs/releases/1.8.10.txt +++ b/docs/releases/1.8.10.txt @@ -14,3 +14,6 @@ Bugfixes * Added system checks for query name clashes of hidden relationships (:ticket:`26162`). + +* Made ``forms.FileField`` and ``utils.translation.lazy_number()`` picklable + (:ticket:`26212`). diff --git a/docs/releases/1.9.3.txt b/docs/releases/1.9.3.txt index e6f200c864..05c6542329 100644 --- a/docs/releases/1.9.3.txt +++ b/docs/releases/1.9.3.txt @@ -24,3 +24,6 @@ Bugfixes * Fixed regression with an ``__in=qs`` lookup for a ``ForeignKey`` with ``to_field`` set (:ticket:`26196`). + +* Made ``forms.FileField`` and ``utils.translation.lazy_number()`` picklable + (:ticket:`26212`). diff --git a/tests/forms_tests/tests/test_fields.py b/tests/forms_tests/tests/test_fields.py index 491756db70..17b8756ddb 100644 --- a/tests/forms_tests/tests/test_fields.py +++ b/tests/forms_tests/tests/test_fields.py @@ -919,6 +919,9 @@ class FieldsTests(SimpleTestCase): # with here) self.assertTrue(f.has_changed('resume.txt', {'filename': 'resume.txt', 'content': 'My resume'})) + def test_file_picklable(self): + self.assertIsInstance(pickle.loads(pickle.dumps(FileField())), FileField) + # ImageField ################################################################## @skipIf(Image is None, "Pillow is required to test ImageField") diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py index 912ee8d1fb..bb88beb483 100644 --- a/tests/i18n/tests.py +++ b/tests/i18n/tests.py @@ -239,6 +239,14 @@ class TranslationTests(SimpleTestCase): ) self.assertEqual(result % {'name': 'Joe', 'num': 4}, "Joe has 4 good results") + def test_ungettext_lazy_pickle(self): + s1 = ungettext_lazy('%d good result', '%d good results') + self.assertEqual(s1 % 1, '1 good result') + self.assertEqual(s1 % 8, '8 good results') + s2 = pickle.loads(pickle.dumps(s1)) + self.assertEqual(s2 % 1, '1 good result') + self.assertEqual(s2 % 8, '8 good results') + @override_settings(LOCALE_PATHS=extended_locale_paths) def test_pgettext(self): trans_real._active = local()