vregistry.py
branchtls-sprint
changeset 665 1305da1ce3f9
parent 660 5233a9457f6b
child 668 61b2328f9ed9
--- a/vregistry.py	Tue Feb 17 16:41:46 2009 +0100
+++ b/vregistry.py	Tue Feb 17 16:42:58 2009 +0100
@@ -205,149 +205,6 @@
     def __contains__(self, key):
         return key in self._registries
 
-
-    ##########
-    def register(self, obj, registryname=None):
-        registryname = registryname or obj.__registry__
-        registry = self._registries.setdefault(registryname, {})
-        registry.setdefault(obj.id, []).append(obj)
-        # XXX automatic reloading management
-        self._registered['%s.%s' % (obj.__module__, obj.id)] = obj
-
-    def register_if_interface_found(self, obj, registryname, iface):
-        registry = self._registries.setdefault(registryname, {})
-        for etype in self.registry_object('etypes'):
-            if implements(etype, iface):
-                registry.setdefault(obj.id, []).append(obj)
-                # XXX automatic reloading management
-                self._registered['%s.%s' % (obj.__module__, obj.id)] = obj
-                break
-
-    def unregister(self, obj, registryname=None):
-        registryname = registryname or obj.__registry__
-        registry = self.registry(registryname)
-        removed_id = obj.classid()
-        for registered in registry[obj.id]:
-            # use classid() to compare classes because vreg will probably
-            # have its own version of the class, loaded through execfile
-            if registered.classid() == removed_id:
-                # XXX automatic reloading management
-                registry[obj.id].remove(registered)
-                break
-    
-    def register_and_replace(self, obj, replaced, registryname=None):
-        registryname = registryname or obj.__registry__
-        registry = self.registry(registryname)
-        registered_objs = registry[obj.id]
-        for index, registered in enumerate(registered_objs):
-            if registered.classid() == replaced:
-                registry[obj.id][index] = obj
-                self._registered['%s.%s' % (obj.__module__, obj.id)] = obj
-    ##########
-    
-    def register_vobject_class(self, cls, _kicked=set()):
-        """handle vobject class registration
-        
-        vobject class with __abstract__ == True in their local dictionnary or
-        with a name starting starting by an underscore are not registered.
-        Also a vobject class needs to have __registry__ and id attributes set
-        to a non empty string to be registered.
-
-        Registration is actually handled by vobject's registerer.
-        """
-        if (cls.__dict__.get('__abstract__') or cls.__name__[0] == '_'
-            or not cls.__registry__ or not cls.id):
-            return
-        # while reloading a module :
-        # if cls was previously kicked, it means that there is a more specific
-        # vobject defined elsewhere re-registering cls would kick it out
-        if cls.classid() in _kicked:
-            self.debug('not re-registering %s because it was previously kicked',
-                      cls.classid())
-        else:
-            regname = cls.__registry__
-            if cls.id in self.config['disable-%s' % regname]:
-                return
-            registry = self._registries.setdefault(regname, {})
-            vobjects = registry.setdefault(cls.id, [])
-            registerer = cls.__registerer__(self, cls)
-            cls = registerer.do_it_yourself(vobjects)
-            #_kicked |= registerer.kicked
-            if cls:
-                # registered() is technically a classmethod but is not declared
-                # as such because we need to compose registered in some cases
-                vobject = cls.registered.im_func(cls, self)
-                try:
-                    vname = vobject.__name__
-                except AttributeError:
-                    vname = vobject.__class__.__name__
-                self.debug('registered vobject %s in registry %s with id %s',
-                          vname, cls.__registry__, cls.id)
-                vobjects.append(vobject)
-            
-    def unregister_module_vobjects(self, modname):
-        """removes registered objects coming from a given module
-
-        returns a dictionnary classid/class of all classes that will need
-        to be updated after reload (i.e. vobjects referencing classes defined
-        in the <modname> module)
-        """
-        unregistered = {}
-        # browse each registered object
-        for registry, objdict in self.items():
-            for oid, objects in objdict.items():
-                for obj in objects[:]:
-                    objname = obj.classid()
-                    # if the vobject is defined in this module, remove it
-                    if objname.startswith(modname):
-                        unregistered[objname] = obj
-                        objects.remove(obj)
-                        self.debug('unregistering %s in %s registry',
-                                  objname, registry)
-                    # if not, check if the vobject can be found in baseclasses
-                    # (because we also want subclasses to be updated)
-                    else:
-                        if not isinstance(obj, type):
-                            obj = obj.__class__
-                        for baseclass in obj.__bases__:
-                            if hasattr(baseclass, 'classid'):
-                                baseclassid = baseclass.classid()
-                                if baseclassid.startswith(modname):
-                                    unregistered[baseclassid] = baseclass
-                # update oid entry
-                if objects:
-                    objdict[oid] = objects
-                else:
-                    del objdict[oid]
-        return unregistered
-
-
-    def update_registered_subclasses(self, oldnew_mapping):
-        """updates subclasses of re-registered vobjects
-
-        if baseviews.PrimaryView is changed, baseviews.py will be reloaded
-        automatically and the new version of PrimaryView will be registered.
-        But all existing subclasses must also be notified of this change, and
-        that's what this method does
-
-        :param oldnew_mapping: a dict mapping old version of a class to
-                               the new version
-        """
-        # browse each registered object
-        for objdict in self.values():
-            for objects in objdict.values():
-                for obj in objects:
-                    if not isinstance(obj, type):
-                        obj = obj.__class__
-                    # build new baseclasses tuple
-                    newbases = tuple(oldnew_mapping.get(baseclass, baseclass)
-                                     for baseclass in obj.__bases__)
-                    # update obj's baseclasses tuple (__bases__) if needed
-                    if newbases != obj.__bases__:
-                        self.debug('updating %s.%s base classes',
-                                  obj.__module__, obj.__name__)
-                        obj.__bases__ = newbases
-
     def registry(self, name):
         """return the registry (dictionary of class objects) associated to
         this name
@@ -372,7 +229,69 @@
             for objs in registry.values():
                 result += objs
             return result
-        
+
+    def object_by_id(self, registry, cid, *args, **kwargs):
+        """return the most specific component according to the resultset"""
+        objects = self[registry][cid]
+        assert len(objects) == 1, objects
+        return objects[0].selected(*args, **kwargs)
+
+    # methods for explicit (un)registration ###################################
+    
+    def register(self, obj, registryname=None, oid=None):
+        """base method to add an object in the registry"""
+        registryname = registryname or obj.__registry__
+        oid = oid or obj.id
+        registry = self._registries.setdefault(registryname, {})
+        vobjects = registry.setdefault(oid, [])
+        # registered() is technically a classmethod but is not declared
+        # as such because we need to compose registered in some cases
+        vobject = obj.registered.im_func(cls, self)
+        assert not vobject in vobjects
+        vobjects.append(vobject)
+        try:
+            vname = vobject.__name__
+        except AttributeError:
+            vname = vobject.__class__.__name__
+        self.debug('registered vobject %s in registry %s with id %s',
+                   vname, registryname, oid)
+        # automatic reloading management
+        self._registered['%s.%s' % (obj.__module__, oid)] = obj
+
+    def unregister(self, obj, registryname=None):
+        registryname = registryname or obj.__registry__
+        registry = self.registry(registryname)
+        removed_id = obj.classid()
+        for registered in registry[obj.id]:
+            # use classid() to compare classes because vreg will probably
+            # have its own version of the class, loaded through execfile
+            if registered.classid() == removed_id:
+                # XXX automatic reloading management
+                try:
+                    registry[obj.id].remove(registered)
+                except ValueError:
+                    self.warning('can\'t remove %s, no id %s in the %s registry',
+                                 removed_id, obj.id, registryname)
+                except ValueError:
+                    self.warning('can\'t remove %s, not in the %s registry with id %s',
+                                 removed_id, registryname, obj.id)
+#                 else:
+#                     # if objects is empty, remove oid from registry
+#                     if not registry[obj.id]:
+#                         del regcontent[oid]                    
+                break
+    
+    def register_and_replace(self, obj, replaced, registryname=None):
+        registryname = registryname or obj.__registry__
+        registry = self.registry(registryname)
+        registered_objs = registry[obj.id]
+        for index, registered in enumerate(registered_objs):
+            if registered.classid() == replaced:
+                registry[obj.id][index] = obj
+                self._registered['%s.%s' % (obj.__module__, obj.id)] = obj                
+
+    # dynamic selection methods ###############################################
+    
     def select(self, vobjects, *args, **kwargs):
         """return an instance of the most specific object according
         to parameters
