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
This commit is contained in:
parent
1c1b36985b
commit
2d6f84742a
@ -107,7 +107,7 @@ def to_primitive(value, convert_instances=False, level=0):
|
|||||||
elif hasattr(value, 'iteritems'):
|
elif hasattr(value, 'iteritems'):
|
||||||
return to_primitive(dict(value.iteritems()),
|
return to_primitive(dict(value.iteritems()),
|
||||||
convert_instances=convert_instances,
|
convert_instances=convert_instances,
|
||||||
level=level)
|
level=level + 1)
|
||||||
elif hasattr(value, '__iter__'):
|
elif hasattr(value, '__iter__'):
|
||||||
return to_primitive(list(value), level)
|
return to_primitive(list(value), level)
|
||||||
elif convert_instances and hasattr(value, '__dict__'):
|
elif convert_instances and hasattr(value, '__dict__'):
|
||||||
|
@ -95,6 +95,24 @@ class ToPrimitiveTestCase(unittest.TestCase):
|
|||||||
p = jsonutils.to_primitive(x)
|
p = jsonutils.to_primitive(x)
|
||||||
self.assertEquals(p, {'a': 1, 'b': 2, 'c': 3})
|
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):
|
def test_instance(self):
|
||||||
class MysteryClass(object):
|
class MysteryClass(object):
|
||||||
a = 10
|
a = 10
|
||||||
|
Loading…
Reference in New Issue
Block a user