503

I have scripts calling other script files but I need to get the filepath of the file that is currently running within the process.

For example, let's say I have three files. Using execfile:

  • script_1.py calls script_2.py.
  • In turn, script_2.py calls script_3.py.

How can I get the file name and path of script_3.py, from code within script_3.py, without having to pass that information as arguments from script_2.py?

(Executing os.getcwd() returns the original starting script's filepath not the current file's.)

kdopen
  • 7,617
  • 7
  • 37
  • 49
Ray
  • 169,974
  • 95
  • 213
  • 200

29 Answers29

581
__file__

as others have said. You may also want to use os.path.realpath to eliminate symlinks:

import os

os.path.realpath(__file__)
Cees Timmerman
  • 13,202
  • 8
  • 78
  • 106
user13993
  • 5,911
  • 2
  • 14
  • 3
  • 15
    One needs to be careful with this approach because sometimes `__file__` returns 'script_name.py', and other times 'script_name.pyc'. So output isn't stable. – mechatroner Sep 05 '15 at 23:53
  • 27
    But since we are only using the path of this file that's irrelevant. – Uwe Koloska Sep 29 '16 at 09:36
  • 5
    this is weird: when running from command line `"__file__"` in quotes (as string) gives the dir from which cmd is run, but `__file__` (without quotes gives the path to the source file ... why is that – muon May 09 '18 at 13:53
  • 10
    @muon there is no check performed on whether a filename string passed in exists, and since file paths are relative to the cwd, that is what the `os.path.realpath` function assumes the `dir` part of the path to be. `os.path.dirname(os.path.realpath(__file__))` returns directory with the file. `os.path.dirname(os.path.realpath("__file__"))` returns cwd. `os.path.dirname(os.path.realpath("here_be_dragons"))` also returns cwd. – Jamie Bull Oct 26 '18 at 08:11
268

p1.py:

execfile("p2.py")

p2.py:

import inspect, os
print (inspect.getfile(inspect.currentframe()) # script filename (usually with path)
print (os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))) # script directory
Krzysztof Janiszewski
  • 3,542
  • 3
  • 15
  • 33
Pat Notz
  • 186,044
  • 29
  • 86
  • 92
  • @David, when I do `inspect.getfile(inspect.currentframe())`, it gives me the full path of the file being processed. So I'm not sure what you mean, or under what conditions this would not give the "name and path". – LarsH Jan 29 '13 at 18:55
  • It does? Not for me, and several others by the look of it. The second line that has been added to the answer does provide the full path though – David Sykes Jan 30 '13 at 13:02
  • 12
    BEWARE: This call does not give the same result with different environments. Consider accepting Usagi's answer below: http://stackoverflow.com/a/6628348/851398 – faraday Mar 05 '14 at 07:41
  • 3
    @faraday: Could you provide an example? I've answered [similar question using `inspect.getabsfile()`](http://stackoverflow.com/a/22881871/4279) and it worked for all cases that I've tried. – jfs Apr 05 '14 at 17:04
  • 1
    Is indeed @Usagi answer better? – Dror Dec 23 '14 at 10:13
  • 4
    nah user13993 nailed it far better – osirisgothra Aug 13 '15 at 04:49
  • 6
    user13993 did indeed nail it. Should be `os.path.realpath(__file__)` – uchuugaka Aug 13 '15 at 09:02
  • @Dror user13933's method gives me the name of the caller not the called. This is right for the question asked. – blindguy Sep 11 '15 at 20:54
  • 1
    @osirisgothra: you do understand that `__file__` doesn't work with `execfile()` that is *explicitly* mentioned in the question. – jfs Sep 21 '15 at 17:20
  • 1
    While __file__ is usually good enough, it wont work when you your program is running somewhere far away from __file__. – emish Dec 17 '15 at 22:49
  • 2
    `inspect.getfile()` returns the `__file__` attribute if passed a module object. `inspect.currentframe()` returns the module. Ergo, this is an expensive way of saying `__file__`. – Martijn Pieters May 12 '18 at 19:01
