Commit ac09b820 authored by Julien Muchembled's avatar Julien Muchembled

ERP5Type: make sure the correct __setattr__ is used when the class is still ghost

parent 0b562a83
......@@ -118,6 +118,17 @@ class GhostBaseMetaClass(ExtensionClass, AccessorHolderType):
# (which would even trigger migration, resulting in a ConflictError).
cls.__getnewargs__ = None
def __setattr__(self, name, value):
"""
When the first access to an object is a call to setattr, __getattribute__
is not involved. Here, we preempt persistent.__setattr__ so that the
correct __setattr__ is used. For example, without this, a broken object
(ERP5BaseBroken) would not raise.
"""
self.__class__.loadClass()
setattr(self, name, value)
cls.__setattr__ = __setattr__
InitGhostBase = GhostBaseMetaClass('InitGhostBase', (ERP5Base,), {})
class PortalTypeMetaClass(GhostBaseMetaClass, PropertyHolder):
......
......@@ -33,7 +33,9 @@ import unittest
import transaction
from persistent import Persistent
from ZODB.broken import BrokenModified
from Products.ERP5Type.dynamic.portal_type_class import synchronizeDynamicModules
from Products.ERP5Type.dynamic.lazy_class import ERP5BaseBroken, InitGhostBase
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from zope.interface import Interface, implementedBy
......@@ -276,7 +278,7 @@ class TestPortalTypeClass(ERP5TypeTestCase):
# then change the type value to something not descending from Folder
# and check behavior
ptype.setTypeClass('Address')
ptype.setTypeClass(types_tool.Address.getTypeClass())
# while the class has not been reset is should still descend from Folder
self.assertTrue(issubclass(module_class, Folder))
......@@ -2245,6 +2247,26 @@ class Test(ERP5TypeTestCase):
self.assertNotEqual(re.search(expected_msg_re_str, output, re.DOTALL), None,
"Expected '%s' in '%s'" % (expected_msg_re_str, output))
def testERP5Broken(self):
# Create a broken ghost object
import erp5.portal_type
name = self._testMethodName
ptype = self.portal.portal_types.newContent(name, type_class="File")
file = ptype.constructInstance(self.portal, name, data="foo")
self.assertEqual(file.size, 3)
self.commit()
self.portal._p_jar.cacheMinimize()
del file
delattr(erp5.portal_type, name)
ptype.setTypeClass(name)
self.commit()
file = self.portal.__dict__[name]
self.assertTrue(isinstance(file, InitGhostBase))
# Check that the class is unghosted before resolving __setattr__
self.assertRaises(BrokenModified, setattr, file, "size", 0)
self.assertTrue(isinstance(file, ERP5BaseBroken))
self.assertEqual(file.size, 3)
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestPortalTypeClass))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment