664

Consider the following Python code:

import os
print os.getcwd()

I use os.getcwd() to get the script file's directory location. When I run the script from the command line it gives me the correct path whereas when I run it from a script run by code in a Django view it prints /.

How can I get the path to the script from within a script run by a Django view?

UPDATE:
Summing up the answers thus far - os.getcwd() and os.path.abspath() both give the current working directory which may or may not be the directory where the script resides. In my web host setup __file__ gives only the filename without the path.

Isn't there any way in Python to (always) be able to receive the path in which the script resides?

martineau
  • 119,623
  • 25
  • 170
  • 301
Jonathan Livni
  • 101,334
  • 104
  • 266
  • 359
  • 2
    You should read that linked article more closely. It never suggests using `getcwd` will tell you your script's location. It suggests `argv[0]`, `dirname`, and `abspath`. – Rob Kennedy Feb 08 '11 at 15:27
  • @Rob - "print sys.argv[0]" on my web host only gives the filename, without the path – Jonathan Livni Feb 08 '11 at 15:57
  • @Rob - here's an excerpt from the linked article "os.getcwd() returns the current working directory." – Jonathan Livni Feb 08 '11 at 19:08
  • 9
    Yes, but the current working directory has absolutely no relation to the directory your script lives in. Compare with `os.chdir`, which *sets* the current working directory; it does not move your script file to a new location on the hard drive. The *initial* working directory might be the same as the directory your script lives in, but not always; the article even demonstrates that. – Rob Kennedy Feb 08 '11 at 20:12
  • 2
    Note that `__file__` will return the filename of the scripts context. Caveat emptor if you're calling out to an external script from your `__main__` - you might get a different response than you expected. –  Oct 15 '12 at 16:22
  • @jfs ? duplicate of what article? Does the SO.UI allow you to specify the link when you mark something as a duplicate? – Jesse Chisholm Aug 31 '17 at 21:59

12 Answers12

1065

You need to call os.path.realpath on __file__, so that when __file__ is a filename without the path you still get the dir path:

import os
print(os.path.dirname(os.path.realpath(__file__)))
Czarek Tomczak
  • 20,079
  • 5
  • 49
  • 56
  • 56
    This won't work if you're running from inside an interpreter, since you'll get `NameError: name '__file__' is not defined` – Ehtesh Choudhury Feb 26 '14 at 21:01
  • @EhteshChoudhury What do you mean by `running from inside an interpreter` – Frozen Flame Jan 01 '15 at 15:05
  • 3
    Try running `python -c 'import os; print os.path.dirname(os.path.realpath(__file__))'`, which is a set of commands run by a python interpreter. – Ehtesh Choudhury Jan 05 '15 at 19:50
  • 49
    I think that is expected behaviour as, that python command does not exist within a file but inside a string which you pass to the interpreter – Har Apr 14 '15 at 08:15
  • 12
    @EhteshChoudhury That's because `__file__` is a module variable that is only created when a script is being executed -> This variable represents the location of the script. An interpreter isn't being run from a file, so it can't have such a variable. – Zizouz212 Jan 21 '16 at 02:52
  • 2
    This answer is wrong. Use sys.path[0] – Mike Apr 18 '16 at 04:47
  • 5
    Mike, how is it wrong? `os.path.dirname(os.path.realpath(__file__)) == sys.path[0]` They're identical. – bobpaul Apr 22 '16 at 16:51
  • 1
    Be careful of `os.chdir()` as well. Underneath, the behavior is equivalent to concatenating the current working directory with the relative path of `__file__`. – solstice333 Aug 02 '16 at 23:03
  • 1
    @Mike Can you explain better why the answer is wrong? – Antonio Aug 29 '16 at 14:37
  • 1
    SyntaxError: invalid syntax – thang Nov 11 '16 at 20:23
  • 5
    This solution gives the directory of the current file. If this is a module in a package (i.e., script's directory's subdirectory), it is *not* the same as the script's directory. If the latter is needed, use `sys.path[0]` instead. To try it, make `t/foo.py` printing both values and `bar.py` that simply contains `import t.foo`. – Vedran Šego Mar 26 '19 at 21:09
  • Would be useful to provide example on what to expect on an absolute path with an enough dept. – mercury Jul 20 '21 at 06:54