@@ -414,15 +333,8 @@
     def select_object(self, registry, cid, *args, **kwargs):
         """return the most specific component according to the resultset"""
         return self.select(self.registry_objects(registry, cid), *args, **kwargs)
-
-    def object_by_id(self, registry, cid, *args, **kwargs):
-        """return the most specific component according to the resultset"""
-        objects = self[registry][cid]
-        assert len(objects) == 1, objects
-        return objects[0].selected(*args, **kwargs)
     
     # intialization methods ###################################################
-
     
     def register_objects(self, path, force_reload=None):
         if force_reload is None:
@@ -513,22 +425,18 @@
         return True
 
     def load_module(self, module):
+        self._registered = {}
         if hasattr(module, 'cw_register_objects'):
-            self._registered = {}
             module.cw_register_objects(self)
-            registered = self._resigtered
-            del self._registered
-            return registered
         else:
-            registered = {}
             self.info('loading %s', module)
             for objname, obj in vars(module).items():
                 if objname.startswith('_'):
                     continue
-                self.load_ancestors_then_object(module.__name__, registered, obj)
-            return registered
+                self.load_ancestors_then_object(module.__name__, obj)
+        return self._registered
     
-    def load_ancestors_then_object(self, modname, registered, obj):
+    def load_ancestors_then_object(self, modname, obj):
         # skip imported classes
         if getattr(obj, '__module__', None) != modname:
             return
