1 import collections
as _collections
2 import inspect
as _inspect
7 def __init__(self
, *typeids
):
9 if not callable(typeid
):
10 raise ValueError(typeid
)
11 self
.__typeids
= typeids
12 return super().__init
__()
15 yield from self
.__typeids
19 for typeid
in self
.__typeids
:
20 name
= typeid
.__qualname
__
21 module
= typeid
.__module
__
22 if module
not in ("builtins",):
23 name
= f
"{module}.{name}"
25 return f
"<{', '.join(names)}>"
27 def __call__(self
, call
):
28 class ConcreteHook(Hook
):
29 def __call__(self
, dispatcher
, instance
):
30 return call(self
=dispatcher
, instance
=instance
)
32 return ConcreteHook(*tuple(self
))
35 class DispatcherMeta(type):
38 def __new__(metacls
, name
, bases
, ns
):
40 ishook
= lambda member
: isinstance(member
, Hook
)
42 for basecls
in reversed(bases
):
43 members
= _inspect
.getmembers(basecls
, predicate
=ishook
)
44 for (_
, hook
) in members
:
45 hooks
.update(dict.fromkeys(hook
, hook
))
47 conflicts
= _collections
.defaultdict(list)
48 for (key
, value
) in tuple(ns
.items()):
54 conflicts
[typeid
].append(key
)
57 for (typeid
, keys
) in conflicts
.items():
59 raise ValueError(f
"dispatch conflict: {keys!r}")
61 ns
["__hooks__"] = _types
.MappingProxyType(hooks
)
63 return super().__new
__(metacls
, name
, bases
, ns
)
65 def dispatch(cls
, typeid
=object):
66 hook
= cls
.__hooks
__.get(typeid
)
69 for (checker
, hook
) in cls
.__hooks
__.items():
70 if not isinstance(checker
, type) and checker(typeid
):
75 class Dispatcher(metaclass
=DispatcherMeta
):
76 def __call__(self
, instance
):
77 for typeid
in instance
.__class
__.__mro
__:
78 hook
= self
.__class
__.dispatch(typeid
=typeid
)
82 hook
= self
.__class
__.dispatch()
83 return hook(dispatcher
=self
, instance
=instance
)
86 def dispatch_object(self
, instance
):
87 raise NotImplementedError()