93

Update 2018-11-28:

Here is a summary of experiments with Python 2 and 3. With

main.py - runs foo.py
foo.py - runs lib/bar.py
lib/bar.py - prints filepath expressions

| Python | Run statement       | Filepath expression                    |
|--------+---------------------+----------------------------------------|
|      2 | execfile            | os.path.abspath(inspect.stack()[0][1]) |
|      2 | from lib import bar | __file__                               |
|      3 | exec                | (wasn't able to obtain it)             |
|      3 | import lib.bar      | __file__                               |

For Python 2, it might be clearer to switch to packages so can use from lib import bar - just add empty __init__.py files to the two folders.

For Python 3, execfile doesn't exist - the nearest alternative is exec(open(<filename>).read()), though this affects the stack frames. It's simplest to just use import foo and import lib.bar - no __init__.py files needed.

See also Difference between import and execfile


Original Answer:

Here is an experiment based on the answers in this thread - with Python 2.7.10 on Windows.

The stack-based ones are the only ones that seem to give reliable results. The last two have the shortest syntax, i.e. -

print os.path.abspath(inspect.stack()[0][1])                   # C:\filepaths\lib\bar.py
print os.path.dirname(os.path.abspath(inspect.stack()[0][1]))  # C:\filepaths\lib

Here's to these being added to sys as functions! Credit to @Usagi and @pablog

Based on the following three files, and running main.py from its folder with python main.py (also tried execfiles with absolute paths and calling from a separate folder).

C:\filepaths\main.py: execfile('foo.py')
C:\filepaths\foo.py: execfile('lib/bar.py')
C:\filepaths\lib\bar.py:

import sys
import os
import inspect

print "Python " + sys.version
print

print __file__                                        # main.py
print sys.argv[0]                                     # main.py
print inspect.stack()[0][1]                           # lib/bar.py
print sys.path[0]                                     # C:\filepaths
print

print os.path.realpath(__file__)                      # C:\filepaths\main.py
print os.path.abspath(__file__)                       # C:\filepaths\main.py
print os.path.basename(__file__)                      # main.py
print os.path.basename(os.path.realpath(sys.argv[0])) # main.py
print

print sys.path[0]                                     # C:\filepaths
print os.path.abspath(os.path.split(sys.argv[0])[0])  # C:\filepaths
print os.path.dirname(os.path.abspath(__file__))      # C:\filepaths
print os.path.dirname(os.path.realpath(sys.argv[0]))  # C:\filepaths
print os.path.dirname(__file__)                       # (empty string)
print

print inspect.getfile(inspect.currentframe())         # lib/bar.py

print os.path.abspath(inspect.getfile(inspect.currentframe())) # C:\filepaths\lib\bar.py
print os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) # C:\filepaths\lib
print

print os.path.abspath(inspect.stack()[0][1])          # C:\filepaths\lib\bar.py
print os.path.dirname(os.path.abspath(inspect.stack()[0][1]))  # C:\filepaths\lib
print
Brian Burns
  • 14,953
  • 5
  • 69
  • 59
73

I think this is cleaner:

import inspect
print inspect.stack()[0][1]

and gets the same information as:

print inspect.getfile(inspect.currentframe())

Where [0] is the current frame in the stack (top of stack) and [1] is for the file name, increase to go backwards in the stack i.e.

print inspect.stack()[1][1]

would be the file name of the script that called the current frame. Also, using [-1] will get you to the bottom of the stack, the original calling script.

Usagi
  • 2,678
  • 2
  • 24
  • 35
  • 4
    Do not recommend relying on the position inside the tuple. It's not clear at all what data you're trying to get when reading the code. – jpmc26 Jan 19 '18 at 02:13
  • 5
    `inspect.getfile()` returns the `__file__` attribute if passed a module object. `inspect.currentframe()` returns the module. Ergo, this is an expensive way of saying `__file__`. – Martijn Pieters May 12 '18 at 19:01
  • `inspect.stack()` is a pretty expensive function, more so than just `inspect.currentframe()`, and it too calls `inspect.getfile()` on a module object. – Martijn Pieters May 12 '18 at 19:03
