Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
erp5
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Laurent S
erp5
Commits
ac09b820
Commit
ac09b820
authored
Jun 06, 2016
by
Julien Muchembled
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ERP5Type: make sure the correct __setattr__ is used when the class is still ghost
parent
0b562a83
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
34 additions
and
1 deletion
+34
-1
product/ERP5Type/dynamic/lazy_class.py
product/ERP5Type/dynamic/lazy_class.py
+11
-0
product/ERP5Type/tests/testDynamicClassGeneration.py
product/ERP5Type/tests/testDynamicClassGeneration.py
+23
-1
No files found.
product/ERP5Type/dynamic/lazy_class.py
View file @
ac09b820
...
@@ -118,6 +118,17 @@ class GhostBaseMetaClass(ExtensionClass, AccessorHolderType):
...
@@ -118,6 +118,17 @@ class GhostBaseMetaClass(ExtensionClass, AccessorHolderType):
# (which would even trigger migration, resulting in a ConflictError).
# (which would even trigger migration, resulting in a ConflictError).
cls
.
__getnewargs__
=
None
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
,),
{})
InitGhostBase
=
GhostBaseMetaClass
(
'InitGhostBase'
,
(
ERP5Base
,),
{})
class
PortalTypeMetaClass
(
GhostBaseMetaClass
,
PropertyHolder
):
class
PortalTypeMetaClass
(
GhostBaseMetaClass
,
PropertyHolder
):
...
...
product/ERP5Type/tests/testDynamicClassGeneration.py
View file @
ac09b820
...
@@ -33,7 +33,9 @@ import unittest
...
@@ -33,7 +33,9 @@ import unittest
import
transaction
import
transaction
from
persistent
import
Persistent
from
persistent
import
Persistent
from
ZODB.broken
import
BrokenModified
from
Products.ERP5Type.dynamic.portal_type_class
import
synchronizeDynamicModules
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
Products.ERP5Type.tests.ERP5TypeTestCase
import
ERP5TypeTestCase
from
zope.interface
import
Interface
,
implementedBy
from
zope.interface
import
Interface
,
implementedBy
...
@@ -276,7 +278,7 @@ class TestPortalTypeClass(ERP5TypeTestCase):
...
@@ -276,7 +278,7 @@ class TestPortalTypeClass(ERP5TypeTestCase):
# then change the type value to something not descending from Folder
# then change the type value to something not descending from Folder
# and check behavior
# 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
# while the class has not been reset is should still descend from Folder
self
.
assertTrue
(
issubclass
(
module_class
,
Folder
))
self
.
assertTrue
(
issubclass
(
module_class
,
Folder
))
...
@@ -2245,6 +2247,26 @@ class Test(ERP5TypeTestCase):
...
@@ -2245,6 +2247,26 @@ class Test(ERP5TypeTestCase):
self.assertNotEqual(re.search(expected_msg_re_str, output, re.DOTALL), None,
self.assertNotEqual(re.search(expected_msg_re_str, output, re.DOTALL), None,
"Expected '
%
s
' in '
%
s
'" % (expected_msg_re_str, output))
"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():
def test_suite():
suite = unittest.TestSuite()
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestPortalTypeClass))
suite.addTest(unittest.makeSuite(TestPortalTypeClass))
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment