How can I get the file name and line number in a Python script?
Exactly the file information we get from an exception traceback. In this case without raising an exception.
011 Answers
Thanks to mcandre, the answer is:
#python3 from inspect import currentframe, getframeinfo frameinfo = getframeinfo(currentframe()) print(frameinfo.filename, frameinfo.lineno) 5Whether you use currentframe().f_back depends on whether you are using a function or not.
Calling inspect directly:
from inspect import currentframe, getframeinfo cf = currentframe() filename = getframeinfo(cf).filename print "This is line 5, python says line ", cf.f_lineno print "The filename is ", filename Calling a function that does it for you:
from inspect import currentframe def get_linenumber(): cf = currentframe() return cf.f_back.f_lineno print "This is line 7, python says line ", get_linenumber() 4Handy if used in a common file - prints file name, line number and function of the caller:
import inspect def getLineInfo(): print(inspect.stack()[1][1],":",inspect.stack()[1][2],":", inspect.stack()[1][3]) 0Filename:
__file__ # or sys.argv[0] Line:
inspect.currentframe().f_lineno (not inspect.currentframe().f_back.f_lineno as mentioned above)
Better to use sys also-
print(dir(sys._getframe())) print(dir(sys._getframe().f_lineno) print(sys._getframe().f_lineno) The output is:
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'f_back', 'f_builtins', 'f_code', 'f_exc_traceback', 'f_exc_type', 'f_exc_value', 'f_globals', 'f_lasti', 'f_lineno', 'f_locals', 'f_restricted', 'f_trace'] ['__abs__', '__add__', '__and__', '__class__', '__cmp__', '__coerce__', '__delattr__', '__div__', '__divmod__', '__doc__', '__float__', '__floordiv__', '__format__', '__getattribute__', '__getnewargs__', '__hash__', '__hex__', '__index__', '__init__', '__int__', '__invert__', '__long__', '__lshift__', '__mod__', '__mul__', '__neg__', '__new__', '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'imag', 'numerator', 'real'] 14 In Python 3 you can use a variation on:
def Deb(msg = None): print(f"Debug {sys._getframe().f_back.f_lineno}: {msg if msg is not None else ''}") In code, you can then use:
Deb("Some useful information") Deb() To produce:
123: Some useful information 124: Where the 123 and 124 are the lines that the calls are made from.
1Just to contribute,
there is a linecache module in python, here is two links that can help.
linecache module documentation
linecache source code
In a sense, you can "dump" a whole file into its cache , and read it with linecache.cache data from class.
import linecache as allLines ## have in mind that fileName in linecache behaves as any other open statement, you will need a path to a file if file is not in the same directory as script linesList = allLines.updatechache( fileName ,None) for i,x in enumerate(lineslist): print(i,x) #prints the line number and content #or for more info print(line.cache) #or you need a specific line specLine = allLines.getline(fileName,numbOfLine) #returns a textual line from that number of line For additional info, for error handling, you can simply use
from sys import exc_info try: raise YourError # or some other error except Exception: print(exc_info() ) import inspect file_name = __FILE__ current_line_no = inspect.stack()[0][2] current_function_name = inspect.stack()[0][3] #Try printing inspect.stack() you can see current stack and pick whatever you want 1Here's a short function that prints the file name and line number.
from inspect import currentframe, getframeinfo def HERE(do_print=True): ''' Get the current file and line number in Python script. The line number is taken from the caller, i.e. where this function is called. Parameters ---------- do_print : boolean If True, print the file name and line number to stdout. Returns ------- String with file name and line number if do_print is False. Examples -------- >>> HERE() # Prints to stdout >>> print(HERE(do_print=False)) ''' frameinfo = getframeinfo(currentframe().f_back) filename = frameinfo.filename.split('/')[-1] linenumber = frameinfo.lineno loc_str = 'File: %s, line: %d' % (filename, linenumber) if do_print: print('HERE AT %s' % (loc_str)) else: return loc_str Usage:
HERE() # Prints to stdout # Output: HERE AT File: model.py, line: 275 print(HERE(False)) # Retrieves string and prints it. # Output: File: model.py, line: 276 1Golang style
import inspect import sys import atexit ERR_FILE = open('errors.log', 'w+', encoding='utf-8') LOG_FILE = open('log.log', 'w+', encoding='utf-8') def exit_handler(): # ctrl + C works as well log("Exiting") ERR_FILE.close() LOG_FILE.close() # close files before exit atexit.register(exit_handler) def log(*args, files=[sys.stdout, LOG_FILE]): # can also add timestamps etc. cf = inspect.currentframe() for f in files: print("DEBUG", f"{inspect.stack()[1][1]}:{cf.f_back.f_lineno}", *args, file=f) f.flush() def log_err(*args, files=[ERR_FILE, sys.stderr]): cf = inspect.currentframe() for f in files: print("ERROR", f"{inspect.stack()[1][1]}:{cf.f_back.f_lineno}", *args, file=f) f.flush() log("Hello World!") log_err("error") Output
DEBUG sample.py:29 Hello World! ERROR sample.py:30 error DEBUG sample.py:9 Exiting Here's what works for me to get the line number in Python 3.7.3 in VSCode 1.39.2 (dmsg is my mnemonic for debug message):
import inspect def dmsg(text_s): print (str(inspect.currentframe().f_back.f_lineno) + '| ' + text_s) To call showing a variable name_s and its value:
name_s = put_code_here dmsg('name_s: ' + name_s) Output looks like this:
37| name_s: value_of_variable_at_line_37