Динамически обновлять абстрактный метод
Я пытаюсь динамически создать Callable
класс, который оборачивает функцию, которая сохраняет kwargs
используя attrs. Я не пользуюсь functools.partial
поскольку call
Метод будет более сложным.
Проблема в том, что __call__
метод остается абстрактным в реестре после замены на MethodType
обязательный, поэтому я не могу создать экземпляр. Как мне пометить __call__
как уже не абстрактно?
import os
import attr
import types
import typing
import inspect
Data = typing.TypeVar['Data']
PathOrBuffer = typing.Union[typing.AnyStr, os.PathLike, typing.TextIO]
ParserFunction = typing.Callable[[PathOrBuffer], Data]
ParameterMapping = typing.Mapping[str, inspect.Parameter]
AttributeGenerator = typing.Iterable[typing.Tuple[str, attr.Attribute]]
def keyword_attributes(func: typing.Callable) -> AttributeGenerator:
"""
Generate :py:class:`attr.Attribute` from function keyword arguments,
preserving default values.
:param func: function to inspect
:return: (name, instance) iterable
"""
p: ParameterMapping = inspect.signature(func).parameters
for k, v in p.items():
if v.default == v.empty:
continue
yield k, attr.ib(default=v.default)
def parser_factory(func: typing.Callable) -> typing.Type[ParserFunction]:
"""
Factory method for :py:class:`ParserFunction` to initialize default
keyword arguments as instances of :py:class:`attr.Attribute`.
:param func: function to wrap
:return: callable class
"""
def __call__(self, arg: PathOrBuffer) -> Data:
kwargs = attr.asdict(self)
data = func(arg, **kwargs)
return data
def camelize():
for s in func.__name__.split('_'):
yield s.capitalize()
attrs = dict(keyword_attributes(func))
name = ''.join(camelize())
cls = attr.make_class(name, attrs, (ParserFunction,))
cls.__call__ = types.MethodType(__call__, cls)
return cls