__FILE__ and __LINE__ in Python

Sunday 3 October 2004

In C++, if you want your code to talk about itself, you often use the predefined magic macros __FILE__ and __LINE__ to get the filename and line number of the current line:

// Use this macro if you can't write the code yet.
#define NOTYET()    NoCodeYet(__FILE__, __LINE__);

void NoCodeYet(const char * pszFile, int nLine)
{
    fprintf(stderr, "No code yet at %s(%d)\n", pszFile, nLine);
}

//...

void ComplicatedFunctionFromTheFuture()
{
    NOTYET()       // I'll get to this later.
}

This provides a convenient way to leave breadcrumbs that will direct you to the spot in the code later.

How to do it in Python? With help from the Python Cookbook, I created this. It uses scary functions from sys (_getframe has a leading underscore and is described as "for internal and specialized uses only"):

def _functionId(nFramesUp):
    """ Create a string naming the function n frames up on the stack.
    """
    co = sys._getframe(nFramesUp+1).f_code
    return "%s (%s @ %d)" % (co.co_name, co.co_filename, co.co_firstlineno)

def notYetImplemented():
    """ Call this function to indicate that a method isn't implemented yet.
    """
    raise Exception("Not yet implemented: %s" % _functionId(1))

#...

def complicatedFunctionFromTheFuture():
    notYetImplemented()

This goes one further than the C++ technique, by providing the function name as well as the file and line.

Comments

[gravatar]
Remco Boerma 9:44 AM on 3 Oct 2004

I've used the following code. .
Using one less f_back, you see where the routines was called from. . .

Using 2 f_back's, and then using 1:

>>> lineheretest.linehere()
"@[file: ...ework\\interact.py, line 257 in 'runcode']"
>>> lineheretest.linehere()
"@[file: , line 1 in '?']"

note: it might also be usefull to some people to use a similar trick to get the callers caller's variables:

def parentVars():
frame = inspect.currentframe().f_back.f_back
return frame.f_globals, frame.f_locals

import inspect
def linehere():
"""Give linenumer, file, and functionname of the callers,
caller.. Uses the standard module inspect
"""
info = inspect.getframeinfo(inspect.currentframe().f_back.f_back)[0:3]
printInfo=[]
# Break long filenames
if len(info[0])>20:
printInfo.append('...'+info[0][-17:])
else:
printInfo.append(info[0])
printInfo.extend(info[1:3])
return '@[file: %s, line %s in %r]'% tuple(printInfo)

Get the source with correct indention by running:

import base64,zlib;f=file("lineheretest.py",'wb');f.write(zlib.decompress(base64.decodestring("""
eNp9UcFKxDAQvS/sPwyV0hRr6K4HobAiXsQP8FSKxHayGzadlkkqfr5pm13RgzkN7715b2Zi+nFg
D4bciK3fbjrUYA3hCRlFXm03EF6SJC/mExeCph65AG0sFqCoAz1R681ApHqEQYM/IbTKWmRXQHyr
zYpKCW8O3aJzPjgo7qAfusnizxgxdS0M6QEOF1Ie0WsOYTMsLmA7MSOthMilfv9Q7Tmvy+q+WU1G
NuRfQ8uhjsgNPDOqM9iBjss+8wYuRoYrIIk5oi6b/HFfxlP8spJqHJE6kUkps9soru92D1WTr3K0
Dv/rvAT8mVHil7/Su7BDFDD6iQmyp3qet4I0nHj+lFCE80DKTZaCn0aL4uoVWr8BAcCTEQ==
""")));f.close()

(source to create this data can be found on: gwork.blogspot.com

[gravatar]
Kent 12:32 PM on 3 Oct 2004

Why not just raise NotImplementedError? The stack trace will show the file, line and function with the error.

[gravatar]
Ned Batchelder 12:43 PM on 3 Oct 2004

In this case, I could have simply raised an exception. I used notYetImplemented() as an illustration of getting the file and line of the current line. It can be used in other ways that don't lend themselves to raising exceptions.

[gravatar]
David Brownell 6:17 PM on 3 Oct 2004

This may or may not be of any use to you, but many C++ compilers do make the current function name available via __FILE__ and __LINE__-like macros. For example, MSVC defines __FUNCSIG__ that will print out the current function.

Boost provides a handy macro called BOOST_CURRENT_FUNCTION that is mapped to the appropriate macro based on your current compiler. The macro is #defined in boost\current_function.hpp.

I hope this helps someone out there!

[gravatar]
Ian Bicking 8:18 PM on 3 Oct 2004

In addition to inspect -- which is very complete -- you can also use the warnings module. There's a "stack" argument, which says how far back in the stack you should go to find the bad code. So in your case, you might go back two steps -- one to get out of your generic warning wrapper, and another to get out of the not-yet-implemented function to the function's caller; this can be even better, because you probably know that the function isn't implemented, but you may be more concerned about the function that called the not-yet-implemented function (or maybe it's a poorly-implemented function, or a deprecated function).

Also, you can use the traceback module to print a traceback, without actually raising an exception.

[gravatar]
Jorge Constanzo 12:37 AM on 12 Jan 2005

Hello:

I saw the code and i thought that it may be very useful to me for finishing a program that i'm making.

But i have a question with the _getframe() function. If i want to get the filename of the current program that it's running, i.e. the path of the self program; which is the argument for _getframe() (in this case nFramesUp+1) that i must input for this purpose?

Beforehand, thank you very much.

Add a comment:

name
email
Ignore this:
not displayed and no spam.
Leave this empty:
www
not searched.
 
Name and either email or www are required.
Don't put anything here:
Leave this empty:
URLs auto-link and some tags are allowed: <a><b><i><p><br><pre>.