#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

import logging

def HelpDebugDecorator(logLevel):
    """Returns a function object that will properly decorate a function."""

    # Note that logLevel used in the nested function HelpDebug
    # comes from this scope.

    def WrapWithHelpDebug(func):
        """Returns a function object that transparently wraps the parameter
        with the HelpDebug function"""

        # The def statement actually defines a function object and binds
        # it to a name.  Since it is nested in this function, the def
        # statement isn't evaluated until
        def HelpDebug(*args, **keyargs):
            "Assist with debugging a function."
            # The func argument is a Pythong function object
            # arg is the positional arguments that follow the
            # first parameter, and keyargs has the keyword arguments.
            try:
                # The name "func" comes from the outer scope, WrapWithHelpDebug
                returnValue = func(*args, **keyargs)
                return returnValue
            except SystemExit:
                raise  # Reraise the system exit exception
            except Exception, error:
                from logging import log
                from sys import exc_info
                import pdb

                log(logLevel, "Caught Exception: %s", error)
                # Start the debugger at the place where the
                # exception occurred
                pdb.post_mortem(exc_info()[2])
            return  # Nothing to return when an exception occurred

        # Back in the WrapWithHelpDebug scope.
        # HelpDebug is now a function objected defined in this scope.
        return HelpDebug
    # Back in the HelpDebugDecorate scope.
    # Return the WrapWithHelpDebug function object
    return WrapWithHelpDebug

@HelpDebugDecorator(logging.ERROR)
def DivXY(x, y):
    "Divides X by Y"
    return x / y
#DivXY = WrapWithHelpDebug(DivXY, logging.DEBUG)

# Debug the following calls
DivXY(5.0, 2.1)  # This will succeed
DivXY(10.0, 0.0) # Causes a ZeroDivisionError exception

