import collections as _collections
import inspect as _inspect
-import operator as _operator
+import types as _types
from . import core as _core
class DispatcherMeta(type):
def __new__(metacls, name, bases, ns):
+ hooks = {}
+ ishook = lambda member: isinstance(member, _core.CallHook)
+
+ for basecls in reversed(bases):
+ members = _inspect.getmembers(basecls, predicate=ishook)
+ for (_, hook) in members:
+ hooks.update(dict.fromkeys(hook, hook))
+
conflicts = _collections.defaultdict(list)
for (key, value) in tuple(ns.items()):
- if not isinstance(value, _core.CallHook):
+ if not ishook(value):
continue
hook = value
for typeid in hook:
+ hooks[typeid] = hook
conflicts[typeid].append(key)
ns[key] = hook
if len(keys) > 1:
raise ValueError(f"dispatch conflict: {keys!r}")
- return super().__new__(metacls, name, bases, ns)
+ ns["__hooks__"] = _types.MappingProxyType(hooks)
- def __init__(cls, name, bases, ns):
- hooks = {}
- for hook in map(_operator.itemgetter(1), _inspect.getmembers(cls,
- predicate=lambda member: isinstance(member, _core.CallHook))):
- for typeid in hook:
- hooks[typeid] = hook
- cls.__hooks = hooks
- return super().__init__(name, bases, ns)
+ return super().__new__(metacls, name, bases, ns)
def dispatch(cls, typeid=object):
- return cls.__hooks.get(typeid)
+ return cls.__hooks__.get(typeid)
class Dispatcher(metaclass=DispatcherMeta):