@@ -539,11 +447,11 @@
         except TypeError:
             return
         objname = '%s.%s' % (modname, obj.__name__)
-        if objname in registered:
+        if objname in self._registered:
             return
-        registered[objname] = obj
+        self._registered[objname] = obj
         for parent in obj.__bases__:
-            self.load_ancestors_then_object(modname, registered, parent)
+            self.load_ancestors_then_object(modname, parent)
         self.load_object(obj)
             
     def load_object(self, obj):
@@ -554,6 +462,93 @@
                 raise
             self.exception('vobject %s registration failed: %s', obj, ex)
         
+    # old automatic registration XXX deprecated ###############################
+    
+    def register_vobject_class(self, cls):
+        """handle vobject class registration
+        
+        vobject class with __abstract__ == True in their local dictionnary or
+        with a name starting starting by an underscore are not registered.
+        Also a vobject class needs to have __registry__ and id attributes set
+        to a non empty string to be registered.
+
+        Registration is actually handled by vobject's registerer.
+        """
+        if (cls.__dict__.get('__abstract__') or cls.__name__[0] == '_'
+            or not cls.__registry__ or not cls.id):
+            return
+        regname = cls.__registry__
+        if cls.id in self.config['disable-%s' % regname]:
+            return
+        registry = self._registries.setdefault(regname, {})
+        vobjects = registry.setdefault(cls.id, [])
+        registerer = cls.__registerer__(self, cls)
+        cls = registerer.do_it_yourself(vobjects)
+        if cls:
+            self.register(cls)
+            
+    def unregister_module_vobjects(self, modname):
+        """removes registered objects coming from a given module
+
+        returns a dictionnary classid/class of all classes that will need
+        to be updated after reload (i.e. vobjects referencing classes defined
+        in the <modname> module)
+        """
+        unregistered = {}
+        # browse each registered object
+        for registry, objdict in self.items():
+            for oid, objects in objdict.items():
+                for obj in objects[:]:
+                    objname = obj.classid()
+                    # if the vobject is defined in this module, remove it
+                    if objname.startswith(modname):
+                        unregistered[objname] = obj
+                        objects.remove(obj)
+                        self.debug('unregistering %s in %s registry',
+                                  objname, registry)
+                    # if not, check if the vobject can be found in baseclasses
+                    # (because we also want subclasses to be updated)
+                    else:
+                        if not isinstance(obj, type):
+                            obj = obj.__class__
+                        for baseclass in obj.__bases__:
+                            if hasattr(baseclass, 'classid'):
+                                baseclassid = baseclass.classid()
+                                if baseclassid.startswith(modname):
+                                    unregistered[baseclassid] = baseclass
+                # update oid entry
+                if objects:
+                    objdict[oid] = objects
+                else:
+                    del objdict[oid]
+        return unregistered
+
+    def update_registered_subclasses(self, oldnew_mapping):
+        """updates subclasses of re-registered vobjects
+
+        if baseviews.PrimaryView is changed, baseviews.py will be reloaded
+        automatically and the new version of PrimaryView will be registered.
+        But all existing subclasses must also be notified of this change, and
+        that's what this method does
+
+        :param oldnew_mapping: a dict mapping old version of a class to
+                               the new version
+        """
+        # browse each registered object
+        for objdict in self.values():
+            for objects in objdict.values():
+                for obj in objects:
+                    if not isinstance(obj, type):
+                        obj = obj.__class__
+                    # build new baseclasses tuple
+                    newbases = tuple(oldnew_mapping.get(baseclass, baseclass)
+                                     for baseclass in obj.__bases__)
+                    # update obj's baseclasses tuple (__bases__) if needed
+                    if newbases != obj.__bases__:
+                        self.debug('updating %s.%s base classes',
+                                  obj.__module__, obj.__name__)
+                        obj.__bases__ = newbases
+        
 # init logging 
 set_log_methods(VObject, getLogger('cubicweb'))
 set_log_methods(VRegistry, getLogger('cubicweb.registry'))