def lazy(func, *resultclasses):
@total_ordering<EOL>class __proxy__(Promise):<EOL><INDENT>"""<STR_LIT>"""<EOL>__prepared = False<EOL>def __init__(self, args, kw):<EOL><INDENT>self.__args = args<EOL>self.__kw = kw<EOL>if not self.__prepared:<EOL><INDENT>self.__prepare_class__()<EOL><DEDENT>self.__prepared = True<EOL><DEDENT>def __reduce__(self):<EOL><INDENT>return (<EOL>_lazy_proxy_unpickle,<EOL>(func, self.__args, self.__kw) + resultclasses<EOL>)<EOL><DEDENT>def __repr__(self):<EOL><INDENT>return repr(self.__cast())<EOL><DEDENT>@classmethod<EOL>def __prepare_class__(cls):<EOL><INDENT>for resultclass in resultclasses:<EOL><INDENT>for type_ in resultclass.mro():<EOL><INDENT>for method_name in type_.__dict__.keys():<EOL><INDENT>if hasattr(cls, method_name):<EOL><INDENT>continue<EOL><DEDENT>meth = cls.__promise__(method_name)<EOL>setattr(cls, method_name, meth)<EOL><DEDENT><DEDENT><DEDENT>cls._delegate_bytes = bytes in resultclasses<EOL>cls._delegate_text = str in resultclasses<EOL>assert not (cls._delegate_bytes and cls._delegate_text), (<EOL>"<STR_LIT>")<EOL>if cls._delegate_text:<EOL><INDENT>cls.__str__ = cls.__text_cast<EOL><DEDENT>elif cls._delegate_bytes:<EOL><INDENT>cls.__bytes__ = cls.__bytes_cast<EOL><DEDENT><DEDENT>@classmethod<EOL>def __promise__(cls, method_name):<EOL><INDENT>def __wrapper__(self, *args, **kw):<EOL><INDENT>res = func(*self.__args, **self.__kw)<EOL>return getattr(res, method_name)(*args, **kw)<EOL><DEDENT>return __wrapper__<EOL><DEDENT>def __text_cast(self):<EOL><INDENT>return func(*self.__args, **self.__kw)<EOL><DEDENT>def __bytes_cast(self):<EOL><INDENT>return bytes(func(*self.__args, **self.__kw))<EOL><DEDENT>def __bytes_cast_encoded(self):<EOL><INDENT>return func(*self.__args, **self.__kw).encode()<EOL><DEDENT>def __cast(self):<EOL><INDENT>if self._delegate_bytes:<EOL><INDENT>return self.__bytes_cast()<EOL><DEDENT>elif self._delegate_text:<EOL><INDENT>return self.__text_cast()<EOL><DEDENT>else:<EOL><INDENT>return func(*self.__args, **self.__kw)<EOL><DEDENT><DEDENT>def __str__(self):<EOL><INDENT>return str(self.__cast())<EOL><DEDENT>def __eq__(self, other):<EOL><INDENT>if isinstance(other, Promise):<EOL><INDENT>other = other.__cast()<EOL><DEDENT>return self.__cast() == other<EOL><DEDENT>def __lt__(self, other):<EOL><INDENT>if isinstance(other, Promise):<EOL><INDENT>other = other.__cast()<EOL><DEDENT>return self.__cast() < other<EOL><DEDENT>def __hash__(self):<EOL><INDENT>return hash(self.__cast())<EOL><DEDENT>def __mod__(self, rhs):<EOL><INDENT>if self._delegate_text:<EOL><INDENT>return str(self) % rhs<EOL><DEDENT>return self.__cast() % rhs<EOL><DEDENT>def __deepcopy__(self, memo):<EOL><INDENT>memo[id(self)] = self<EOL>return self<EOL><DEDENT><DEDENT>@wraps(func)<EOL>def __wrapper__(*args, **kw):<EOL><INDENT>return __proxy__(args, kw)<EOL><DEDENT>return __wrapper__<EOL>
Turn any callable into a lazy evaluated callable. result classes or types
is required -- at least one is needed so that the automatic forcing of
the lazy evaluation code is triggered. Results are not memoized; the
function is evaluated on every access.