From 4c8fed00760505929a88cec4317cae19886be2af Mon Sep 17 00:00:00 2001 From: Dmitry Selyutin Date: Wed, 14 Jun 2023 00:52:38 +0300 Subject: [PATCH] all: refactor hooks binding process --- src/mdis/dispatcher.py | 50 ++++++++++++++++++++++++------------------ src/mdis/visitor.py | 4 +--- src/mdis/walker.py | 4 +--- 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/mdis/dispatcher.py b/src/mdis/dispatcher.py index a40a1c1..be8e42e 100644 --- a/src/mdis/dispatcher.py +++ b/src/mdis/dispatcher.py @@ -1,37 +1,45 @@ +import inspect as _inspect +import operator as _operator + from . import core as _core class DispatcherMeta(type): - @classmethod - def dispatch(metacls, typeid=object): - module = typeid.__module__ - qualname = typeid.__qualname__ - if module == "builtins": - return qualname - return f"{module}.{qualname}".replace(".", "_") - def __new__(metacls, name, bases, ns): hooks = {} for (key, value) in tuple(ns.items()): - if isinstance(value, _core.CallHook): - hook = ns.pop(key) - for typeid in hook.typeids: - site = metacls.dispatch(typeid) - hooks[typeid] = (hook, site) - - for (typeid, (hook, site)) in tuple(hooks.items()): + if not isinstance(value, _core.CallHook): + continue + hook = ns.pop(key) + for typeid in hook.typeids: + if typeid in hooks: + raise ValueError(f"conflicting hook: {typeid!r}") + hooks[typeid] = hook + site = hook.call.__name__ ns[site] = hook return super().__new__(metacls, name, bases, ns) + 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.typeids: + hooks[typeid] = hook + cls.__hooks = hooks + return super().__init__(name, bases, ns) + + def dispatch(cls, typeid=object): + return cls.__hooks.get(typeid) + class Dispatcher(metaclass=DispatcherMeta): def __call__(self, instance): - nil = object() for typeid in instance.__class__.__mro__: - site = self.__class__.dispatch(typeid) - call = getattr(self, site, nil) - if call is not nil: - return call(self, instance) - return getattr(self, self.__class__.dispatch()) + hook = self.__class__.dispatch(typeid=typeid) + if hook is not None: + break + if hook is None: + hook = self.__class__.dispatch() + return hook(dispatcher=self, instance=instance) diff --git a/src/mdis/visitor.py b/src/mdis/visitor.py index bbdc042..2b28433 100644 --- a/src/mdis/visitor.py +++ b/src/mdis/visitor.py @@ -5,9 +5,7 @@ from . import dispatcher as _dispatcher class VisitorMeta(_dispatcher.DispatcherMeta): - @classmethod - def dispatch(metacls, typeid): - return ("visit_" + super().dispatch(typeid)) + pass class Visitor(_dispatcher.Dispatcher, metaclass=VisitorMeta): diff --git a/src/mdis/walker.py b/src/mdis/walker.py index c60d71a..3adb93c 100644 --- a/src/mdis/walker.py +++ b/src/mdis/walker.py @@ -3,9 +3,7 @@ from . import dispatcher as _dispatcher class WalkerMeta(_dispatcher.DispatcherMeta): - @classmethod - def dispatch(metacls, typeid): - return ("walk_" + super().dispatch(typeid)) + pass class Walker(_dispatcher.Dispatcher, metaclass=WalkerMeta): -- 2.30.2