text: from inspect import isclass, ismodule
  
  from .compat import PY2
  from .colls import walk_values
  from .funcs import iffy
  from .strings import cut_prefix
  
  
  __all__ = ['cached_property', 'cached_readonly', 'wrap_prop', 'monkey', 'namespace', 'LazyObject']
  
  
  class cached_property(object):
      """
      Decorator that converts a method with a single self argument into
      a property cached on the instance.
      """
      # NOTE: implementation borrowed from Django.
      # NOTE: we use fget, fset and fdel attributes to mimic @property.
      fset = fdel = None
  
      def __init__(self, fget):
          self.fget = fget
          self.__doc__ = getattr(fget, '__doc__')
  
      def __get__(self, instance, type=None):
          if instance is None:
              return self
          res = instance.__dict__[self.fget.__name__] = self.fget(instance)
          return res
  
  
  class cached_readonly(cached_property):
      """Same as @cached_property, but protected against rewrites."""
      def __set__(self, instance, value):
          raise AttributeError("property is read-only")
  
  
  def wrap_prop(ctx):
      """Wrap a property accessors with a context manager"""
      def decorator(prop):
          class WrapperProp(object):
              def __repr__(self):
                  return repr(prop)
  
              def __get__(self, instance, type=None):
                  if instance is None:
                      return self
  
                  with ctx:
                      return prop.__get__(instance, type)
  
              if hasattr(prop, '__set__'):
                  def __set__(self, name, value):
                      with ctx:
                          return prop.__set__(name, value)
  
              if hasattr(prop, '__del__'):
                  def __del__(self, name):
                      with ctx:
                          return prop.__del__(name)
  
          return WrapperProp()
      return decorator
  
  
  def monkey(cls, name=None):
      """
      Monkey patches class or module by adding to it decorated function.
  
      Anything overwritten could be accessed via .original attribute of decorated object.
      """
      assert isclass(cls) or ismodule(cls), "Attempting to monkey patch non-class and non-module"
  
      def decorator(value):
          func = getattr(value, 'fget', value) # Support properties
          func_name = name or cut_prefix(func.__name__, '%s__' % cls.__name__)
  
          func.__name__ = func_name
          func.original = getattr(cls, func_name, None)
  
          setattr(cls, func_name, value)
          return value
      return decorator
  
  
  # TODO: monkey_mix()?
  
  
  class namespace_meta(type):
      def __new__(cls, name, bases, attrs):
          attrs = walk_values(iffy(callable, staticmethod), attrs)
          return super(namespace_meta, cls).__new__(cls, name, bases, attrs)
  
  class namespace(object):
      """A base class that prevents its member functions turning into methods."""
      if PY2:
          __metaclass__ = namespace_meta
  
  
  class LazyObject(object):
      """
      A simplistic lazy init object.
      Rewrites itself when any attribute is accessed.
      """
      # NOTE: we can add lots of magic methods here to intercept on more events,
      #       this is postponed. As well as metaclass to support isinstance() check.
      def __init__(self, init):
          self.__dict__['_init'] = init
  
      def _setup(self):
          obj = self._init()
          object.__setattr__(self, '__class__', obj.__class__)
          object.__setattr__(self, '__dict__', obj.__dict__)
  
      def __getattr__(self, name):
          self._setup()
          return getattr(self, name)
  
      def __setattr__(self, name, value):
          self._setup()
          return setattr(self, name, value)
  