Sunday 3 October 2004 — This is 20 years old. Be careful.
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
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
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!
Also, you can use the traceback module to print a traceback, without actually raising an exception.
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: