3
import functools
import logging
def logDeprecated( msg=None, *args, **kwargs ):
    """Log a message at level 'WARNING'

    Args:
        msg=None : (str)
            The message you wish to log.
            If no msg is passed, default to 'This function has been deprecated.'
            All other args are passed directly to logging.Logger.log().

    Keyword Args:
        category : (str)
            The category for the message to be logged.  If not
            specified, then an appropriate category will be
            determined based on the calling context.

        All other keyword args are passed directly to logging.Logger.log().

    Raises:
        n/a

    Returns:
        n/a

    """
    if not msg:
        msg = "This function has been deprecated."

    # Make sure category is stripped from kwargs before passing to log().
    cat = kwargs.pop('category', None)
    if not cat:
        cat = _getLoggingCategory()
    cat = "{0}.DEPRECATED".format(cat)

    logging.getLogger( category=cat ).log( logging.WARNING, msg, *args, **kwargs )

def decoratedLogDeprecated(func):
    def thisFunc(*args, **kwargs):
        func(*args, **kwargs)
        logDeprecated()
    return wraps(func)(thisFunc)

@decoratedLogDeprecated
def somefunc():
    print "This used to work"

def main():
    somefunc()

if __name__ == 'main':
    main()

The line number that is getting logged is the line number in main. When in actuality, it should be reporting the line number in the actual function.

Is there any way to use a decorator to inject that function into the decorated function? All the help would be greatly appreciated.

Stephen Lu
  • 314
  • 1
  • 9
  • 2
    Do you care to share how `logDeprecated` is implemented? If you're using frames, you need to go one level deeper. – JBernardo Nov 02 '12 at 01:40
  • In your example, do you expect number 8 (function definition) or 12 (function call) to be printed out? – Yevgen Yampolskiy Nov 02 '12 at 01:57
  • I added a bit more to my example so the line numbers would be different. But in this case, I would expect number 46 to be the expected line number. However, in this example, the line number I would get is 49 inside the main function – Stephen Lu Nov 02 '12 at 02:01
  • You should accept the answers that work for you (click on the green check mark by the answer that works best). – Ethan Furman Sep 05 '13 at 15:57

1 Answers1

4

Here is how you can get both definition line number and call line number

from functools import wraps
def decoratedLogDeprecated(func):
    import inspect
    l = inspect.stack(1)[1][2]
    def thisFunc(*args, **kwargs):
        print "Defined at line", l
        func(*args, **kwargs)
        logDeprecated()

    return wraps(func)(thisFunc)

def logDeprecated():
    import inspect
    print "Called at line", inspect.stack(2)[2][2]

@decoratedLogDeprecated
def f():
    pass

@decoratedLogDeprecated
def g():
    pass

f()
g()
Yevgen Yampolskiy
  • 7,022
  • 3
  • 26
  • 23
  • Ah, clever--this looks at the stack when the decorator first runs, rather than when the wrapper is called, to find the declaration line. Nicely done. – Jamey Sharp Nov 02 '12 at 02:07