from itertools import chain
from typing import Type


def wrap_for_pyro(cls: Type) -> Type:
    """Create proxy class compatible with pyro.

    Some classes, such as those autogenerated by SWIG, may be difficult
    to expose via `Pyro.api.expose`, because Pyro wants to add attributes
    directly to every class and class method that it exposes.  In some
    cases, this leads to an error like:

    AttributeError: 'method_descriptor' object has no attribute '_pyroExposed'

    This wrapper takes a class and returns a proxy class whose methods can
    all be modified.
    """

    def __init__(self, *args, **kwargs) -> None:
        self._obj = cls(*args, **kwargs)

    def _proxy_method(name):
        def _f(self, *args, **kwargs):
            obj = getattr(self, "_obj")
            method = getattr(obj, name)
            return method(*args, **kwargs)

        _f.__name__ = name
        return _f

    _dict_ = {}
    for k, v in chain(*(c.__dict__.items() for c in reversed(cls.mro()))):
        if callable(v) and not k.startswith("_"):
            _dict_[k] = _proxy_method(k)
            for attr in dir(v):
                if attr.startswith("_pyro"):
                    setattr(_dict_[k], attr, getattr(v, attr))

    _dict_["__init__"] = __init__
    return type(f"{cls.__name__}Proxy", (), _dict_)
