summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Carey <jecarey@us.ibm.com>2014-03-11 16:22:12 +0000
committerJames Carey <jecarey@us.ibm.com>2014-03-11 16:22:12 +0000
commit2c61721479fb69f6a43d2c1c46fdad4cd9e21920 (patch)
tree1a111bd0b1f1f5c3e27131dfef6b99e283fdbe39
parent8d42b3b97aadbd92aa55f5663e33eb3732ad38d8 (diff)
downloadoslo-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.py9
-rw-r--r--tests/unit/test_gettext.py31
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')