# Path: infi/pyutils/decorators.py
# def wraps(wrapped):
#     """ a convenience function on top of functools.wraps:
# 
#     - adds the original function to the wrapped function as __wrapped__ attribute."""
#     def new_decorator(f):
#         returned = functools.wraps(wrapped)(f)
#         returned.__wrapped__ = wrapped
#         return returned
#     return new_decorator
# 
# Path: infi/pyutils/python_compat.py
# _PYTHON_VERSION = platform.python_version()
# _IS_PYTHON_3 = _PYTHON_VERSION >= '3'
# _IS_BELOW_PYTHON_2_7 = _PYTHON_VERSION < '2.7'
# def get_underlying_function(f):
# def _get_underlying_classmethod_function(f):
#     def create_bound_method(func, self):
#     class TemporaryClass(object):


import itertools
import time
from .decorators import wraps
from .python_compat import iteritems
from logging import getLogger
from types import MethodType, FunctionType
    from inspect import getmembers
            return func(inst, *args, **kwargs)
        try:
            value = inst._cache[key]
        except (KeyError, AttributeError):
            value = func(inst, *args, **kwargs)
            try:
                inst._cache[key] = value
            except AttributeError:
                inst._cache = {}
                inst._cache[key] = value
        return value

    callee.__cached_method__ = True
    callee.__method_id__ = method_id
    return callee


class cached_method_with_custom_cache(object):
    def __init__(self, cache_class=None):
        if cache_class is None:
            cache_class = dict
        self.cache_class = cache_class

    def __call__(self, func):
        """Decorator that caches a method's return value each time it is called.
        If called later with the same arguments, the cached value is returned, and
        not re-evaluated.
        decorated class must implement inst.init_cache() which creates inst._cache dictionary.
        """
        method_id = next(_cached_method_id_allocator)

# Path: infi/pyutils/decorators.py
# def wraps(wrapped):
#     """ a convenience function on top of functools.wraps:
# 
#     - adds the original function to the wrapped function as __wrapped__ attribute."""
#     def new_decorator(f):
#         returned = functools.wraps(wrapped)(f)
#         returned.__wrapped__ = wrapped
#         return returned
#     return new_decorator
# 
# Path: infi/pyutils/python_compat.py
# _PYTHON_VERSION = platform.python_version()
# _IS_PYTHON_3 = _PYTHON_VERSION >= '3'
# _IS_BELOW_PYTHON_2_7 = _PYTHON_VERSION < '2.7'
# def get_underlying_function(f):
# def _get_underlying_classmethod_function(f):
#     def create_bound_method(func, self):
#     class TemporaryClass(object):


# Path: infi/pyutils/lazy.py
import itertools
import time
from .decorators import wraps
from .python_compat import iteritems
from logging import getLogger
from types import MethodType, FunctionType
    from inspect import getmembers

            return func(inst, *args, **kwargs)
        try:
            value = inst._cache[key]
        except (KeyError, AttributeError):
            value = func(inst, *args, **kwargs)
            try:
                inst._cache[key] = value
            except AttributeError:
                inst._cache = {}
                inst._cache[key] = value
        return value

    callee.__cached_method__ = True
    callee.__method_id__ = method_id
    return callee


class cached_method_with_custom_cache(object):
    def __init__(self, cache_class=None):
        if cache_class is None:
            cache_class = dict
        self.cache_class = cache_class

    def __call__(self, func):
        """Decorator that caches a method's return value each time it is called.
        If called later with the same arguments, the cached value is returned, and
        not re-evaluated.
        decorated class must implement inst.init_cache() which creates inst._cache dictionary.
        """
        method_id = next(_cached_method_id_allocator)

        @wraps(func)