Commit 4dde4bdf authored by Yoshinori Okuji's avatar Yoshinori Okuji

Define isTempDocument to specify if an object is a temporary object or...

Define isTempDocument to specify if an object is a temporary object or persistent object, rather than using a hack. Remove hasattr in TempDocumentConstructor. Write a test for _aq_dynamic with a temporary object. Remove an unused test. Make it safe to call _aq_dynamic with a temporary object.

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@14005 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent b3a6d79c
...@@ -407,6 +407,7 @@ class Base( CopyContainer, ...@@ -407,6 +407,7 @@ class Base( CopyContainer,
isPredicate = 0 # isPredicate = 0 #
isTemplate = 0 # isTemplate = 0 #
isDocument = 0 # isDocument = 0 #
isTempDocument = 0 # If set to 0, instances are temporary.
# Dynamic method acquisition system (code generation) # Dynamic method acquisition system (code generation)
aq_method_generated = {} aq_method_generated = {}
...@@ -490,6 +491,13 @@ class Base( CopyContainer, ...@@ -490,6 +491,13 @@ class Base( CopyContainer,
# Proceed with property generation # Proceed with property generation
klass = self.__class__ klass = self.__class__
if self.isTempObject():
# If self is a temporary object, generate methods for the base
# document class rather than for the temporary document class.
# Otherwise, instances of the base document class would fail
# in calling such methods, because they are not instances of
# the temporary document class.
klass = klass.__bases__[0]
generated = 0 # Prevent infinite loops generated = 0 # Prevent infinite loops
# Generate class methods # Generate class methods
...@@ -2114,13 +2122,9 @@ class Base( CopyContainer, ...@@ -2114,13 +2122,9 @@ class Base( CopyContainer,
security.declarePublic('isTempObject') security.declarePublic('isTempObject')
def isTempObject(self): def isTempObject(self):
"""Return true if self is an instance of a temporary document class.
""" """
Tells if an object is temporary or not return getattr(self.__class__, 'isTempDocument', 0)
Implementation is based on the fact that reindexObject method is overloaded
for all TempObjects with the same dummy method
"""
return self.reindexObject.im_func is self._temp_reindexObject.im_func
# Workflow Related Method # Workflow Related Method
security.declarePublic('getWorkflowStateItemList') security.declarePublic('getWorkflowStateItemList')
...@@ -2916,6 +2920,7 @@ class TempBase(Base): ...@@ -2916,6 +2920,7 @@ class TempBase(Base):
we shoud used TempBase we shoud used TempBase
""" """
isIndexable = 0 isIndexable = 0
isTempDocument = 1
# Declarative security # Declarative security
security = ClassSecurityInfo() security = ClassSecurityInfo()
......
...@@ -350,6 +350,7 @@ class TempDocumentConstructor(DocumentConstructor): ...@@ -350,6 +350,7 @@ class TempDocumentConstructor(DocumentConstructor):
def __init__(self, klass): def __init__(self, klass):
# Create a new class to set permissions specific to temporary objects. # Create a new class to set permissions specific to temporary objects.
class TempDocument(klass): class TempDocument(klass):
isTempDocument = 1
pass pass
# Replace some attributes. # Replace some attributes.
...@@ -369,7 +370,8 @@ class TempDocumentConstructor(DocumentConstructor): ...@@ -369,7 +370,8 @@ class TempDocumentConstructor(DocumentConstructor):
o = self.klass(id) o = self.klass(id)
if kw: if kw:
o.__of__(folder)._edit(force_update=1, **kw) o.__of__(folder)._edit(force_update=1, **kw)
if hasattr(folder, 'isTempObject') and folder.isTempObject(): isTempObject = getattr(folder, 'isTempObject', None)
if isTempObject is not None and isTempObject():
folder._setObject(id, o)# Temp Object in Temp Object should use containment folder._setObject(id, o)# Temp Object in Temp Object should use containment
return id # return id to be compatible with CMF constructInstance return id # return id to be compatible with CMF constructInstance
else: # Temp Object in Persistent Object should use acquisition else: # Temp Object in Persistent Object should use acquisition
......
...@@ -209,19 +209,8 @@ class TestERP5Type(PropertySheetTestCase, LogInterceptor): ...@@ -209,19 +209,8 @@ class TestERP5Type(PropertySheetTestCase, LogInterceptor):
self.failUnless(business_template.getTitle()==test_string) self.failUnless(business_template.getTitle()==test_string)
# Test Dynamic Code Generation # Test Dynamic Code Generation
def test_01_AqDynamic(self): def test_02_AqDynamic(self, quiet=quiet, run=run_all_test):
portal = self.getPortal() if not run: return
#module = portal.person
from Products.ERP5Type.Base import initializeClassDynamicProperties
from Products.ERP5Type.Base import initializePortalTypeDynamicProperties
from Products.ERP5Type.Base import Base
from Products.ERP5Type import Document
initializeClassDynamicProperties(portal, Base)
# Base class should now have a state method
# self.failUnless(hasattr(Base, 'getFirstName'))
# This test is now useless since methods are portal type based
def test_02_AqDynamic(self):
portal = self.getPortal() portal = self.getPortal()
module = self.getPersonModule() module = self.getPersonModule()
person = module.newContent(id='1', portal_type='Person') person = module.newContent(id='1', portal_type='Person')
...@@ -1273,6 +1262,72 @@ class TestPropertySheet: ...@@ -1273,6 +1262,72 @@ class TestPropertySheet:
checked_permission="View"), checked_permission="View"),
[doo.getTitle(), bar.getTitle(), ]) [doo.getTitle(), bar.getTitle(), ])
def test_25_AqDynamicWithTempObject(self, quiet=quiet, run=run_all_test):
"""Check if _aq_dynamic works correctly, regardless of whether
it is first called for a temporary object or a persistent object.
This test is based on the fact that a portal type is shared between
a temporary document and a persistent document, and if a class for
the temporary document is used for generating new methods, calling
such methods from a persistent object may fail, because such a
persistent object is not an instance of the temporary document class.
"""
if not run: return
portal = self.getPortal()
# Clear out all generated methods.
_aq_reset()
# Create a new temporary person object.
from Products.ERP5Type.Document import newTempPerson
o = newTempPerson(portal, 'temp_person_1')
self.failUnless(o.isTempObject())
# This should generate a workflow method.
self.assertEquals(o.getValidationState(), 'draft')
o.validate()
self.assertEquals(o.getValidationState(), 'validated')
# Create a new persistent person object.
person_module = portal.person_module
person_id = 'person_1'
if person_id in person_module.objectIds():
person_module.manage_delObjects([person_id])
o = person_module.newContent(id=person_id, portal_type='Person')
self.failIf(o.isTempObject())
# This should call methods generated above for the temporary object.
self.assertEquals(o.getValidationState(), 'draft')
o.validate()
self.assertEquals(o.getValidationState(), 'validated')
# Paranoia: test the reverse snenario as well, although this
# should succeed anyway.
# Create a new persistent person object.
person_id = 'person_2'
if person_id in person_module.objectIds():
person_module.manage_delObjects([person_id])
o = person_module.newContent(id=person_id, portal_type='Person')
self.failIf(o.isTempObject())
# Clear out all generated methods.
_aq_reset()
# This should generate workflow methods.
self.assertEquals(o.getValidationState(), 'draft')
o.validate()
self.assertEquals(o.getValidationState(), 'validated')
# Create a new temporary person object.
o = newTempPerson(portal, 'temp_person_2')
self.failUnless(o.isTempObject())
# This should call methods generated for the persistent object.
self.assertEquals(o.getValidationState(), 'draft')
o.validate()
self.assertEquals(o.getValidationState(), 'validated')
if __name__ == '__main__': if __name__ == '__main__':
framework() framework()
else: else:
......
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