vregistry.py
branchtls-sprint
changeset 712 ce49e3885453
parent 711 f758b86cf484
child 714 39a2a6673171
equal deleted inserted replaced
711:f758b86cf484 712:ce49e3885453
    27 
    27 
    28 import sys
    28 import sys
    29 from os import listdir, stat
    29 from os import listdir, stat
    30 from os.path import dirname, join, realpath, split, isdir
    30 from os.path import dirname, join, realpath, split, isdir
    31 from logging import getLogger
    31 from logging import getLogger
       
    32 import types
    32 
    33 
    33 from cubicweb import CW_SOFTWARE_ROOT, set_log_methods
    34 from cubicweb import CW_SOFTWARE_ROOT, set_log_methods
    34 from cubicweb import RegistryNotFound, ObjectNotFound, NoSelectableObject
    35 from cubicweb import RegistryNotFound, ObjectNotFound, NoSelectableObject
    35 
    36 
    36 
    37 
    86     rset may be None. If not, row and col arguments may be optionally
    87     rset may be None. If not, row and col arguments may be optionally
    87     given if the registry is scoring a given row or a given cell of
    88     given if the registry is scoring a given row or a given cell of
    88     the result set (both row and col are int if provided).
    89     the result set (both row and col are int if provided).
    89     """    
    90     """    
    90     raise NotImplementedError(cls)
    91     raise NotImplementedError(cls)
    91 
       
    92 
       
    93 class autoselectors(type):
       
    94     """implements __selectors__ / __select__ compatibility layer so that:
       
    95 
       
    96     __select__ = chainall(classmethod(A, B, C))
       
    97 
       
    98     can be replaced by something like:
       
    99     
       
   100     __selectors__ = (A, B, C)
       
   101     """
       
   102     def __new__(mcs, name, bases, classdict):
       
   103         if '__select__' in classdict and '__selectors__' in classdict:
       
   104             raise TypeError("__select__ and __selectors__ "
       
   105                             "can't be used together")
       
   106         if '__select__' not in classdict and '__selectors__' in classdict:
       
   107             selectors = classdict['__selectors__']
       
   108             if not isinstance(selectors, (tuple, list)):
       
   109                 selectors = (selectors,)
       
   110             if len(selectors) > 1:
       
   111                 classdict['__select__'] = classmethod(chainall(*selectors))
       
   112             else:
       
   113                 classdict['__select__'] = classmethod(selectors[0])
       
   114         return super(autoselectors, mcs).__new__(mcs, name, bases, classdict)
       
   115 
       
   116     def __setattr__(self, attr, value):
       
   117         if attr == '__selectors__':
       
   118             self.__select__ = classmethod(chainall(*value))
       
   119         super(autoselectors, self).__setattr__(attr, value)
       
   120 
    92 
   121 
    93 
   122 class VObject(object):
    94 class VObject(object):
   123     """visual object, use to be handled somehow by the visual components
    95     """visual object, use to be handled somehow by the visual components
   124     registry.
    96     registry.
   140       (__select__ and __selectors__ are mutually exclusive)
   112       (__select__ and __selectors__ are mutually exclusive)
   141       
   113       
   142     Moreover, the `__abstract__` attribute may be set to True to indicate
   114     Moreover, the `__abstract__` attribute may be set to True to indicate
   143     that a vobject is abstract and should not be registered
   115     that a vobject is abstract and should not be registered
   144     """
   116     """
   145     __metaclass__ = autoselectors
       
   146     # necessary attributes to interact with the registry
   117     # necessary attributes to interact with the registry
   147     id = None
   118     id = None
   148     __registry__ = None
   119     __registry__ = None
   149     __registerer__ = None
   120     __registerer__ = None
   150     __select__ = None
   121     __select__ = None
   155 
   126 
   156         It must return the  object that will be actually registered (this
   127         It must return the  object that will be actually registered (this
   157         may be the right hook to create an instance for example). By
   128         may be the right hook to create an instance for example). By
   158         default the vobject is returned without any transformation.
   129         default the vobject is returned without any transformation.
   159         """
   130         """
       
   131         cls.__select__ = cls.build___select__()
   160         return cls
   132         return cls
   161 
   133 
   162     @classmethod
   134     @classmethod
   163     def selected(cls, *args, **kwargs):
   135     def selected(cls, *args, **kwargs):
   164         """called by the registry when the vobject has been selected.
   136         """called by the registry when the vobject has been selected.
   172 
   144 
   173     @classmethod
   145     @classmethod
   174     def classid(cls):
   146     def classid(cls):
   175         """returns a unique identifier for the vobject"""
   147         """returns a unique identifier for the vobject"""
   176         return '%s.%s' % (cls.__module__, cls.__name__)
   148         return '%s.%s' % (cls.__module__, cls.__name__)
       
   149 
       
   150     @classmethod
       
   151     def build___select__(cls):
       
   152         classdict = cls.__dict__
       
   153         if '__select__' in classdict and '__selectors__' in classdict:
       
   154             raise TypeError("__select__ and __selectors__ can't be used together")
       
   155         if '__selectors__' in classdict:
       
   156             # case where __selectors__ is defined locally (but __select__
       
   157             # is in a parent class)
       
   158             selectors = classdict['__selectors__']
       
   159             if len(selectors) == 1:
       
   160                 # micro optimization: don't bother with AndSelector if there's
       
   161                 # only one selector
       
   162                 return _instantiate_selector(selectors[0])
       
   163             return AndSelector(_instantiate_selector(selector)
       
   164                                for selector in selectors)
       
   165         return cls.__select__
   177 
   166 
   178 
   167 
   179 class VRegistry(object):
   168 class VRegistry(object):
   180     """class responsible to register, propose and select the various
   169     """class responsible to register, propose and select the various
   181     elements used to build the web interface. Currently, we have templates,
   170     elements used to build the web interface. Currently, we have templates,
   663         
   652         
   664     """
   653     """
   665     return type(selector_func.__name__, (Selector,),
   654     return type(selector_func.__name__, (Selector,),
   666                 {'__call__': lambda self, *args: selector_func(*args)})
   655                 {'__call__': lambda self, *args: selector_func(*args)})
   667 
   656 
       
   657 def _instantiate_selector(selector):
       
   658     """ensures `selector` is a `Selector` instance
       
   659     
       
   660     NOTE: This should only be used locally in build___select__()
       
   661     """
       
   662     if isinstance(selector, types.FunctionType):
       
   663         return objectify_selector(selector)()
       
   664     if issubclass(selector, Selector):
       
   665         return selector()
       
   666     return selector
       
   667 
   668 
   668 
   669 class AndSelector(MultiSelector):
   669 class AndSelector(MultiSelector):
   670     """and-chained selectors (formerly known as chainall)"""
   670     """and-chained selectors (formerly known as chainall)"""
   671     def __call__(self, cls, *args, **kwargs):
   671     def __call__(self, cls, *args, **kwargs):
   672         score = 0
   672         score = 0