Ray
Ray

Reputation: 192476

How do I get the path and name of the python file that is currently executing?

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:

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.)

Upvotes: 592

Views: 632465

Answers (26)

Gabriel Staples
Gabriel Staples

Reputation: 53225

I'd like to go above and beyond since I need even more information. Here is how to obtain the:

  1. full path to the script being run
  2. directory of the script
  3. base filename of the script
  4. filename without the extension
  5. extension of the script
  6. home directory of the user running the script
  7. home directory of the user in whose home directory the script resides

From get_script_path.py in my eRCaGuy_hello_world repo:

import os
import sys

FULL_PATH_TO_SCRIPT = os.path.abspath(__file__)
SCRIPT_DIRECTORY = str(os.path.dirname(FULL_PATH_TO_SCRIPT))
SCRIPT_PARENT_DIRECTORY = str(os.path.dirname(SCRIPT_DIRECTORY))
# this also works, but its output will have the two dots (`/..`) in it.
SCRIPT_PARENT_DIRECTORY2 = f"{SCRIPT_DIRECTORY}/.."
FILENAME = str(os.path.basename(FULL_PATH_TO_SCRIPT))
FILENAME_NO_EXTENSION = os.path.splitext(FILENAME)[0]
FILENAME_EXTENSION = os.path.splitext(FILENAME)[1]

# the full path to the executable script being run
EXECUTABLE_FULL_PATH = sys.argv[0]
# the name of the executable being run
EXECUTABLE_NAME = os.path.basename(EXECUTABLE_FULL_PATH)

# Other useful paths:

# home directory of the current, running user
HOME_DIR_USER = os.path.expanduser("~")
# Obtain the home dir of the user in whose home directory this script resides,
# which may *not* be the home dir of the current user! Ex: run this script
# as root, via `sudo`, and you'll see that `HOME_DIR_USER` != `HOME_DIR_SCRIPT`.
script_path_list = os.path.normpath(FULL_PATH_TO_SCRIPT).split(os.sep)
HOME_DIR_SCRIPT = os.path.join("/", script_path_list[1], script_path_list[2])

# Bonus: add the parent directory to the start of the system PATH variable so
# that you can import modules directly in that directory above this script!
sys.path.insert(0, SCRIPT_PARENT_DIRECTORY)
# Now, assuming there is a `config.py`` file in the `SCRIPT_PARENT_DIRECTORY`,
# you can import it directly, like this:
#
# import config.py
#

# Print results
print(f"__file__:                  {__file__}")
print(f"FULL_PATH_TO_SCRIPT:       {FULL_PATH_TO_SCRIPT}")
print(f"SCRIPT_DIRECTORY:          {SCRIPT_DIRECTORY}")
print(f"SCRIPT_PARENT_DIRECTORY:   {SCRIPT_PARENT_DIRECTORY}")
print(f"SCRIPT_PARENT_DIRECTORY2:  {SCRIPT_PARENT_DIRECTORY2}")
print(f"FILENAME:                  {FILENAME}")
print(f"FILENAME_NO_EXTENSION:     {FILENAME_NO_EXTENSION}")
print(f"FILENAME_EXTENSION:        {FILENAME_EXTENSION}")
print("---")
print(f"HOME_DIR_USER:             {HOME_DIR_USER}")
print(f"script_path_list:          {script_path_list}")
print(f"HOME_DIR_SCRIPT:           {HOME_DIR_SCRIPT}")

Example run and output, tested on Linux Ubuntu 20.04 and 22.04:

eRCaGuy_hello_world$ python/get_script_path.py
__file__:                  python/get_script_path.py
FULL_PATH_TO_SCRIPT:       /home/gabriel/GS/dev/eRCaGuy_hello_world/python/get_script_path.py
SCRIPT_DIRECTORY:          /home/gabriel/GS/dev/eRCaGuy_hello_world/python
SCRIPT_PARENT_DIRECTORY:   /home/gabriel/GS/dev/eRCaGuy_hello_world
SCRIPT_PARENT_DIRECTORY2:  /home/gabriel/GS/dev/eRCaGuy_hello_world/python/..
FILENAME:                  get_script_path.py
FILENAME_NO_EXTENSION:     get_script_path
FILENAME_EXTENSION:        .py
---
HOME_DIR_USER:             /home/gabriel
script_path_list:          ['', 'home', 'gabriel', 'GS', 'dev', 'eRCaGuy_hello_world', 'python', 'get_script_path.py']
HOME_DIR_SCRIPT:           /home/gabriel

When run as root: notice that HOME_DIR_USER, the active user's home dir, now changes:

eRCaGuy_hello_world$ sudo python/get_script_path.py
[sudo] password for gabriel:
__file__:                  python/get_script_path.py
FULL_PATH_TO_SCRIPT:       /home/gabriel/GS/dev/eRCaGuy_hello_world/python/get_script_path.py
SCRIPT_DIRECTORY:          /home/gabriel/GS/dev/eRCaGuy_hello_world/python
SCRIPT_PARENT_DIRECTORY:   /home/gabriel/GS/dev/eRCaGuy_hello_world
SCRIPT_PARENT_DIRECTORY2:  /home/gabriel/GS/dev/eRCaGuy_hello_world/python/..
FILENAME:                  get_script_path.py
FILENAME_NO_EXTENSION:     get_script_path
FILENAME_EXTENSION:        .py
---
HOME_DIR_USER:             /root
script_path_list:          ['', 'home', 'gabriel', 'GS', 'dev', 'eRCaGuy_hello_world', 'python', 'get_script_path.py']
HOME_DIR_SCRIPT:           /home/gabriel

