diff options
author | James Carey <jecarey@us.ibm.com> | 2014-03-11 16:22:12 +0000 |
---|---|---|
committer | James Carey <jecarey@us.ibm.com> | 2014-03-11 16:22:12 +0000 |
commit | 2c61721479fb69f6a43d2c1c46fdad4cd9e21920 (patch) | |
tree | 1a111bd0b1f1f5c3e27131dfef6b99e283fdbe39 | |
parent | 8d42b3b97aadbd92aa55f5663e33eb3732ad38d8 (diff) | |
download | oslo-i18n-2c61721479fb69f6a43d2c1c46fdad4cd9e21920.tar.gz |
Fix gettextutil.Message handling of deep copy failures
Broadened deep copy exception handling and changed the keyword
dictionary deep copy to doing each element separately so that only
the failing dictionary item is converted to unicode.
Also added test cases.
Closes-bug: #1290468
Change-Id: I15f3880b32bec55bb61d96af41762c98486a274d
-rw-r--r-- | openstack/common/gettextutils.py | 9 | ||||
-rw-r--r-- | tests/unit/test_gettext.py | 31 |
2 files changed, 37 insertions, 3 deletions
diff --git a/openstack/common/gettextutils.py b/openstack/common/gettextutils.py index a2ba6e1..b77087d 100644 --- a/openstack/common/gettextutils.py +++ b/openstack/common/gettextutils.py @@ -248,10 +248,13 @@ class Message(six.text_type): params = (other,) elif isinstance(other, dict): # Merge the dictionaries + # Copy each item in case one does not support deep copy. params = {} if isinstance(self.params, dict): - params.update(self._copy_param(self.params)) - params.update(self._copy_param(other)) + for key, val in self.params.items(): + params[key] = self._copy_param(val) + for key, val in other.items(): + params[key] = self._copy_param(val) else: params = self._copy_param(other) return params @@ -259,7 +262,7 @@ class Message(six.text_type): def _copy_param(self, param): try: return copy.deepcopy(param) - except TypeError: + except Exception: # Fallback to casting to unicode this will handle the # python code-like objects that can't be deep-copied return six.text_type(param) diff --git a/tests/unit/test_gettext.py b/tests/unit/test_gettext.py index f131907..5d285f5 100644 --- a/tests/unit/test_gettext.py +++ b/tests/unit/test_gettext.py @@ -341,6 +341,25 @@ class MessageTestCase(test.BaseTestCase): # translation should use the original list self.assertEqual(result.translate(), "Found list: [1, 2, 3]") + def test_mod_deep_copies_param_nodeep_param(self): + msgid = "Value: %s" + params = NoDeepCopyObject(5) + # Apply the params + result = self.message(msgid) % params + self.assertEqual(result.translate(), "Value: 5") + + def test_mod_deep_copies_param_nodeep_dict(self): + msgid = "Values: %(val1)s %(val2)s" + params = {'val1': 1, 'val2': NoDeepCopyObject(2)} + # Apply the params + result = self.message(msgid) % params + self.assertEqual(result.translate(), "Values: 1 2") + + # Apply again to make sure other path works as well + params = {'val1': 3, 'val2': NoDeepCopyObject(4)} + result = self.message(msgid) % params + self.assertEqual(result.translate(), "Values: 3 4") + def test_mod_returns_a_copy(self): msgid = "Some msgid string: %(test1)s %(test2)s" message = self.message(msgid) @@ -777,3 +796,15 @@ class SomeObject(object): def __unicode__(self): return self.message + + +class NoDeepCopyObject(object): + + def __init__(self, value): + self.value = value + + def __unicode__(self): + return unicode(self.value) + + def __deepcopy__(self, memo): + raise TypeError('Deep Copy not supported') |