From acd0bb39df5c9ca486e49ec55ae34538242ce071 Mon Sep 17 00:00:00 2001 From: Florian Apolloner Date: Sat, 18 May 2013 17:36:31 +0200 Subject: [PATCH] Fixed #14894 -- Ensure that activating a translation doesn't run into threading issues. Thanks to maxbublis for the report and sergeykolosov for the patch. --- django/utils/translation/trans_real.py | 2 +- tests/i18n/tests.py | 30 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py index f7b15240854..26be0ed729c 100644 --- a/django/utils/translation/trans_real.py +++ b/django/utils/translation/trans_real.py @@ -140,7 +140,7 @@ def translation(language): # doesn't affect en-gb), even though they will both use the core "en" # translation. So we have to subvert Python's internal gettext caching. base_lang = lambda x: x.split('-', 1)[0] - if base_lang(lang) in [base_lang(trans) for trans in _translations]: + if base_lang(lang) in [base_lang(trans) for trans in list(_translations)]: res._info = res._info.copy() res._catalog = res._catalog.copy() diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py index 29223e5add2..1b15720c168 100644 --- a/tests/i18n/tests.py +++ b/tests/i18n/tests.py @@ -334,6 +334,36 @@ class TranslationTests(TestCase): self.assertEqual(rendered, 'My other name is James.') +class TranslationThreadSafetyTests(TestCase): + def setUp(self): + self._old_language = get_language() + self._translations = trans_real._translations + + # here we rely on .split() being called inside the _fetch() + # in trans_real.translation() + class sideeffect_str(str): + def split(self, *args, **kwargs): + res = str.split(self, *args, **kwargs) + trans_real._translations['en-YY'] = None + return res + + trans_real._translations = {sideeffect_str('en-XX'): None} + + def tearDown(self): + trans_real._translations = self._translations + activate(self._old_language) + + def test_bug14894_translation_activate_thread_safety(self): + translation_count = len(trans_real._translations) + try: + translation.activate('pl') + except RuntimeError: + self.fail('translation.activate() is not thread-safe') + + # make sure sideeffect_str actually added a new translation + self.assertLess(translation_count, len(trans_real._translations)) + + @override_settings(USE_L10N=True) class FormattingTests(TestCase):