48
import os
os.path.dirname(__file__) # relative directory path
os.path.abspath(__file__) # absolute file path
os.path.basename(__file__) # the file name only
Neal Xiong
  • 1,047
  • 10
  • 7
  • 1
    I just tried @Pat Notz's comment. I think you could just get the filename through `__file__`. – hlin117 Apr 25 '15 at 17:51
  • In Python3, `os.path.dirname` will give you the relative path from where you are running the script. e.g. in `python ../../test.py` the `os.path.dirname` will be `../../` and not the absolute path to the script. I was looking for abspath but removing the name of the script. The first element of sys.path apparently is the answer `sys.path[0]`. – aerijman Nov 13 '19 at 14:42
37

The suggestions marked as best are all true if your script consists of only one file.

If you want to find out the name of the executable (i.e. the root file passed to the python interpreter for the current program) from a file that may be imported as a module, you need to do this (let's assume this is in a file named foo.py):

import inspect

print inspect.stack()[-1][1]

Because the last thing ([-1]) on the stack is the first thing that went into it (stacks are LIFO/FILO data structures).

Then in file bar.py if you import foo it'll print bar.py, rather than foo.py, which would be the value of all of these:

  • __file__
  • inspect.getfile(inspect.currentframe())
  • inspect.stack()[0][1]
  • It works well but not for unit test on eclipse, I got /home/user/Softwares/eclipse/plugins/org.python.pydev_4.5.5.201603221110/pysrc – hayj Jun 14 '16 at 14:29
  • 2
    This is an expensive way of spelling `sys.modules['__main__'].__file__`, really. – Martijn Pieters May 12 '18 at 19:08
15

It's not entirely clear what you mean by "the filepath of the file that is currently running within the process". sys.argv[0] usually contains the location of the script that was invoked by the Python interpreter. Check the sys documentation for more details.

As @Tim and @Pat Notz have pointed out, the __file__ attribute provides access to

the file from which the module was loaded, if it was loaded from a file

twasbrillig
  • 12,313
  • 7
  • 37
  • 61
Blair Conrad
  • 202,794
  • 24
  • 127
  • 110
  • 1
    "print os.path.abspath( __file__ )" and "print inspect.getfile( inspect.currentframe() )" doesn't work when we pass the python program to a win32 exe. Only sys.argv[0] works! :) but you only get the name! – aF. Sep 01 '11 at 15:02
14
import os
print os.path.basename(__file__)

this will give us the filename only. i.e. if abspath of file is c:\abcd\abc.py then 2nd line will print abc.py

vishal ekhe
  • 199
  • 2
  • 8
12

I have a script that must work under windows environment. This code snipped is what I've finished with:

import os,sys
PROJECT_PATH = os.path.abspath(os.path.split(sys.argv[0])[0])

it's quite a hacky decision. But it requires no external libraries and it's the most important thing in my case.

Jahid
  • 18,228
  • 8
  • 79
  • 95
garmoncheg
  • 803
  • 8
  • 24
  • 1
    I had to "import os, sys" for this, but so far it's the best answer that actually returns just the path without a file name at the end of the string. – emmagras Oct 18 '14 at 15:40
10

Try this,

import os
os.path.dirname(os.path.realpath(__file__))
Soumyajit
  • 309
  • 1
  • 4
  • 15
8
import os
os.path.dirname(os.path.abspath(__file__))

No need for inspect or any other library.

This worked for me when I had to import a script (from a different directory then the executed script), that used a configuration file residing in the same folder as the imported script.

Gergo Erdosi
  • 36,694
  • 21
  • 106
  • 90
Kwuite
  • 437
  • 5
  • 5
  • This will not produce the desired answer if the current working directory (os.getcwd) is different from the directory in which the file is located. – Iron Pillow Aug 01 '14 at 20:59
  • 2
    How so? Works fine for me in this case. I get the directory the file is located in. – Michael Mior Aug 13 '14 at 01:39
  • @IronPillow maybe this answer will help you with what you need. http://stackoverflow.com/a/41546830/3123191 – Kwuite Feb 23 '17 at 15:21
8

The __file__ attribute works for both the file containing the main execution code as well as imported modules.

See https://web.archive.org/web/20090918095828/http://pyref.infogami.com/__file__

Brian Burns
  • 14,953
  • 5
  • 69
  • 59
readonly
  • 306,152
  • 101
  • 198
  • 201
8

Since Python 3 is fairly mainstream, I wanted to include a pathlib answer, as I believe that it is probably now a better tool for accessing file and path information.

from pathlib import Path

current_file: Path = Path(__file__).resolve()

If you are seeking the directory of the current file, it is as easy as adding .parent to the Path() statement:

current_path: Path = Path(__file__).parent.resolve()
Doug
  • 2,730
  • 3
  • 15
  • 15
7
import sys

print sys.path[0]

this would print the path of the currently executing script

appusajeev
  • 1,653
  • 3
  • 16
  • 19
  • 2
    sys.path[0] is very useful, but gives the path of script1, not script3 as requested – James Jan 28 '11 at 01:26
  • At least on OS X, with 2.7, I don't find this does anything reliable. It works if executing directly the same file. Doesn't work from repl, especially from an imported egg – uchuugaka Aug 13 '15 at 08:58
5

I think it's just __file__ Sounds like you may also want to checkout the inspect module.

smparkes
  • 13,460
  • 4
  • 34
  • 62
Pat Notz
  • 186,044
  • 29
  • 86
  • 92
4

You can use inspect.stack()

import inspect,os
inspect.stack()[0]  => (<frame object at 0x00AC2AC0>, 'g:\\Python\\Test\\_GetCurrentProgram.py', 15, '<module>', ['print inspect.stack()[0]\n'], 0)
os.path.abspath (inspect.stack()[0][1]) => 'g:\\Python\\Test\\_GetCurrentProgram.py'
Jahid
  • 18,228
  • 8
  • 79
  • 95
PabloG
  • 23,021
  • 10
  • 41
  • 58
3
import sys
print sys.argv[0]
WBAR
  • 4,273
  • 6
  • 40
  • 77
  • 10
    Unfortunately this only works if the script was called with its full path, because it only returns the "first argument" on the command line, which is the calling to the script. – cregox May 13 '10 at 17:40
2

This should work:

import os,sys
filename=os.path.basename(os.path.realpath(sys.argv[0]))
dirname=os.path.dirname(os.path.realpath(sys.argv[0]))
Jahid
  • 18,228
  • 8
  • 79
  • 95
2
print(__file__)
print(__import__("pathlib").Path(__file__).parent)
BaiJiFeiLong
  • 1,781
  • 1
  • 13
  • 18
  • 6
    Code only answers are discouraged. Please add some explanation as to how this solves the problem, or how this differs from the existing answers. [From Review](https://stackoverflow.com/review/low-quality-posts/22927933) – Nick May 05 '19 at 01:51
1

To get directory of executing script

 print os.path.dirname( inspect.getfile(inspect.currentframe()))
pbaranski
  • 17,946
  • 16
  • 88
  • 101
1

Here is what I use so I can throw my code anywhere without issue. __name__ is always defined, but __file__ is only defined when the code is run as a file (e.g. not in IDLE/iPython).

if '__file__' in globals():
    self_name = globals()['__file__']
elif '__file__' in locals():
    self_name = locals()['__file__']
else:
    self_name = __name__

Alternatively, this can be written as:

self_name = globals().get('__file__', locals().get('__file__', __name__))
craymichael
  • 3,468
  • 1
  • 11
  • 22
0

I wrote a function which take into account eclipse debugger and unittest. It return the folder of the first script you launch. You can optionally specify the __file__ var, but the main thing is that you don't have to share this variable across all your calling hierarchy.

Maybe you can handle others stack particular cases I didn't see, but for me it's ok.

import inspect, os
def getRootDirectory(_file_=None):
    """
    Get the directory of the root execution file
    Can help: http://stackoverflow.com/questions/50499/how-do-i-get-the-path-and-name-of-the-file-that-is-currently-executing
    For eclipse user with unittest or debugger, the function search for the correct folder in the stack
    You can pass __file__ (with 4 underscores) if you want the caller directory
    """
    # If we don't have the __file__ :
    if _file_ is None:
        # We get the last :
        rootFile = inspect.stack()[-1][1]
        folder = os.path.abspath(rootFile)
        # If we use unittest :
        if ("/pysrc" in folder) & ("org.python.pydev" in folder):
            previous = None
            # We search from left to right the case.py :
            for el in inspect.stack():
                currentFile = os.path.abspath(el[1])
                if ("unittest/case.py" in currentFile) | ("org.python.pydev" in currentFile):
                    break
                previous = currentFile
            folder = previous
        # We return the folder :
        return os.path.dirname(folder)
    else:
        # We return the folder according to specified __file__ :
        return os.path.dirname(os.path.realpath(_file_))
hayj
  • 710
  • 8
  • 17
0

To keep the migration consistency across platforms (macOS/Windows/Linux), try:

path = r'%s' % os.getcwd().replace('\\','/')

Qiao Zhang
  • 415
  • 4
  • 8
0

Simplest way is:

in script_1.py:

import subprocess
subprocess.call(['python3',<path_to_script_2.py>])

in script_2.py:

sys.argv[0]

P.S.: I've tried execfile, but since it reads script_2.py as a string, sys.argv[0] returned <string>.

Lucas Azevedo
  • 1,243
  • 15
  • 29
0

I used the approach with __file__
os.path.abspath(__file__)
but there is a little trick, it returns the .py file when the code is run the first time, next runs give the name of *.pyc file
so I stayed with:
inspect.getfile(inspect.currentframe())
or
sys._getframe().f_code.co_filename

mik80
  • 53
  • 2
  • 8
0

I have always just used the os feature of Current Working Directory, or CWD. This is part of the standard library, and is very easy to implement. Here is an example:

    import os
    base_directory = os.getcwd()
Ethan J.
  • 62
  • 2
  • 1
    Could you modify your answer so that it applies to the question posed? This answer does not apply to the question "How do I get the path and name *of the file that is currently executing?*" – Marco Mar 14 '19 at 16:17
  • 1
    This gives the path from where you ran the python command. So it seems to work when you run the `python script.py` command in the same folder you already are, when in reality it's the same as running `pwd` on linux. – George Jul 14 '19 at 13:10
-2

Most of these answers were written in Python version 2.x or earlier. In Python 3.x the syntax for the print function has changed to require parentheses, i.e. print().

So, this earlier high score answer from user13993 in Python 2.x:

import inspect, os
print inspect.getfile(inspect.currentframe()) # script filename (usually with path)
print os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) # script directory

Becomes in Python 3.x:

import inspect, os
print(inspect.getfile(inspect.currentframe())) # script filename (usually with path)
print(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) ) # script directory
-3

if you want just the filename without ./ or .py you can try this

filename = testscript.py
file_name = __file__[2:-3]

file_name will print testscript you can generate whatever you want by changing the index inside []

mychalvlcek
  • 3,801
  • 1
  • 17
  • 34
sapam
  • 3
  • 1
-3
import os

import wx


# return the full path of this file
print(os.getcwd())

icon = wx.Icon(os.getcwd() + '/img/image.png', wx.BITMAP_TYPE_PNG, 16, 16)

# put the icon on the frame
self.SetIcon(icon)
bschlueter
  • 3,069
  • 23
  • 45
jscabuzzo
  • 11
  • 1
  • 7
    os.getcwd() returns the current WORKING directory of the PROCESS, not the directory of the currently executing file. This might appear to return the correct results but there are plenty of cases where the result would not be the current file's parent directory. Much better to use os.path.dirname(__file__) as suggested above. – samaspin May 22 '15 at 14:17