diff options
author | Russell Bryant <rbryant@redhat.com> | 2012-07-18 16:15:52 -0400 |
---|---|---|
committer | Russell Bryant <rbryant@redhat.com> | 2012-07-18 16:15:52 -0400 |
commit | a91d35a3da1e6c1228cedb7e07f2b3c0798001fc (patch) | |
tree | 515c7f7bdb08c1a3b8cb3b6cc8b05f5bea6377f2 | |
parent | a9ed13380c948f3c8372e8aba244e1b030b9fe06 (diff) | |
download | oslo-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.py | 2 | ||||
-rw-r--r-- | tests/unit/test_jsonutils.py | 18 |
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 |