Log message for revision 113943: LP #143531: Fix broken object so they give access to their state. merge branch gotcha-LP143531
Changed: U Zope/branches/2.12/doc/CHANGES.rst U Zope/branches/2.12/src/OFS/Uninstalled.py U Zope/branches/2.12/src/OFS/tests/test_Uninstalled.py -=- Modified: Zope/branches/2.12/doc/CHANGES.rst =================================================================== --- Zope/branches/2.12/doc/CHANGES.rst 2010-06-27 16:12:02 UTC (rev 113942) +++ Zope/branches/2.12/doc/CHANGES.rst 2010-06-27 16:17:03 UTC (rev 113943) @@ -11,6 +11,8 @@ Bugs Fixed ++++++++++ +- LP #143531: Fix broken object so they give access to their state. + - LP #578326: Issue a warning if someone specifies a non-public permission attribute in the browser:view directive. This attribute has never been supported in Zope 2. Modified: Zope/branches/2.12/src/OFS/Uninstalled.py =================================================================== --- Zope/branches/2.12/src/OFS/Uninstalled.py 2010-06-27 16:12:02 UTC (rev 113942) +++ Zope/branches/2.12/src/OFS/Uninstalled.py 2010-06-27 16:17:03 UTC (rev 113943) @@ -22,12 +22,14 @@ from App.special_dtml import DTMLFile from OFS.SimpleItem import Item from Persistence import Overridable +from ZODB.broken import Broken as ZODB_Broken +from ZODB.broken import persistentBroken broken_klasses={} broken_klasses_lock = allocate_lock() LOG = getLogger('OFS.Uninstalled') -class BrokenClass(Explicit, Item, Overridable): +class BrokenClass(ZODB_Broken, Explicit, Item, Overridable): _p_changed=0 meta_type='Broken Because Product is Gone' icon='p_/broken' @@ -37,12 +39,6 @@ manage_page_header = Acquired manage_page_footer = Acquired - def __getstate__(self): - raise SystemError, ( - """This object was originally created by a product that - is no longer installed. It cannot be updated. - (%s)""" % repr(self)) - def __getattr__(self, name): if name[:3]=='_p_': return BrokenClass.inheritedAttribute('__getattr__')(self, name) @@ -74,6 +70,7 @@ klass.info=( 'This object\'s class was %s in module %s.' % (klass.__name__, klass.__module__)) + klass = persistentBroken(klass) LOG.warning('Could not import class %s ' 'from module %s' % (`klass.__name__`, `klass.__module__`)) finally: Modified: Zope/branches/2.12/src/OFS/tests/test_Uninstalled.py =================================================================== --- Zope/branches/2.12/src/OFS/tests/test_Uninstalled.py 2010-06-27 16:12:02 UTC (rev 113942) +++ Zope/branches/2.12/src/OFS/tests/test_Uninstalled.py 2010-06-27 16:17:03 UTC (rev 113943) @@ -13,7 +13,14 @@ ############################################################################## import unittest +from OFS.SimpleItem import SimpleItem +from Testing.ZopeTestCase import base + +class ToBreak(SimpleItem): + pass + + class TestsOfBroken(unittest.TestCase): """Tests for the factory for "broken" classes. """ @@ -77,24 +84,8 @@ self.assertEqual(klass.__module__, 'Products.MyProduct.MyClass') self.assertEqual(klass.product_name, 'MyProduct') - def test_Broken_instance___getstate___raises_useful_exception(self): - # see http://www.zope.org/Collectors/Zope/2157 - from OFS.Uninstalled import Broken - from OFS.Uninstalled import BrokenClass - OID = '\x01' * 8 - - inst = Broken(self, OID, ('Products.MyProduct.MyClass', 'MyClass')) - - try: - dict = inst.__getstate__() - except SystemError, e: - self.failUnless('MyClass' in str(e), str(e)) - else: - self.fail("'__getstate__' didn't raise SystemError!") - def test_Broken_instance___getattr___allows_persistence_attrs(self): from OFS.Uninstalled import Broken - from OFS.Uninstalled import BrokenClass OID = '\x01' * 8 PERSISTENCE_ATTRS = ["_p_changed", "_p_jar", @@ -119,14 +110,47 @@ for meth_name in PERSISTENCE_METHODS: meth = getattr(inst, meth_name) # doesn't raise + +class TestsIntegratedBroken(base.TestCase): + + def test_Broken_instance___getstate___gives_access_to_its_state(self): + from Acquisition import aq_base + from OFS.Uninstalled import BrokenClass + from OFS.tests import test_Uninstalled + import transaction + + # store an instance + tr = ToBreak() + tr.id = 'tr' + self.app._setObject('tr', tr) + # commit to allow access in another connection + transaction.commit() + # remove class from namespace to ensure broken object + del test_Uninstalled.ToBreak + # get new connection that will give access to broken object + app = base.app() + inst = aq_base(app.tr) + self.failUnless(isinstance(inst, BrokenClass)) + state = inst.__getstate__() + self.assertEqual(state, {'id': 'tr'}) + + # cleanup + app.manage_delObjects('tr') + transaction.commit() + # check that object is not left over + app = base.app() + self.failIf('tr' in app.objectIds()) + + def test_suite(): suite = unittest.TestSuite() - suite.addTest( unittest.makeSuite(TestsOfBroken)) + suite.addTest(unittest.makeSuite(TestsOfBroken)) + suite.addTest(unittest.makeSuite(TestsIntegratedBroken)) return suite + def main(): unittest.main(defaultTest='test_suite') if __name__ == '__main__': main() - _______________________________________________ Zope-Checkins maillist - Zope-Checkins@zope.org https://mail.zope.org/mailman/listinfo/zope-checkins