207

Try sys.path[0].

To quote from the Python docs:

As initialized upon program startup, the first item of this list, path[0], is the directory containing the script that was used to invoke the Python interpreter. If the script directory is not available (e.g. if the interpreter is invoked interactively or if the script is read from standard input), path[0] is the empty string, which directs Python to search modules in the current directory first. Notice that the script directory is inserted before the entries inserted as a result of PYTHONPATH.

Source: https://docs.python.org/library/sys.html#sys.path

Asclepius
  • 57,944
  • 17
  • 167
  • 143
RED MONKEY
  • 3,025
  • 2
  • 21
  • 23
  • 18
    @thang Usually, it would be, but this returns the filepath of the script that is running, not the directory of the called script. In other words, if I call script `/baz.py` from `/foo/bar.py`, this solution will return `/foo` instead of the desired `/`. – Edwin Apr 11 '17 at 04:12
  • 1
    I encountered one problem with this solution. I'm building a large program named `foo` where the main script is called `__main__.py` and resides in the `foo` directory. I can either invoke my program by running `python foo/__main__.py` or simply `python foo`. With the former, your solution works, but with the latter, I end up with the relative path instead of the absolute path. Wrapping your solution in `os.path.realpath()` solved this problem. – Adam Stewart May 29 '18 at 15:43
  • They sys.argv[0] failed in one case for me: When wrapping my scripts into an App on MacOS with py2app, the sys.argv[0] becomes a hard-coded `my.app/Contents/Resources/lib/python36.zip`, when all my supporting scripts are in `my.app/Contents/Resources`. It could be a py2app bug but it proves that relying on the argv is still a bit fragile. – kakyo Jul 03 '18 at 21:47
  • I'm calling a script as a symlink in my bin directory, to an executable python file that's not in my PATH. However, sys.path[0] shows my bin directory rather than the absolute path to the script being run. – Brian Minton Jul 13 '18 at 18:39
  • `sys.path[0]` refers to the location script is running from which in most cases will be the same as the directory containing the script. Now if you compile your script to binary and then execute it, well, then `sys.path[0]` would refer to %temp% since exe runs from temp. At least this is the case on Windows. – user6037143 Nov 16 '18 at 19:44
156

I use:

import os
import sys

def get_script_path():
    return os.path.dirname(os.path.realpath(sys.argv[0]))

As aiham points out in a comment, you can define this function in a module and use it in different scripts.

Asclepius
  • 57,944
  • 17
  • 167
  • 143
neuro
  • 14,948
  • 3
  • 36
  • 59
  • 14
    +1 because the useful `__file__` module attribute is not always defined. – iacopo Jul 03 '13 at 12:13
  • 5
    This is also useful if you want to place getScriptPath() in a different module but get the path of the file that was actually executed rather than the module path. – aiham Sep 18 '14 at 01:13
  • @aiham: Good point. In fact this function is in my framework utils module :) – neuro Sep 18 '14 at 07:20
  • @aiham: This does not seem to work for me when using a virtualenv. I get the path to the virtualenv's bin dir instead of the .py file where I call getScriptPath(). i.e. /home/vagrant/.virtualenvs/myvenv/bin/ ...Any idea around that? – mjd2 Oct 09 '15 at 02:22
  • Hum look at sys.argv[1:] ... – neuro Oct 09 '15 at 14:47
  • 1
    Just a note, this will return the path to the executed Python script. If you have these codes as package somewhere else, these codes will not return the source of the Python file. – notalentgeek Aug 28 '17 at 16:51
  • 3
    argv[0] is not a reliable way to find the script's path/filename. It can be a symbolic link's name, or anything else passed to execve(2) system call. – youfu Nov 15 '17 at 05:33
  • I wanted the path to the initial Python program, not the path to other modules in the tree where the code was executed, so this solution is perfect. Those who actually want the path to calling modules should use `__file__` instead of `sys.argv[0]`. – Nagev Aug 14 '18 at 12:43
