summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Bryant <rbryant@redhat.com>2012-07-18 16:15:52 -0400
committerRussell Bryant <rbryant@redhat.com>2012-07-18 16:15:52 -0400
commita91d35a3da1e6c1228cedb7e07f2b3c0798001fc (patch)
tree515c7f7bdb08c1a3b8cb3b6cc8b05f5bea6377f2
parenta9ed13380c948f3c8372e8aba244e1b030b9fe06 (diff)
downloadoslo-serialization-a91d35a3da1e6c1228cedb7e07f2b3c0798001fc.tar.gz
Track to_primitive() depth after iteritems().
Change jsonutils.to_primitive() to increase the recursion depth counter when calling to_primitive() on the result of iteritems() from the current element. Previously, the only time the counter was increased was when converting the __dict__ from an object. The iteritems() case risks cycles, as well. I hit a problem with this when trying to call to_primitive on an instance of nova.db.sqlalchemy.models.Instance. An Instance includes a reference to InstanceInfoCache, which has a reference back to the Instance. Without this change, to_primitive() would raise an exception for an Instance due to excessive recursion. Related to nova blueprint no-db-messaging. Change-Id: Ifb878368d97e92ab6c361a4dd5f5ab2e68fc16e2
-rw-r--r--openstack/common/jsonutils.py2
-rw-r--r--tests/unit/test_jsonutils.py18
2 files changed, 19 insertions, 1 deletions
diff --git a/openstack/common/jsonutils.py b/openstack/common/jsonutils.py
index 6130a7f..e8e14c4 100644
--- a/openstack/common/jsonutils.py
+++ b/openstack/common/jsonutils.py
@@ -107,7 +107,7 @@ def to_primitive(value, convert_instances=False, level=0):
elif hasattr(value, 'iteritems'):
return to_primitive(dict(value.iteritems()),
convert_instances=convert_instances,
- level=level)
+ level=level + 1)
elif hasattr(value, '__iter__'):
return to_primitive(list(value), level)
elif convert_instances and hasattr(value, '__dict__'):
diff --git a/tests/unit/test_jsonutils.py b/tests/unit/test_jsonutils.py
index fe25697..46b5b36 100644
--- a/tests/unit/test_jsonutils.py
+++ b/tests/unit/test_jsonutils.py
@@ -95,6 +95,24 @@ class ToPrimitiveTestCase(unittest.TestCase):
p = jsonutils.to_primitive(x)
self.assertEquals(p, {'a': 1, 'b': 2, 'c': 3})
+ def test_iteritems_with_cycle(self):
+ class IterItemsClass(object):
+ def __init__(self):
+ self.data = dict(a=1, b=2, c=3)
+ self.index = 0
+
+ def iteritems(self):
+ return self.data.items()
+
+ x = IterItemsClass()
+ x2 = IterItemsClass()
+ x.data['other'] = x2
+ x2.data['other'] = x
+
+ # If the cycle isn't caught, to_primitive() will eventually result in
+ # an exception due to excessive recursion depth.
+ p = jsonutils.to_primitive(x)
+
def test_instance(self):
class MysteryClass(object):
a = 10