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 -*- # -*- coding: utf-8 -*-
import gc, sys import sys
from Products.ERP5Type.Base import Base as ERP5Base from Products.ERP5Type.Base import Base as ERP5Base
from ExtensionClass import Base as ExtensionBase from ExtensionClass import Base as ExtensionBase
from ZODB.broken import Broken, PersistentBroken from ZODB.broken import Broken, PersistentBroken
...@@ -13,12 +13,36 @@ ERP5BaseBroken = type('ERP5BaseBroken', (Broken, ERP5Base), dict(x ...@@ -13,12 +13,36 @@ ERP5BaseBroken = type('ERP5BaseBroken', (Broken, ERP5Base), dict(x
if x[0] not in ('__dict__', '__module__', '__weakref__'))) if x[0] not in ('__dict__', '__module__', '__weakref__')))
ExtensionClass = type(ExtensionBase) 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): def InitializePortalTypeClass(klass):
# beware of the scary meta type
ExtensionClass.__init__(klass, klass) ExtensionClass.__init__(klass, klass)
for klass in gc.get_referrers(klass): for klass in PortalTypeMetaClass.getSubclassList(klass):
if isinstance(klass, ExtensionClass): ExtensionClass.__init__(klass, klass)
InitializePortalTypeClass(klass)
def generateLazyPortalTypeClass(portal_type_name, def generateLazyPortalTypeClass(portal_type_name,
portal_type_class_loader): portal_type_class_loader):
...@@ -87,4 +111,4 @@ def generateLazyPortalTypeClass(portal_type_name, ...@@ -87,4 +111,4 @@ def generateLazyPortalTypeClass(portal_type_name,
# "loading attribute %s.%s..." % (name, attr)) # "loading attribute %s.%s..." % (name, attr))
return load(self, 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