""" error.py

Module for logging errors
"""
__copyright__ = "Copyright (c) 2002-2005 Free Software Foundation, Inc."
__license__ = """ GNU General Public License

This program is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA. """

import sys
import traceback
import pprint
from StringIO import StringIO

stream = sys.stderr

def log(*args):
    caller = traceback.extract_stack()[-2]
    _log(caller, *args)

def _log(caller = None, *args):
    if caller is None:
        caller = traceback.extract_stack()[-2]
    try:
        cf = caller[0][caller[0].rindex("/")+1:]
    except:
        cf = caller[0]
    stream.write("%s:%d:%s: " % (cf, caller[1], caller[2]))
    for a in args:
        if type(a) is not type(''):
            a = repr(a)
        stream.write(a)
    stream.write("\n")

def logtb(*args):
    _log(traceback.extract_stack()[-2], *args)
    l = traceback.format_list(traceback.extract_stack()[:-1])
    for e in l:
        stream.write(e)

def logparam(locals, *vars):
    logargs = []
    for v in vars:
        logargs.append(v + ": " + str(locals[v]))
    _log(traceback.extract_stack()[-2], ", ".join(logargs))
    
def logpparam(locals, *vars):
    logargs = []
    for v in vars:
        sio = StringIO()
        pprint.pprint(locals[v], sio)
        logargs.append(v + ": " + sio.getvalue())
        sio.close()
    _log(traceback.extract_stack()[-2], "".join(logargs))


depth = 0
def incr_depth():
    global depth
    depth += 1
def decr_depth():
    global depth
    depth -= 1
def get_indent(): return " " * depth

def debug_around(f):
    caller = traceback.extract_stack()[-2]
    
    def f2(*args, **kwargs):
        def maybe_str(o):
            if isinstance(o, str):
                return repr(o)
            return str(o)
        indent = get_indent()
        _log(caller, "%sEntering " % indent, f.__name__)
        argstr = ", ".join([maybe_str(a) for a in args])
        if len(kwargs) > 0:
            argstr += ", " + ", ".join(
                ["%s: %s" % (maybe_str(k), maybe_str(v))
                 for k, v in kwargs.items()])
        _log(caller, "%sArgs: (" % indent, argstr, ")")
        incr_depth()
        r = None
        try:
            r = f(*args, **kwargs)
        finally:
            decr_depth()
            _log(caller, "%sReturning %s from %s" % (
                indent, str(r), f.__name__))
            return r


    return f2

# Originally by Bryn Keller
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52215
def log_exc(message):
    """
    Print the usual traceback information, followed by a listing of all the
    local variables in each frame.
    """
    _log(traceback.extract_stack()[-2], message)
    tb = sys.exc_info()[2]
    while 1:
        if not tb.tb_next:
            break
        tb = tb.tb_next
    stack = []
    f = tb.tb_frame
    while f:
        stack.append(f)
        f = f.f_back
    stack.reverse()
    traceback.print_exc()
    print >>stream, "Locals by frame, innermost last"
    for frame in stack:
        print >>stream
        print >>stream, "Frame %s in %s at line %s" % (
            frame.f_code.co_name, frame.f_code.co_filename,
            frame.f_lineno)
        for key, value in frame.f_locals.items():
            print >>stream, "\t%20s = " % key,
            #We have to be careful not to cause a new error in our error
            #printer! Calling str() on an unknown object could cause an
            #error we don't want.
            try:                   
                print >>stream, value
            except:
                print >>stream, "<ERROR WHILE PRINTING VALUE>"
