How can I find script's directory? [duplicate]
Asked Answered
C

12

681

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?

Crippling answered 8/2, 2011 at 15:14 Comment(6)
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.Phobe
@Rob - "print sys.argv[0]" on my web host only gives the filename, without the pathCrippling
@Rob - here's an excerpt from the linked article "os.getcwd() returns the current working directory."Crippling
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.Phobe
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.Keenankeene
@jfs ? duplicate of what article? Does the SO.UI allow you to specify the link when you mark something as a duplicate?Hoekstra
A
1087

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__)))
Acierate answered 19/2, 2012 at 16:10 Comment(12)
This won't work if you're running from inside an interpreter, since you'll get NameError: name '__file__' is not definedInebriety
@EhteshChoudhury What do you mean by running from inside an interpreterDetritus
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.Inebriety
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 interpreterForehead
@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.Friction
This answer is wrong. Use sys.path[0]Monkshood
Mike, how is it wrong? os.path.dirname(os.path.realpath(__file__)) == sys.path[0] They're identical.Gorham
Be careful of os.chdir() as well. Underneath, the behavior is equivalent to concatenating the current working directory with the relative path of __file__.Magavern
@Monkshood Can you explain better why the answer is wrong?Unstrained
SyntaxError: invalid syntaxPaxwax
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.Historiated
Would be useful to provide example on what to expect on an absolute path with an enough dept.Mistake
E
211

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

Emma answered 29/3, 2011 at 15:43 Comment(5)
@Paxwax 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 /.Vase
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.Scorecard
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.Domel
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.Saidee
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.Bewick
B
159

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.

Banyan answered 9/2, 2011 at 10:18 Comment(9)
+1 because the useful __file__ module attribute is not always defined.Inimitable
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.Loricate
@aiham: Good point. In fact this function is in my framework utils module :)Banyan
@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?Transarctic
Hum look at sys.argv[1:] ...Banyan
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.Hyonhyoscine
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.Schorl
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].Averi
Using the library pathlib, introduced in Python 3.4, the code becomes: return pathlib.Path(sys.argv[0]).resolve().parent. But usually, someone would like to point to a file in the same dir as the script, so the with_*() functions could be used, for instance with_name() . And the code could be pathlib.Path(sys.argv[0]).resolve().with_name("new_filename")Einkorn
C
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.

Convention answered 27/5, 2012 at 1:59 Comment(0)
T
19
import os,sys
# Store current working directory
pwd = os.path.dirname(__file__)
# Append current directory to the python path
sys.path.append(pwd)
Tractor answered 9/2, 2011 at 7:1 Comment(2)
This works great on my dev machine but doesn't work on my web host - I get '/'Crippling
Odd, do you have access to the apache conf files? Or is this a windows server?Tractor
C
12

Use os.path.abspath('')

Crippling answered 8/2, 2011 at 16:6 Comment(6)
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'),)Crippling
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.Saidee
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!Carminecarmita
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.Hettie
That is genius, helped to define the layout of folders based on how unittests were started(via pycharm or via console)Liponis
This actually is the same as os.getcwd(), so it's not exactly the same as os.path.dirname(__file__)Domel
S
9

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

os.path.realpath(__file__)
Steinway answered 20/9, 2011 at 15:38 Comment(0)
H
9
import os
script_dir = os.path.dirname(os.path.realpath(__file__)) + os.sep
Humfrid answered 2/2, 2012 at 22:42 Comment(0)
D
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)
Dempstor answered 13/8, 2014 at 17:57 Comment(0)
C
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__))

Condyloid answered 4/8, 2012 at 21:11 Comment(0)
S
0
import os
exec_filepath = os.path.realpath(__file__)
exec_dirpath = exec_filepath[0:len(exec_filepath)-len(os.path.basename(__file__))]
Stereograph answered 22/11, 2011 at 16:47 Comment(2)
Why not use os.path.dirname?Ofris
I didn't know about os.path.dirname, maybe that works also.Stereograph
F
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)
Flowing answered 20/9, 2014 at 13:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.