You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
48 lines
1.6 KiB
48 lines
1.6 KiB
2 years ago
|
# coding: utf-8
|
||
|
from functools import singledispatch, update_wrapper
|
||
|
|
||
|
|
||
|
class singledispatchmethod:
|
||
|
"""Single-dispatch generic method descriptor.
|
||
|
|
||
|
Supports wrapping existing descriptors and handles non-descriptor
|
||
|
callables as instance methods.
|
||
|
"""
|
||
|
|
||
|
def __init__(self, func):
|
||
|
if not callable(func) and not hasattr(func, "__get__"):
|
||
|
raise TypeError(f"{func!r} is not callable or a descriptor")
|
||
|
|
||
|
self.dispatcher = singledispatch(func)
|
||
|
self.func = func
|
||
|
|
||
|
def register(self, cls, method=None):
|
||
|
"""generic_method.register(cls, func) -> func
|
||
|
|
||
|
Registers a new implementation for the given *cls* on a *generic_method*.
|
||
|
"""
|
||
|
return self.dispatcher.register(cls, func=method)
|
||
|
|
||
|
def __get__(self, obj, cls=None):
|
||
|
def _method(*args, **kwargs):
|
||
|
if args:
|
||
|
method = self.dispatcher.dispatch(args[0].__class__)
|
||
|
else:
|
||
|
method = self.func
|
||
|
for v in kwargs.values():
|
||
|
if v.__class__ in self.dispatcher.registry:
|
||
|
method = self.dispatcher.dispatch(v.__class__)
|
||
|
if method is not self.func:
|
||
|
break
|
||
|
|
||
|
return method.__get__(obj, cls)(*args, **kwargs)
|
||
|
|
||
|
_method.__isabstractmethod__ = self.__isabstractmethod__
|
||
|
_method.register = self.register
|
||
|
update_wrapper(_method, self.func)
|
||
|
return _method
|
||
|
|
||
|
@property
|
||
|
def __isabstractmethod__(self):
|
||
|
return getattr(self.func, '__isabstractmethod__', False)
|