201

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.

Joey
  • 5,541
  • 7
  • 27
  • 27

13 Answers13

236

Thanks to mcandre, the answer is:

#python3
from inspect import currentframe, getframeinfo

frameinfo = getframeinfo(currentframe())

print(frameinfo.filename, frameinfo.lineno)
Yash
  • 108
  • 9
Joey
  • 5,541
  • 7
  • 27
  • 27
  • 2
    Does using this method have any performance impact (like minor increase in run time or more CPU needed ) ? – gsinha Dec 14 '14 at 05:41
  • 10
    @gsinha: Every function call has performance impact. You have to measure if this impact is acceptable for you. – omikron Nov 09 '15 at 14:45
  • 18
    So, if you like "one line" type answers use: `import inspect inspect.getframeinfo(inspect.currentframe()).lineno` – 1-ijk Sep 21 '17 at 18:11
  • 2
    To expand on this, at what point is the line number "evaluated", in the second or third line? I.e does `frameinfo.lineno` give you the line numer when you evaluate it, or when you created it with `getframeinfo(currentframe())`? – Marses Mar 26 '18 at 13:48
  • 2
    @LimokPalantaemon it happens when `currentframe()` is called, which means you can't simplify this any more than `getframeinfo(currentframe()).lineno` (if you only care about the line number and not the file name). See https://docs.python.org/2/library/inspect.html#inspect.currentframe – Aaron Miller Sep 21 '18 at 17:20
92

Whether 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()
aaren
  • 5,325
  • 6
  • 29
  • 24
36

Handy 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])
loki
  • 9,816
  • 7
  • 56
  • 82
Streamsoup
  • 834
  • 8
  • 7
27

Better to use sys also-

import sys
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
SRG
  • 498
  • 7
  • 19
Mohammad Shahid Siddiqui
  • 3,730
  • 2
  • 27
  • 12
  • Should use `sys._getframe().f_back.f_lineno`, especialy when used in a function, otherwise it will print the line where it's being called in the function. – synkro May 15 '23 at 21:34
23

Filename:

__file__
# or
sys.argv[0]

Line:

inspect.currentframe().f_lineno

(not inspect.currentframe().f_back.f_lineno as mentioned above)

Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
arilou
  • 465
  • 3
  • 6
  • 1
    `NameError: global name '__file__' is not defined` on my Python interpreter: `Python 2.7.6 (default, Sep 26 2014, 15:59:23)`. See http://stackoverflow.com/questions/9271464/what-does-the-file-variable-mean-do/9271617#comment33090606_9271479 – bgoodr May 05 '17 at 17:41
  • 1
    a function version, ```def __LINE__() -> int: return inspect.currentframe().f_back.f_lineno def __FILE__() -> str: return inspect.currentframe().f_back.f_code.co_filename``` – hanshenrik May 10 '22 at 21:25
  • @hanshenrik, copilot agrees with you – oldpride Jul 18 '23 at 22:50
22

In Python 3 you can use a variation on (This has been improved after a comment by Claudio):

def Deb(msg=""):
  print(f"Debug {sys._getframe().f_back.f_lineno}: {msg}")

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.

Thickycat
  • 894
  • 6
  • 12
8

Just 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() )
Danilo
  • 1,017
  • 13
  • 32
7
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 
0xC0000022L
  • 20,597
  • 9
  • 86
  • 152
Haroon Rashedu
  • 155
  • 1
  • 9
  • Similar to `__file__`: See http://stackoverflow.com/questions/3056048/filename-and-line-number-of-python-script#comment74661035_10623150 – bgoodr May 05 '17 at 17:45
7

Here'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
stackoverflowuser2010
  • 38,621
  • 48
  • 169
  • 217
1

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
Steph
  • 81
  • 1
  • 1
  • 6
  • Thanks @Steph! I came up with the following for my code: def dbgline(): print(f"{inspect.currentframe().f_back.f_globals['__file__']}:{inspect.currentframe().f_back.f_lineno}") – Mahmut ARIKAN Mar 03 '23 at 13:38
1

Golang 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
Phani Rithvij
  • 4,030
  • 3
  • 25
  • 60
0

Inspired by many of the above answers and the console.log() function of JavaScript, I have deployed a pip package to serve this purpose. Please check this out here.

How to install?

Just install the package using the command:

pip3 install print_position

A simple example is (test.py):

from printPosition.printPosition import printPosition as print 
print("Test on line 2 from test.py")
print("Test on line 3 from test.py")



print("Test on line 7 from test.py")

The output of the above code is:

@/home/pranav/Desktop/GitHub/PrintPosition-pip/print-log/test.py: 2 
Test on line 2 from test.py
@/home/pranav/Desktop/GitHub/PrintPosition-pip/print-log/test.py: 3 
Test on line 3 from test.py
@/home/pranav/Desktop/GitHub/PrintPosition-pip/print-log/test.py: 7 
Test on line 7 from test.py

Please let me know if it helped you! Also feel free to raise any issues/requests, everything is mentioned on the pip page here.

0

People familiar with PHP's __FILE__ and __LINE__ might appreciate

import inspect

def __FILE__() -> str:
    # ptyhon has a native __file__ 
    return inspect.currentframe().f_back.f_code.co_filename

def __LINE__() -> int:
    # python has no native __line__, the closest thing I could find was: sys._getframe().f_lineno
    return inspect.currentframe().f_back.f_lineno

unfortunately they must be used with (), sample usage:

print("file: " + __FILE__() + " line: " + str(__LINE__()) );

(both are part of my collection of php-apis-ported-to-python, https://github.com/divinity76/phppy/blob/main/php.py )

hanshenrik
  • 19,904
  • 4
  • 43
  • 89
  • This didn't work for me – con Aug 09 '23 at 14:49
  • @con what happens when you try it? an error? wrong line number? wrong file? fwiw here is the code running on Wandbox: https://wandbox.org/permlink/WABqQbLtEJdltVwV – hanshenrik Aug 09 '23 at 15:26
  • maybe I didn't implement the code correctly, a minimal example seems to work, the much larger project that I edited before didn't work, likely my own fault – con Aug 10 '23 at 16:25