Additional explanation for finding HOME_DIR_SCRIPT

...which is the home directory of the path in which your Python script resides.

If the path to your script is /home/gabriel/GS/dev/eRCaGuy_dotfiles/useful_scripts/cpu_logger.py, and you wish to obtain the home directory part of that path, which is /home/gabriel, you can do this:

import os

# Obtain the home dir of the user in whose home directory this script resides
script_path_list = os.path.normpath(os.path.abspath(__file__)).split(os.sep)
home_dir = os.path.join("/", script_path_list[1], script_path_list[2])

To help make sense of this, here are the paths for os.path.abspath(__file__), script_path_list, and home_dir. Notice that script_path_list is a list of the path components, with the first element being an empty string since it originally contained the / root dir path separator for this Linux path:

os.path.abspath(__file__): /home/gabriel/GS/dev/eRCaGuy_dotfiles/useful_scripts/cpu_logger.py
script_path_list:          ['', 'home', 'gabriel', 'GS', 'dev', 'eRCaGuy_dotfiles', 'useful_scripts', 'cpu_logger.py']
home_dir:                  /home/gabriel

My answer where I first documented this: Python: obtain the path to the home directory of the user in whose directory the script being run is located [duplicate]

Going further: relative imports in Python, from one directory up

This section has been moved to my new answer here: Relative imports in Python, from one directory up.

See also

  1. My answer on how to do the same thing in Bash: How to obtain the full file path, full directory, and base filename of any script being run OR sourced... ...even when the called script is called from within another bash function or script, or when nested sourcing is being used!
  2. This related, useful answer to: How do I get the parent directory in Python?
  3. To make the #!/usr/bin/env python3 hash-bang at the top work in Windows too, not just Linux, see my answer here: Python not working in the command line of git bash

Upvotes: 1

pbaranski
pbaranski

Reputation: 25072

To get directory of executing script

print os.path.dirname( inspect.getfile(inspect.currentframe()))

Upvotes: 2

nichoio
nichoio

Reputation: 7667

The following returns the path where your current main script is located at. I tested this with Linux, Win10, IPython and Jupyter Lab. I needed a solution that works for local Jupyter notebooks as well.

import builtins
import os
import sys

def current_dir():
    if "get_ipython" in globals() or "get_ipython" in dir(builtins):
        # os.getcwd() is PROBABLY the dir that hosts the active notebook script.
        # See also https://github.com/ipython/ipython/issues/10123
        return os.getcwd()
    else:
        return os.path.abspath(os.path.dirname(sys.argv[0]))

Upvotes: 0

Pat Notz
Pat Notz

Reputation: 214486

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

Upvotes: 289

craymichael
craymichael

Reputation: 4821

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__))

Upvotes: 4

Doug
Doug

Reputation: 3903

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()

Upvotes: 41

BaiJiFeiLong
BaiJiFeiLong

Reputation: 4675

print(__file__)
print(__import__("pathlib").Path(__file__).parent)

Upvotes: 4

Soumyajit
Soumyajit

Reputation: 349

Try this,

import os
os.path.dirname(os.path.realpath(__file__))

Upvotes: 13

Brian Burns
Brian Burns

Reputation: 22070

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

Upvotes: 105

Lucas Azevedo
Lucas Azevedo

Reputation: 2370

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>.

Upvotes: 0

user13993
user13993

Reputation: 6539

__file__

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

import os

os.path.realpath(__file__)

Upvotes: 643

hayj
hayj

Reputation: 1263

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_))

Upvotes: 0

readonly
readonly

Reputation: 356014

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__

Upvotes: 9

PabloG
PabloG

Reputation: 26745

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'

Upvotes: 5

garmoncheg
garmoncheg

Reputation: 906

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.

Upvotes: 12

Jahid
Jahid

Reputation: 22448

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]))

Upvotes: 4

Pat Notz
Pat Notz

Reputation: 214486

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

Upvotes: 6

Neal Xiong
Neal Xiong

Reputation: 1107

import os
os.path.dirname(__file__) # relative directory path
os.path.abspath(__file__) # absolute file path
os.path.basename(__file__) # the file name only

Upvotes: 52

Blair Conrad
Blair Conrad

Reputation: 242120

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

Upvotes: 18

Kwuite
Kwuite

Reputation: 646

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.

Upvotes: 9

vishal ekhe
vishal ekhe

Reputation: 209

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

Upvotes: 15

Usagi
Usagi

Reputation: 2946

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.

Upvotes: 81

mik80
mik80

Reputation: 25

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

Upvotes: 0

WBAR
WBAR

Reputation: 4984

import sys
print sys.argv[0]

Upvotes: 4

user282406
user282406

Reputation:

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]

Upvotes: 38

appusajeev
appusajeev

Reputation: 2309

import sys

print sys.path[0]

this would print the path of the currently executing script

Upvotes: 8

Related Questions