dispatcher: refactor hooks binding process
authorDmitry Selyutin <ghostmansd@gmail.com>
Wed, 14 Jun 2023 09:53:06 +0000 (12:53 +0300)
committerDmitry Selyutin <ghostmansd@gmail.com>
Wed, 14 Jun 2023 09:53:18 +0000 (12:53 +0300)
src/mdis/dispatcher.py

index c2c85f483cfb1fcfdf4a54021e90c11a1112345e..94067636b5faf11e798aa6b70869a8c96eae9ce2 100644 (file)
@@ -1,18 +1,27 @@
 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
 
@@ -20,19 +29,12 @@ class DispatcherMeta(type):
             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):