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
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
Why not just raise NotImplementedError? The stack trace will show the file, line and function with the error.
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.
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!
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.
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: