Динамически обновлять абстрактный метод

Я пытаюсь динамически создать 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

0 ответов

Другие вопросы по тегам