Code

Ticket #14894: bug-14894-translation-thread-safety.diff

File bug-14894-translation-thread-safety.diff, 2.1 KB (added by sergeykolosov, 14 months ago)

Patch which uses list() on _translations, so that it is Python 3.x complatible (where .keys() is an iterator); along with a regression test.

Line 
1diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py
2index 07353c3..8c54862 100644
3--- a/django/utils/translation/trans_real.py
4+++ b/django/utils/translation/trans_real.py
5@@ -140,7 +140,7 @@ def translation(language):
6         # doesn't affect en-gb), even though they will both use the core "en"
7         # translation. So we have to subvert Python's internal gettext caching.
8         base_lang = lambda x: x.split('-', 1)[0]
9-        if base_lang(lang) in [base_lang(trans) for trans in _translations]:
10+        if base_lang(lang) in [base_lang(trans) for trans in list(_translations)]:
11             res._info = res._info.copy()
12             res._catalog = res._catalog.copy()
13 
14diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py
15index 1022c8d..0726bcf 100644
16--- a/tests/i18n/tests.py
17+++ b/tests/i18n/tests.py
18@@ -333,6 +333,36 @@ class TranslationTests(TestCase):
19             self.assertEqual(rendered, 'My other name is James.')
20 
21 
22+class TranslationThreadSafetyTests(TestCase):
23+    def setUp(self):
24+        self._old_language = get_language()
25+        self._translations = trans_real._translations
26+
27+        # here we rely on .split() being called inside 'base_lang' lambda
28+        # in _fetch() in trans_real.translation()
29+        class sideeffect_str(str):
30+            def split(self, *args, **kwargs):
31+                res = str.split(self, *args, **kwargs)
32+                trans_real._translations['en-YY'] = None
33+                return res
34+
35+        trans_real._translations = {sideeffect_str('en-XX'): None}
36+
37+    def tearDown(self):
38+        trans_real._translations = self._translations
39+        activate(self._old_language)
40+
41+    def test_bug14894_translation_activate_thread_safety(self):
42+        translation_count = len(trans_real._translations)
43+        try:
44+            translation.activate('pl')
45+        except RuntimeError:
46+            self.fail('translation.activate() is not thread-safe')
47+
48+        # make sure sideeffect_str actually added a new translation
49+        self.assertLess(translation_count, len(trans_real._translations))
50+
51+
52 @override_settings(USE_L10N=True)
53 class FormattingTests(TestCase):
54