Armed with a text editor

mu's views on program and recipe! design

def trace(module):
    from inspect import getmembers, isfunction, isclass, getmodule, classify_class_attrs
    import inspect
    def maketrace(name, func):
        def _trace(*args, **kwargs):
            print>>trace.fobj, ">>%*s%s(%s)" % (trace.indent, "",
                    name, ", ".join(map(repr, args) +
                ["%s=%r" % (k,v) for (k,v) in kwargs.iteritems()]))
            trace.indent += 2
            val = Exception
            try:
                val = func(*args, **kwargs)
            finally:
                trace.indent -= 2
                print>>trace.fobj,"<<%*s%s: %r" % (trace.indent, "", name, val)
            return val

        return _trace

    for name, func in getmembers(module, isfunction):
        if getmodule(func) != module: continue
        if name.startswith('__') and name.endswith('__'): continue
        print 'replacing', module.__name__, name
        setattr(module, name, maketrace(name, func))

    for name, cls in getmembers(module, isclass):
        if getmodule(cls) != module: continue
        print 'checking out class', name
        for name, kind, cls, obj in list(classify_class_attrs(cls)):
            if name.startswith('__') and name.endswith('__'): continue
            if name in ('items', 'keys', 'values'): continue
            if cls is list: continue
            if kind == 'class method':
                print 'replacing classmethod', name
                setattr(cls, name, staticmethod(maketrace(name, getattr(cls, name))))
            elif kind == 'static method':
                print 'replacing staticmethod', name
                setattr(cls, name, staticmethod(maketrace(name, getattr(cls, name))))
            elif kind == 'property2':
                print 'replacing property', name
                setattr(cls, name, property(
                    obj.fget and maketrace('get_' + name, obj.fget),
                    obj.fset and maketrace('set_' + name, obj.fset),
                    obj.fdel and maketrace('del_' + name, obj.fdel),
                    obj.__doc__))
            elif kind == 'method':
                print 'replacing method', name
                setattr(cls, name, maketrace(name, obj))

    if not hasattr(trace, 'fobj'):
        trace.indent = 0
        trace.fobj = open("tracelog", "w")

        class tracefile(file):
            def read(self, *size):
                print>>trace.fobj,">>%*sfile#read%r at %d" % (trace.indent, "", size, self.tell())
                trace.indent += 2
                val = Exception
                try:
                    val = super(tracefile, self).read(*size)
                finally:
                    trace.indent -= 2
                    print>>trace.fobj,"<<%*sfile#read: %r" % (trace.indent, "", val[:15])
                return val

            def write(self, *data):
                print>>trace.fobj,">>%*sfile#write%r at %d" % (trace.indent, "", data[0][:15], self.tell())
                trace.indent += 2
                val = Exception
                try:
                    val = super(tracefile, self).write(*data)
                finally:
                    trace.indent -= 2
                    print>>trace.fobj,"<<%*sfile#write: %r" % (trace.indent, "", val)
                return val
        import __builtin__
        __builtin__.file = __builtin__.open = tracefile