Commit a7c4a527 authored by Nicolas Dumazet's avatar Nicolas Dumazet

add support for interfaces on Portal Type classes.

You can now add and remove interfaces to Portal Types on the fly.


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@39879 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent fa803092
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import sys import sys
from Products.ERP5Type.Globals import InitializeClass from Products.ERP5Type.Globals import InitializeClass
from Products.ERP5Type.Base import Base as ERP5Base from Products.ERP5Type.Base import Base as ERP5Base
from ExtensionClass import ExtensionClass, pmc_init_of from ExtensionClass import ExtensionClass, pmc_init_of
from zope.interface import classImplements
from ZODB.broken import Broken, PersistentBroken from ZODB.broken import Broken, PersistentBroken
from zLOG import LOG, WARNING, BLATHER from zLOG import LOG, WARNING, BLATHER
...@@ -120,22 +123,28 @@ class PortalTypeMetaClass(ExtensionClass): ...@@ -120,22 +123,28 @@ class PortalTypeMetaClass(ExtensionClass):
portal_type = klass.__name__ portal_type = klass.__name__
try: try:
baseclasses, attributes = generatePortalTypeClass(portal_type) class_definition = generatePortalTypeClass(portal_type)
except AttributeError: except AttributeError:
LOG("ERP5Type.Dynamic", WARNING, LOG("ERP5Type.Dynamic", WARNING,
"Could not access Portal Type Object for type %r" "Could not access Portal Type Object for type %r"
% portal_type, error=sys.exc_info()) % portal_type, error=sys.exc_info())
baseclasses = (ERP5BaseBroken, ) base_list = (ERP5BaseBroken, )
attributes = {} attribute_dict = {}
interface_list = []
else:
base_list, interface_list, attribute_dict = class_definition
# save the old bases to be able to restore a ghost state later # save the old bases to be able to restore a ghost state later
klass.__ghostbase__ = klass.__bases__ klass.__ghostbase__ = klass.__bases__
klass.__bases__ = baseclasses klass.__bases__ = base_list
for key, value in attributes.iteritems(): for key, value in attribute_dict.iteritems():
setattr(klass, key, value) setattr(klass, key, value)
klass.resetAcquisitionAndSecurity() klass.resetAcquisitionAndSecurity()
for interface in interface_list:
classImplements(klass, interface)
def generateLazyPortalTypeClass(portal_type_name): def generateLazyPortalTypeClass(portal_type_name):
return PortalTypeMetaClass(portal_type_name, (GhostPortalType,), {}) return PortalTypeMetaClass(portal_type_name, (GhostPortalType,), {})
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
import sys import sys
import inspect import inspect
from types import ModuleType from types import ModuleType
from dynamic_module import registerDynamicModule from dynamic_module import registerDynamicModule
...@@ -39,6 +38,8 @@ from Products.ERP5Type.Globals import InitializeClass ...@@ -39,6 +38,8 @@ from Products.ERP5Type.Globals import InitializeClass
from Products.ERP5Type.Utils import setDefaultClassProperties from Products.ERP5Type.Utils import setDefaultClassProperties
from Products.ERP5Type import document_class_registry, mixin_class_registry from Products.ERP5Type import document_class_registry, mixin_class_registry
from Products.ERP5Type import PropertySheet as FilesystemPropertySheet from Products.ERP5Type import PropertySheet as FilesystemPropertySheet
from zope.interface import classImplements
from zLOG import LOG, ERROR, INFO from zLOG import LOG, ERROR, INFO
def _importClass(classpath): def _importClass(classpath):
...@@ -175,11 +176,19 @@ def generatePortalTypeClass(portal_type_name): ...@@ -175,11 +176,19 @@ def generatePortalTypeClass(portal_type_name):
baseclasses = [klass] + accessor_holder_list + mixin_class_list baseclasses = [klass] + accessor_holder_list + mixin_class_list
interface_class_list = []
if interface_list:
from Products.ERP5Type import interfaces
interface_class_list = [getattr(interfaces, name)
for name in interface_list]
#LOG("ERP5Type.dynamic", INFO, #LOG("ERP5Type.dynamic", INFO,
# "Portal type %s loaded with bases %s" \ # "Portal type %s loaded with bases %s" \
# % (portal_type_name, repr(baseclasses))) # % (portal_type_name, repr(baseclasses)))
return tuple(baseclasses), dict(portal_type=portal_type_name) return (tuple(baseclasses),
interface_class_list,
dict(portal_type=portal_type_name))
from lazy_class import generateLazyPortalTypeClass from lazy_class import generateLazyPortalTypeClass
def initializeDynamicModules(): def initializeDynamicModules():
......
...@@ -35,6 +35,8 @@ from Products.ERP5Type.dynamic.portal_type_class import synchronizeDynamicModule ...@@ -35,6 +35,8 @@ from Products.ERP5Type.dynamic.portal_type_class import synchronizeDynamicModule
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from Products.ERP5Type.tests.backportUnittest import expectedFailure, skip from Products.ERP5Type.tests.backportUnittest import expectedFailure, skip
from zope.interface import Interface, implementedBy
class TestPortalTypeClass(ERP5TypeTestCase): class TestPortalTypeClass(ERP5TypeTestCase):
def getBusinessTemplateList(self): def getBusinessTemplateList(self):
return 'erp5_base', return 'erp5_base',
...@@ -205,6 +207,40 @@ class TestPortalTypeClass(ERP5TypeTestCase): ...@@ -205,6 +207,40 @@ class TestPortalTypeClass(ERP5TypeTestCase):
self.assertEquals(accessor(), 'foobar') self.assertEquals(accessor(), 'foobar')
self.assertEquals(temp.__class__.__module__, 'erp5.temp_portal_type') self.assertEquals(temp.__class__.__module__, 'erp5.temp_portal_type')
def testInterfaces(self):
types_tool = self.portal.portal_types
# a new interface
class IForTest(Interface):
pass
from Products.ERP5Type import interfaces
interfaces.IForTest = IForTest
# one new type
dummy_type = types_tool.newContent('InterfaceTestType',
'Base Type')
# implementing IForTest
dummy_type.edit(type_class='Person',
type_interface_list=['IForTest',],)
transaction.commit()
from erp5.portal_type import InterfaceTestType
# it's necessary to load the class
# to have a correct list of interfaces
implemented_by = list(implementedBy(InterfaceTestType))
self.failIf(IForTest in implemented_by)
InterfaceTestType.loadClass()
implemented_by = list(implementedBy(InterfaceTestType))
self.assertTrue(IForTest in implemented_by,
'IForTest not in %s' % implemented_by)
InterfaceTestType.restoreGhostState()
implemented_by = list(implementedBy(InterfaceTestType))
self.failIf(IForTest in implemented_by)
class TestZodbPropertySheet(ERP5TypeTestCase): class TestZodbPropertySheet(ERP5TypeTestCase):
""" """
XXX: WORK IN PROGRESS XXX: WORK IN PROGRESS
......
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