tags:

views:

1647

answers:

5

I feel like I should know this, but I haven't been able to figure it out...

I want to get the name of a method--which happens to be an integration test--from inside it so it can print out some diagnostic text. I can, of course, just hard-code the method's name in the string, but I'd like to make the test a little more DRY if possible.

+2  A: 

I think the traceback module might have what you're looking for. In particular, the extract_stack function looks like it will do the job.

Greg Hewgill
+5  A: 

This decorator makes the name of the method available inside the function by passing it as a keyword argument.

from functools import wraps
def pass_func_name(func):
    "Name of decorated function will be passed as keyword arg _func_name"
    @wraps(func)
    def _pass_name(*args, **kwds):
        kwds['_func_name'] = func.func_name
        return func(*args, **kwds)
    return _pass_name

You would use it this way:

@pass_func_name
def sum(a, b, _func_name):
    print "running function %s" % _func_name
    return a + b

print sum(2, 4)

But maybe you'd want to write what you want directly inside the decorator itself. Then the code is an example of a way to get the function name in a decorator. If you give more details about what you want to do in the function, that requires the name, maybe I can suggest something else.

nosklo
+1 on using a decorator over relying on implementation details
Matthew Trevor
+19  A: 

This seems to be the simplest way using module inspect:

import inspect
def somefunc(a,b,c):
    print "My name is: %s" % inspect.stack()[0][3]

You could generalise this with:

def funcname():
    return inspect.stack()[1][3]

def somefunc(a,b,c):
    print "My name is: %s" % funcname()

Credit to Steffan Lippens which was found via google.

mhawke
Typo: the name should be "Stefaan." The link is old and does not work---try "http://stefaanlippens.net/python_inspect".
Winston C. Yang
+6  A: 
# file "foo.py" 
import sys
import os

def LINE( back = 0 ):
    return sys._getframe( back + 1 ).f_lineno
def FILE( back = 0 ):
    return sys._getframe( back + 1 ).f_code.co_filename
def FUNC( back = 0):
    return sys._getframe( back + 1 ).f_code.co_name
def WHERE( back = 0 ):
    frame = sys._getframe( back + 1 )
    return "%s/%s %s()" % ( os.path.basename( frame.f_code.co_filename ),     
                            frame.f_lineno, frame.f_code.co_name )

def testit():
   print "Here in %s, file %s, line %s" % ( FUNC(), FILE(), LINE() )
   print "WHERE says '%s'" % WHERE()

testit()

Output:

$ python foo.py
Here in testit, file foo.py, line 17
WHERE says 'foo.py/18 testit()'

Use "back = 1" to find info regarding two levels back down the stack, etc.

Kevin Little
+7  A: 

The answers involving introspection via inspect and the like are reasonable. But there may be another option, depending on your situation:

If your integration test is written with the unittest module, then you could use self.id() within your TestCase.

spiv
I just discovered that self.id() works in the unittest setUp() method (it returns the name of the test, not "setUp" itself), unlike the other solutions. Therefore, I'm changing this to the accepted answer for this particular question.
Daryl Spitzer