2009-02-27 18:18:27 +08:00
|
|
|
"""
|
2009-04-09 08:36:07 +08:00
|
|
|
py lib plugins and plugin call management
|
2009-02-27 18:18:27 +08:00
|
|
|
"""
|
|
|
|
|
|
|
|
import py
|
|
|
|
|
|
|
|
class MultiCall:
|
2009-08-10 05:51:25 +08:00
|
|
|
""" execute a call into multiple python functions/methods. """
|
2009-02-27 18:18:27 +08:00
|
|
|
|
2009-08-10 05:51:25 +08:00
|
|
|
def __init__(self, methods, kwargs, firstresult=False):
|
2009-03-25 06:00:07 +08:00
|
|
|
self.methods = methods[:]
|
2009-02-27 18:18:27 +08:00
|
|
|
self.kwargs = kwargs
|
|
|
|
self.results = []
|
2009-08-10 05:51:25 +08:00
|
|
|
self.firstresult = firstresult
|
2009-02-27 18:18:27 +08:00
|
|
|
|
2009-08-06 20:34:19 +08:00
|
|
|
def __repr__(self):
|
2009-08-10 05:51:25 +08:00
|
|
|
status = "%d results, %d meths" % (len(self.results), len(self.methods))
|
|
|
|
return "<MultiCall %s, kwargs=%r>" %(status, self.kwargs)
|
|
|
|
|
|
|
|
def execute(self):
|
2009-02-27 18:18:27 +08:00
|
|
|
while self.methods:
|
2009-08-10 05:51:25 +08:00
|
|
|
method = self.methods.pop()
|
|
|
|
res = self._call1(method)
|
2009-02-27 18:18:27 +08:00
|
|
|
if res is not None:
|
|
|
|
self.results.append(res)
|
2009-08-10 05:51:25 +08:00
|
|
|
if self.firstresult:
|
|
|
|
break
|
|
|
|
if not self.firstresult:
|
2009-02-27 18:18:27 +08:00
|
|
|
return self.results
|
|
|
|
if self.results:
|
2009-08-10 05:51:25 +08:00
|
|
|
return self.results[-1]
|
|
|
|
|
|
|
|
def _call1(self, method):
|
|
|
|
kwargs = self.kwargs
|
|
|
|
if '__call__' in varnames(method):
|
|
|
|
kwargs = kwargs.copy()
|
|
|
|
kwargs['__call__'] = self
|
|
|
|
return method(**kwargs)
|
|
|
|
|
|
|
|
def varnames(rawcode):
|
|
|
|
rawcode = getattr(rawcode, 'im_func', rawcode)
|
|
|
|
rawcode = getattr(rawcode, 'func_code', rawcode)
|
|
|
|
try:
|
|
|
|
return rawcode.co_varnames
|
|
|
|
except AttributeError:
|
|
|
|
return ()
|
2009-03-25 06:00:07 +08:00
|
|
|
|
2009-04-09 22:03:09 +08:00
|
|
|
class Registry:
|
2009-02-27 18:18:27 +08:00
|
|
|
"""
|
2009-08-10 05:51:25 +08:00
|
|
|
Manage Plugins: register/unregister call calls to plugins.
|
2009-02-27 18:18:27 +08:00
|
|
|
"""
|
|
|
|
def __init__(self, plugins=None):
|
|
|
|
if plugins is None:
|
|
|
|
plugins = []
|
2009-04-09 22:34:53 +08:00
|
|
|
self._plugins = plugins
|
2009-02-27 18:18:27 +08:00
|
|
|
|
|
|
|
def register(self, plugin):
|
|
|
|
assert not isinstance(plugin, str)
|
2009-08-10 05:51:25 +08:00
|
|
|
assert not plugin in self._plugins
|
2009-04-09 22:34:53 +08:00
|
|
|
self._plugins.append(plugin)
|
2009-02-27 18:18:27 +08:00
|
|
|
|
|
|
|
def unregister(self, plugin):
|
2009-04-09 22:34:53 +08:00
|
|
|
self._plugins.remove(plugin)
|
2009-02-27 18:18:27 +08:00
|
|
|
|
|
|
|
def isregistered(self, plugin):
|
2009-04-09 22:34:53 +08:00
|
|
|
return plugin in self._plugins
|
2009-02-27 18:18:27 +08:00
|
|
|
|
2009-04-09 22:21:07 +08:00
|
|
|
def __iter__(self):
|
2009-04-09 22:34:53 +08:00
|
|
|
return iter(self._plugins)
|
2009-04-09 22:21:07 +08:00
|
|
|
|
2009-03-21 23:14:22 +08:00
|
|
|
def listattr(self, attrname, plugins=None, extra=(), reverse=False):
|
2009-02-27 18:18:27 +08:00
|
|
|
l = []
|
|
|
|
if plugins is None:
|
2009-04-09 22:34:53 +08:00
|
|
|
plugins = self._plugins
|
2009-04-14 23:25:59 +08:00
|
|
|
for plugin in list(plugins) + list(extra):
|
2009-02-27 18:18:27 +08:00
|
|
|
try:
|
|
|
|
l.append(getattr(plugin, attrname))
|
|
|
|
except AttributeError:
|
|
|
|
continue
|
2009-03-21 23:14:22 +08:00
|
|
|
if reverse:
|
|
|
|
l.reverse()
|
2009-02-27 18:18:27 +08:00
|
|
|
return l
|
|
|
|
|
2009-08-10 05:51:25 +08:00
|
|
|
class HookRelay:
|
|
|
|
def __init__(self, hookspecs, registry):
|
2009-05-08 00:01:53 +08:00
|
|
|
self._hookspecs = hookspecs
|
2009-08-10 05:51:25 +08:00
|
|
|
self._registry = registry
|
2009-05-08 00:01:53 +08:00
|
|
|
for name, method in vars(hookspecs).items():
|
2009-06-11 20:48:53 +08:00
|
|
|
if name[:1] != "_":
|
2009-08-10 05:51:25 +08:00
|
|
|
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()
|
|
|
|
|
2009-04-08 04:46:50 +08:00
|
|
|
def __repr__(self):
|
2009-08-10 05:51:25 +08:00
|
|
|
return "<HookRelay %r %r>" %(self._hookspecs, self._registry)
|
2009-04-08 04:22:52 +08:00
|
|
|
|
2009-08-10 05:51:25 +08:00
|
|
|
class HookCaller:
|
|
|
|
def __init__(self, hookrelay, name, firstresult, extralookup=()):
|
|
|
|
self.hookrelay = hookrelay
|
2009-04-08 04:22:52 +08:00
|
|
|
self.name = name
|
2009-04-08 23:15:56 +08:00
|
|
|
self.firstresult = firstresult
|
2009-05-12 01:23:57 +08:00
|
|
|
self.extralookup = extralookup and [extralookup] or ()
|
|
|
|
|
2009-04-08 04:22:52 +08:00
|
|
|
def __repr__(self):
|
2009-08-10 05:51:25 +08:00
|
|
|
return "<HookCaller %r firstresult=%s %s>" %(
|
|
|
|
self.name, self.firstresult, self.hookrelay)
|
|
|
|
|
|
|
|
def __call__(self, **kwargs):
|
|
|
|
methods = self.hookrelay._getmethods(self.name,
|
|
|
|
extralookup=self.extralookup)
|
|
|
|
mc = MultiCall(methods, kwargs, firstresult=self.firstresult)
|
|
|
|
return self.hookrelay._performcall(self.name, mc)
|
|
|
|
|
|
|
|
comregistry = Registry([])
|