22

This code:

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

sets "dn" to the name of the directory containing the currently executing script. This code:

fn = os.path.join(dn,"vcb.init")
fp = open(fn,"r")

sets "fn" to "script_dir/vcb.init" (in a platform independent manner) and opens that file for reading by the currently executing script.

Note that "the currently executing script" is somewhat ambiguous. If your whole program consists of 1 script, then that's the currently executing script and the "sys.path[0]" solution works fine. But if your app consists of script A, which imports some package "P" and then calls script "B", then "P.B" is currently executing. If you need to get the directory containing "P.B", you want the "os.path.realpath(__file__)" solution.

"__file__" just gives the name of the currently executing (top-of-stack) script: "x.py". It doesn't give any path info. It's the "os.path.realpath" call that does the real work.

Al Cramer
  • 229
  • 2
  • 2
18
import os,sys
# Store current working directory
pwd = os.path.dirname(__file__)
# Append current directory to the python path
sys.path.append(pwd)
Andrea Spadaccini
  • 12,378
  • 5
  • 40
  • 54
jbcurtin
  • 1,793
  • 2
  • 14
  • 23
12

Use os.path.abspath('')

Jonathan Livni
  • 101,334
  • 104
  • 266
  • 359
  • 1
    This works for everything on my dev machine, but only for script files on my web host. It does not work for settings.py, e.g. the following doesn't work: TEMPLATE_DIRS = ((os.path.abspath('')+'/templates'),) – Jonathan Livni Feb 08 '11 at 19:14
  • This didn't work for me. I'm calling an executable python scdript (that's not in my PATH) via a symlink from my PATH. It just printed my bin directory. – Brian Minton Jul 13 '18 at 18:47
  • 1
    wow... this works from all the hard cases such as running from notebook which started from parent folder OR in REPL. This should be accepted answer! – Shital Shah Jan 24 '19 at 05:29
  • 1
    This worked for me, while the answers above didn't, as I'm running Python embedded in another program. However, I wonder how it compares to `os.getcwd()`, which delivers the same result for me. – creativecoding Apr 13 '22 at 16:00
  • 1
    That is genius, helped to define the layout of folders based on how unittests were started(via pycharm or via console) – Azzonith May 02 '22 at 15:04
  • This actually is the same as `os.getcwd()`, so it's not exactly the same as `os.path.dirname(__file__)` – kakyo Aug 09 '23 at 00:56
9

This worked for me (and I found it via the this stackoverflow question)

os.path.realpath(__file__)
Community
  • 1
  • 1
Dan R
  • 384
  • 5
  • 13
9
import os
script_dir = os.path.dirname(os.path.realpath(__file__)) + os.sep
beoliver
  • 5,579
  • 5
  • 36
  • 72
4

Here's what I ended up with. This works for me if I import my script in the interpreter, and also if I execute it as a script:

import os
import sys

# Returns the directory the current script (or interpreter) is running in
def get_script_directory():
    path = os.path.realpath(sys.argv[0])
    if os.path.isdir(path):
        return path
    else:
        return os.path.dirname(path)
mpontillo
  • 13,559
  • 7
  • 62
  • 90
3

This is a pretty old thread but I've been having this problem when trying to save files into the current directory the script is in when running a python script from a cron job. getcwd() and a lot of the other path come up with your home directory.

to get an absolute path to the script i used

directory = os.path.abspath(os.path.dirname(__file__))

Ivo Flipse
  • 10,222
  • 18
  • 50
  • 63
James
  • 241
  • 3
  • 13
0

Try this:

def get_script_path(for_file = None):
    path = os.path.dirname(os.path.realpath(sys.argv[0] or 'something'))
    return path if not for_file else os.path.join(path, for_file)
AstroCB
  • 12,337
  • 20
  • 57
  • 73
Davious
  • 1,833
  • 2
  • 15
  • 16
0
import os
exec_filepath = os.path.realpath(__file__)
exec_dirpath = exec_filepath[0:len(exec_filepath)-len(os.path.basename(__file__))]
Stan
  • 4,169
  • 2
  • 31
  • 39