Commit 38e142d5 authored by Nicolas Dumazet's avatar Nicolas Dumazet

Nicer way to set re-initialize classes after changing their bases.

1) Do not use gc.get_referrers as this is highly inefficient.
(the returned list contains a lot of objects, some of them
are persistent objects, some of them are not classes, etc, etc...
But worse, "dead" objects with a zero reference count can be returned
by this function, and this function would "ressucitate" them.
gc.get_referrers for application code is usually a bad idea)

2) Use instead a Python metaclass to track who's been subclassing
a portal type class, and after a change on the portal type class,
we just call the efficient PortalTypeMetaClass.getSubclassList to
get descendants.


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@39751 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 07ecaeb3
# -*- coding: utf-8 -*-
import gc, sys
import sys
from Products.ERP5Type.Base import Base as ERP5Base
from ExtensionClass import Base as ExtensionBase
from ZODB.broken import Broken, PersistentBroken
......@@ -13,12 +13,36 @@ ERP5BaseBroken = type('ERP5BaseBroken', (Broken, ERP5Base), dict(x
if x[0] not in ('__dict__', '__module__', '__weakref__')))
ExtensionClass = type(ExtensionBase)
class PortalTypeMetaClass(ExtensionClass):
"""
Meta class that will be used by portal type classes
"""
# register which classes subclass portal type classes
subclass_register = {} # XXX ideal defaultdict(list) wannabe
def __init__(cls, name, bases, dictionary):
"""
This method is called when a portal type class is
created, or when a class inheriting a portal type
class is created
"""
for parent in bases:
if issubclass(type(parent), PortalTypeMetaClass):
PortalTypeMetaClass.subclass_register.setdefault(parent, []).append(cls)
super(PortalTypeMetaClass, cls).__init__(name, bases, dictionary)
@classmethod
def getSubclassList(metacls, cls):
"""
Returns classes deriving from cls
"""
return metacls.subclass_register.get(cls, [])
def InitializePortalTypeClass(klass):
# beware of the scary meta type
ExtensionClass.__init__(klass, klass)
for klass in gc.get_referrers(klass):
if isinstance(klass, ExtensionClass):
InitializePortalTypeClass(klass)
for klass in PortalTypeMetaClass.getSubclassList(klass):
ExtensionClass.__init__(klass, klass)
def generateLazyPortalTypeClass(portal_type_name,
portal_type_class_loader):
......@@ -87,4 +111,4 @@ def generateLazyPortalTypeClass(portal_type_name,
# "loading attribute %s.%s..." % (name, attr))
return load(self, attr)
return type(portal_type_name, (GhostPortalType,), dict())
return PortalTypeMetaClass(portal_type_name, (GhostPortalType,), dict())
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