""" Object proxy

    Getting into the middle between some application code and e.g.
    some library module by intercepting all calls and logging all results.
"""
from types import *

class Proxy(object):
    def __init__(self, wrapped):
        # remember the object we wrap:
        self.wrapped = wrapped
        # for prettier logging - find out name of object:
        if hasattr(wrapped, '__name__'):
            self.name = wrapped.__name__
        elif hasattr(wrapped, '__class__'):
            self.name = wrapped.__class__
        else:
            self.name = 'Unknown'

    def log(self, format, *args):
        print "Proxy: %s." % self.name + format % args

    def need_proxy(self, obj):
        """ checks if we need a proxy object """
        # XXX is there a better way to check if we want to proxy?
        if isinstance(obj, (
            NoneType,
            TypeType,
            IntType,
            LongType,
            FloatType,
            BooleanType,
            ComplexType,
            StringTypes,
            BufferType,
            TupleType,
            ListType,
            DictType,
            DictProxyType,
            GeneratorType,
            BuiltinFunctionType,
            BuiltinMethodType,
            ClassType,
            UnboundMethodType,
            FileType,
            XRangeType,
            SliceType,
            EllipsisType,
            NotImplementedType,
            )):
            # it is something simple, we don't need a proxy
            return False

        if isinstance(obj, (
            FunctionType,
            InstanceType,
            MethodType,
            ModuleType,
            )):
            # something complex, like functions, class instances, modules, ...
            return True

        # something not listed above
        return False

    def __getattr__(self, name):
        wrapped = getattr(self.wrapped, name)
        if self.need_proxy(wrapped):
            return Proxy(wrapped)
        else:
            self.log("%s -> %r", name, wrapped)
            return wrapped

    def __call__(self, *args, **kw):
        result = self.wrapped(*args, **kw)
        self.log("call(%r %r) --> %r", args, kw, result)
        if self.need_proxy(result):
            return Proxy(result)
        else:
            return result

# testing (all output generated comes from the proxy):
if __name__ == '__main__':
    import sys
    import ldap
    ldap = sys.modules['ldap'] = Proxy(sys.modules['ldap'])

    ldap.PORT
    lo = ldap.initialize("ldap://localhost")
    lo.timelimit


