improve dot schema rendering by associating edge colors and label colors
"""This file contains some basic registerers required by application objectsregistry to handle registration at startup time.A registerer is responsible to tell if an object should be registered accordingto the application's schema or to already registered object:organization: Logilab:copyright: 2006-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr"""__docformat__="restructuredtext en"fromcubicweb.vregistryimportregistererdef_accepts_interfaces(obj):returnsorted(getattr(obj,'accepts_interfaces',()))classyes_registerer(registerer):"""register without any other action"""defdo_it_yourself(self,registered):returnself.vobjectclasspriority_registerer(registerer):"""systematically kick previous registered class and register the wrapped class (based on the fact that directory containing vobjects are loaded from the most generic to the most specific). This is usually for templates or startup views where we want to keep only the latest in the load path """defdo_it_yourself(self,registered):ifregistered:iflen(registered)>1:self.warning('priority_registerer found more than one registered objects ''(registerer monkey patch ?)')forregobjinregistered[:]:self.kick(registered,regobj)returnself.vobjectdefremove_equivalents(self,registered):for_objinregistered[:]:ifself.equivalent(_obj):self.kick(registered,_obj)breakdefremove_all_equivalents(self,registered):for_objinregistered[:]:if_objisself.vobject:continueifself.equivalent(_obj):self.kick(registered,_obj)defequivalent(self,other):raiseNotImplementedError(self,self.vobject)classkick_registerer(registerer):"""systematically kick previous registered class and don't register the wrapped class. This is temporarily used to discard library object registrable but that we don't want to use """defdo_it_yourself(self,registered):ifregistered:self.kick(registered,registered[-1])returnclassaccepts_registerer(priority_registerer):"""register according to the .accepts attribute of the wrapped class, which should be a tuple refering some entity's types * if no type is defined the application'schema, skip the wrapped class * if the class defines a requires attribute, each entity type defined in the requires list must be in the schema * if an object previously registered has equivalent .accepts attribute, kick it out * register """defdo_it_yourself(self,registered):# if object is accepting interface, we have register it now and# remove it latter if no object is implementing accepted interfacesif_accepts_interfaces(self.vobject):returnself.vobjectifnot'Any'inself.vobject.accepts:forertypeinself.vobject.accepts:ifertypeinself.schema:breakelse:self.skip()returnNoneforrequiredingetattr(self.vobject,'requires',()):ifrequirednotinself.schema:self.skip()returnself.remove_equivalents(registered)returnself.vobjectdefequivalent(self,other):if_accepts_interfaces(self.vobject)!=_accepts_interfaces(other):returnFalsetry:newaccepts=list(other.accepts)foretypeinself.vobject.accepts:try:newaccepts.remove(etype)exceptValueError:continueifnewaccepts:other.accepts=tuple(newaccepts)returnFalsereturnTrueexceptAttributeError:returnFalseclassid_registerer(priority_registerer):"""register according to the "id" attribute of the wrapped class, refering to an entity type. * if the type is not Any and is not defined the application'schema, skip the wrapped class * if an object previously registered has the same .id attribute, kick it out * register """defdo_it_yourself(self,registered):etype=self.vobject.idifetype!='Any'andnotself.schema.has_entity(etype):self.skip()returnself.remove_equivalents(registered)returnself.vobjectdefequivalent(self,other):returnother.id==self.vobject.idclassetype_rtype_registerer(registerer):"""registerer handling optional .etype and .rtype attributes.: * if .etype is set and is not an entity type defined in the application schema, skip the wrapped class * if .rtype or .relname is set and is not a relation type defined in the application schema, skip the wrapped class * register """defdo_it_yourself(self,registered):cls=self.vobjectifhasattr(cls,'etype'):ifnotself.schema.has_entity(cls.etype):returnrtype=getattr(cls,'rtype',None)ifrtypeandnotself.schema.has_relation(rtype):returnreturnclsclassetype_rtype_priority_registerer(etype_rtype_registerer):"""add priority behaviour to the etype_rtype_registerer """defdo_it_yourself(self,registered):cls=super(etype_rtype_priority_registerer,self).do_it_yourself(registered)ifcls:registerer=priority_registerer(self.registry,cls)cls=registerer.do_it_yourself(registered)returnclsclassaction_registerer(etype_rtype_registerer):"""'all in one' actions registerer, handling optional .accepts, .etype and .rtype attributes: * if .etype is set and is not an entity type defined in the application schema, skip the wrapped class * if .rtype or .relname is set and is not a relation type defined in the application schema, skip the wrapped class * if .accepts is set, delegate to the accepts_registerer * register """defdo_it_yourself(self,registered):cls=super(action_registerer,self).do_it_yourself(registered)ifhasattr(cls,'accepts'):registerer=accepts_registerer(self.registry,cls)cls=registerer.do_it_yourself(registered)returnclsclassextresources_registerer(priority_registerer):"""'registerer according to a .need_resources attributes which should list necessary resource identifiers for the wrapped object. If one of its resources is missing, don't register """defdo_it_yourself(self,registered):ifnothasattr(self.config,'has_resource'):returnforresourceidinself.vobject.need_resources:ifnotself.config.has_resource(resourceid):returnreturnsuper(extresources_registerer,self).do_it_yourself(registered)__all__=[cls.__name__forclsinglobals().values()ifisinstance(cls,type)andissubclass(cls,registerer)andnotclsisregisterer]