From 819ffaf9efe0d5a3eee85afc847ceb6969242833 Mon Sep 17 00:00:00 2001 From: Alexey Kotlyarov Date: Tue, 8 Dec 2015 12:56:00 +1100 Subject: Test LazyValues handling CyclicDefinitionError --- tests/test_containers.py | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/tests/test_containers.py b/tests/test_containers.py index 083b306..9107b0d 100644 --- a/tests/test_containers.py +++ b/tests/test_containers.py @@ -78,18 +78,40 @@ class LazyStubTestCase(unittest.TestCase): self.assertEqual(2, stub.factory_parent.rank) self.assertEqual(1, stub.factory_parent.factory_parent.rank) - def test_cyclic_definition(self): - class LazyAttr(containers.LazyValue): - def __init__(self, attrname): - self.attrname = attrname + class LazyAttr(containers.LazyValue): + def __init__(self, attrname): + self.attrname = attrname - def evaluate(self, obj, container=None): - return 1 + getattr(obj, self.attrname) + def evaluate(self, obj, container=None): + return 1 + getattr(obj, self.attrname) - stub = containers.LazyStub({'one': LazyAttr('two'), 'two': LazyAttr('one')}) + def test_cyclic_definition(self): + stub = containers.LazyStub({ + 'one': self.LazyAttr('two'), + 'two': self.LazyAttr('one'), + }) self.assertRaises(containers.CyclicDefinitionError, getattr, stub, 'one') + def test_cyclic_definition_rescue(self): + class LazyAttrDefault(self.LazyAttr): + def __init__(self, attname, defvalue): + super(LazyAttrDefault, self).__init__(attname) + self.defvalue = defvalue + def evaluate(self, obj, container=None): + try: + return super(LazyAttrDefault, self).evaluate(obj, container) + except containers.CyclicDefinitionError: + return self.defvalue + + stub = containers.LazyStub({ + 'one': LazyAttrDefault('two', 10), + 'two': self.LazyAttr('one'), + }) + + self.assertEqual(10, stub.one) + self.assertEqual(11, stub.two) + def test_representation(self): class RandomObj(object): pass -- cgit v1.2.3 From f023e5a477668b8374a75c78e87d946b21a27f15 Mon Sep 17 00:00:00 2001 From: Alexey Kotlyarov Date: Tue, 8 Dec 2015 12:57:24 +1100 Subject: Don't leave AttributeBuilder in an inconsistent state on exceptions When one of the LazyValues raises an exception, don't leave its name in __pending stack of the AttributeBuilder, preventing evaluation of any other LazyValues. --- factory/containers.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/factory/containers.py b/factory/containers.py index 0ae354b..ec33ca1 100644 --- a/factory/containers.py +++ b/factory/containers.py @@ -102,8 +102,10 @@ class LazyStub(object): val = self.__attrs[name] if isinstance(val, LazyValue): self.__pending.append(name) - val = val.evaluate(self, self.__containers) - last = self.__pending.pop() + try: + val = val.evaluate(self, self.__containers) + finally: + last = self.__pending.pop() assert name == last self.__values[name] = val return val -- cgit v1.2.3