123 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			123 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Python
		
	
	
	
"""
 | 
						|
py lib plugins and plugin call management
 | 
						|
"""
 | 
						|
 | 
						|
import py
 | 
						|
 
 | 
						|
class MultiCall:
 | 
						|
    """ execute a call into multiple python functions/methods.  """
 | 
						|
 | 
						|
    def __init__(self, methods, kwargs, firstresult=False):
 | 
						|
        self.methods = methods[:]
 | 
						|
        self.kwargs = kwargs.copy()
 | 
						|
        self.kwargs['__multicall__'] = self
 | 
						|
        self.results = []
 | 
						|
        self.firstresult = firstresult
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        status = "%d results, %d meths" % (len(self.results), len(self.methods))
 | 
						|
        return "<MultiCall %s, kwargs=%r>" %(status, self.kwargs)
 | 
						|
 | 
						|
    def execute(self):
 | 
						|
        while self.methods:
 | 
						|
            method = self.methods.pop()
 | 
						|
            kwargs = self.getkwargs(method)
 | 
						|
            res = method(**kwargs)
 | 
						|
            if res is not None:
 | 
						|
                self.results.append(res) 
 | 
						|
                if self.firstresult:
 | 
						|
                    return res
 | 
						|
        if not self.firstresult:
 | 
						|
            return self.results 
 | 
						|
 | 
						|
    def getkwargs(self, method):
 | 
						|
        kwargs = {}
 | 
						|
        for argname in varnames(method):
 | 
						|
            try:
 | 
						|
                kwargs[argname] = self.kwargs[argname]
 | 
						|
            except KeyError:
 | 
						|
                pass # might be optional param
 | 
						|
        return kwargs 
 | 
						|
 | 
						|
def varnames(rawcode):
 | 
						|
    ismethod = hasattr(rawcode, 'im_self')
 | 
						|
    rawcode = getattr(rawcode, 'im_func', rawcode)
 | 
						|
    rawcode = getattr(rawcode, 'func_code', rawcode)
 | 
						|
    try:
 | 
						|
        return rawcode.co_varnames[ismethod:]
 | 
						|
    except AttributeError:
 | 
						|
        return ()
 | 
						|
 | 
						|
class Registry:
 | 
						|
    """
 | 
						|
        Manage Plugins: register/unregister call calls to plugins. 
 | 
						|
    """
 | 
						|
    def __init__(self, plugins=None):
 | 
						|
        if plugins is None:
 | 
						|
            plugins = []
 | 
						|
        self._plugins = plugins
 | 
						|
 | 
						|
    def register(self, plugin):
 | 
						|
        assert not isinstance(plugin, str)
 | 
						|
        assert not plugin in self._plugins
 | 
						|
        self._plugins.append(plugin)
 | 
						|
 | 
						|
    def unregister(self, plugin):
 | 
						|
        self._plugins.remove(plugin)
 | 
						|
 | 
						|
    def isregistered(self, plugin):
 | 
						|
        return plugin in self._plugins 
 | 
						|
 | 
						|
    def __iter__(self):
 | 
						|
        return iter(self._plugins)
 | 
						|
 | 
						|
    def listattr(self, attrname, plugins=None, extra=(), reverse=False):
 | 
						|
        l = []
 | 
						|
        if plugins is None:
 | 
						|
            plugins = self._plugins
 | 
						|
        for plugin in list(plugins) + list(extra):
 | 
						|
            try:
 | 
						|
                l.append(getattr(plugin, attrname))
 | 
						|
            except AttributeError:
 | 
						|
                continue 
 | 
						|
        if reverse:
 | 
						|
            l.reverse()
 | 
						|
        return l
 | 
						|
 | 
						|
class HookRelay: 
 | 
						|
    def __init__(self, hookspecs, registry):
 | 
						|
        self._hookspecs = hookspecs
 | 
						|
        self._registry = registry
 | 
						|
        for name, method in vars(hookspecs).items():
 | 
						|
            if name[:1] != "_":
 | 
						|
                setattr(self, name, self._makecall(name))
 | 
						|
 | 
						|
    def _makecall(self, name, extralookup=None):
 | 
						|
        hookspecmethod = getattr(self._hookspecs, name)
 | 
						|
        firstresult = getattr(hookspecmethod, 'firstresult', False)
 | 
						|
        return HookCaller(self, name, firstresult=firstresult,
 | 
						|
            extralookup=extralookup)
 | 
						|
 | 
						|
    def _getmethods(self, name, extralookup=()):
 | 
						|
        return self._registry.listattr(name, extra=extralookup)
 | 
						|
 | 
						|
    def _performcall(self, name, multicall):
 | 
						|
        return multicall.execute()
 | 
						|
        
 | 
						|
class HookCaller:
 | 
						|
    def __init__(self, hookrelay, name, firstresult, extralookup=()):
 | 
						|
        self.hookrelay = hookrelay 
 | 
						|
        self.name = name 
 | 
						|
        self.firstresult = firstresult 
 | 
						|
        self.extralookup = extralookup and [extralookup] or ()
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return "<HookCaller %r>" %(self.name,)
 | 
						|
 | 
						|
    def __call__(self, **kwargs):
 | 
						|
        methods = self.hookrelay._getmethods(self.name, self.extralookup)
 | 
						|
        mc = MultiCall(methods, kwargs, firstresult=self.firstresult)
 | 
						|
        return self.hookrelay._performcall(self.name, mc)
 | 
						|
   
 | 
						|
comregistry = Registry([])
 |