I'm building a simple helper script for work that will copy a couple of template files in our code base to the current directory. I don't, however, have the absolute path to the directory where the templates are stored. I do have a relative path from the script but when I call the script it treats that as a path relative to the current working directory. Is there a way to specify that this relative url is from the location of the script instead?
-
1Similar questions: https://stackoverflow.com/questions/51520/how-to-get-an-absolute-file-path-in-python https://stackoverflow.com/questions/7165749/open-file-in-a-relative-location-in-python https://stackoverflow.com/questions/3561691/python-syntaxerror-eol-while-scanning-string-literal – Raj Oct 12 '17 at 21:24
-
See also [What exactly is current working directory?](https://stackoverflow.com/questions/45591428/what-exactly-is-current-working-directory) – tripleee Sep 01 '21 at 04:49
-
The (only) answer below using pathlib (instead of os) [is here](https://stackoverflow.com/a/36906785/6069586) – JWCS Jan 27 '22 at 18:05
-
2@JWCS Did you mean [here](https://stackoverflow.com/a/51149057/1707427)? – Sören Apr 30 '22 at 18:55
-
@Raj the last one isn't similar at all. – Karl Knechtel Sep 04 '22 at 00:51
21 Answers
In the file that has the script, you want to do something like this:
import os
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')
This will give you the absolute path to the file you're looking for. Note that if you're using setuptools, you should probably use its package resources API instead.
UPDATE: I'm responding to a comment here so I can paste a code sample. :-)
Am I correct in thinking that
__file__
is not always available (e.g. when you run the file directly rather than importing it)?
I'm assuming you mean the __main__
script when you mention running the file directly. If so, that doesn't appear to be the case on my system (python 2.5.1 on OS X 10.5.7):
#foo.py
import os
print os.getcwd()
print __file__
#in the interactive interpreter
>>> import foo
/Users/jason
foo.py
#and finally, at the shell:
~ % python foo.py
/Users/jason
foo.py
However, I do know that there are some quirks with __file__
on C extensions. For example, I can do this on my Mac:
>>> import collections #note that collections is a C extension in Python 2.5
>>> collections.__file__
'/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-
dynload/collections.so'
However, this raises an exception on my Windows machine.

- 1,048,767
- 296
- 4,058
- 3,343

- 192,085
- 135
- 376
- 510
-
1Am I correct in thinking that __file__ is not always available (e.g. when you run the file directly rather than importing it)? – Stephen Edmonds May 28 '09 at 12:43
-
@Stephen Edmonds I'm using it a file that I run, rather than import, and it works great. – baudtack Jun 04 '09 at 03:37
-
27Note you should use os.path.join everywhere for portability: `filename = os.path.join(dir, 'relative', 'path', 'to', 'file', 'you' , 'want')` – ford Feb 06 '14 at 17:51
-
34`os.path.dirname(__file__)` can give an empty string, use `os.path.dirname(os.path.abspath(__file__))` instead – Dmitry Trofimov Mar 10 '15 at 22:03
-
22It's a minor thing, but PLEASE don't use dir as a variable name since it is a builtin. – David Jul 14 '15 at 19:18
-
-
This is a good solution, but it won't work unless you take Dimitry Troflimov's comment, please updated your answer to reflect that. os.path.dirname(os.path.abspath(__file__)). This is an issue I had in both Ubuntu 20.0.4 and MacOS – Amro Younes Mar 29 '21 at 14:19
-
@DmitryTrofimov If we omit the os.path.abspath, we still get a valid *relative* path from the working directory, correct? – Duncan MacIntyre Jul 30 '21 at 05:51
-
-
@Julien The special variable `__file__` contains the path (directory + file name) of the currently running script. Note that `__file__` can fail and should be replaced by `inspect.getfile(inspect.currentframe())` (after `import inspect`): https://stackoverflow.com/a/6098238/1386750 – AstroFloyd Aug 14 '22 at 06:36
-
It's 2018 now, and Python has already evolved to the __future__
long time ago. So how about using the amazing pathlib
coming with Python 3.4 to accomplish the task instead of struggling with os
, os.path
, glob
, shutil
, etc.
So we have 3 paths here (possibly duplicated):
mod_path
: which is the path of the simple helper scriptsrc_path
: which contains a couple of template files waiting to be copied.cwd
: current directory, the destination of those template files.
and the problem is: we don't have the full path of src_path
, only know its relative path to the mod_path
.
Now let's solve this with the amazing pathlib
:
# Hope you don't be imprisoned by legacy Python code :)
from pathlib import Path
# `cwd`: current directory is straightforward
cwd = Path.cwd()
# `mod_path`: According to the accepted answer and combine with future power
# if we are in the `helper_script.py`
mod_path = Path(__file__).parent
# OR if we are `import helper_script`
mod_path = Path(helper_script.__file__).parent
# `src_path`: with the future power, it's just so straightforward
relative_path_1 = 'same/parent/with/helper/script/'
relative_path_2 = '../../or/any/level/up/'
src_path_1 = (mod_path / relative_path_1).resolve()
src_path_2 = (mod_path / relative_path_2).resolve()
In the future, it's just that simple.
Moreover, we can select and check and copy/move those template files with pathlib
:
if src_path != cwd:
# When we have different types of files in the `src_path`
for template_path in src_path.glob('*.ini'):
fname = template_path.name
target = cwd / fname
if not target.exists():
# This is the COPY action
with target.open(mode='wb') as fd:
fd.write(template_path.read_bytes())
# If we want MOVE action, we could use:
# template_path.replace(target)

- 23,933
- 14
- 88
- 109

- 16,128
- 9
- 76
- 72
-
9In summary: `from pathlib import Path` `script_dir=Path(__file__).parent` `template_path=(script_dir / template_name).resolve()` – a113nw Jun 30 '20 at 15:06
-
1@4myle: resolve the `__file__` path _first_, for scripts it is possibly the relative path given to the interpreter. So `script_dir = Path(__file__).resolve().parent`. From there on out `script_dir` is absolute, and everything else can be built on top of that. Further `resolve()` calls are only needed if you need to resolve symlinks. – Martijn Pieters Aug 17 '21 at 13:12
-
Then again, since the __past__, `__file__` can fail and should not be used. Instead, use `~inspect.getfile(inspect.currentframe())` (after `import inspect`): https://stackoverflow.com/a/6098238/1386750 – AstroFloyd Aug 14 '22 at 06:06
you need os.path.realpath
(sample below adds the parent directory to your path)
import sys,os
sys.path.append(os.path.realpath('..'))

- 1,686
- 3
- 16
- 20
-
3`os.path.dirname(__file__)` gave me an empty string. This worked perfectly. – Darragh Enright Feb 21 '14 at 10:51
-
5This seems to give the parent of the directory the script is run from, not of the script's location. – Coquelicot Jul 17 '17 at 03:50
-
25`os.path.realpath('..')` gives you the parent directory of the **current working dir**. That's usually **not** what you want. – Martijn Pieters May 12 '18 at 18:55
-
1@DarraghEnright: That only happens in a Python-script-to-exe packaging environment. That's one of the rare exceptions where relying on the current working dir would be the alternative. – Martijn Pieters May 12 '18 at 18:56
As mentioned in the accepted answer
import os
dir = os.path.dirname(__file__)
filename = os.path.join(dir, '/relative/path/to/file/you/want')
I just want to add that
the latter string can't begin with the backslash , infact no string should include a backslash
It should be something like
import os
dir = os.path.dirname(__file__)
filename = os.path.join(dir, 'relative','path','to','file','you','want')
The accepted answer can be misleading in some cases , please refer to this link for details
-
4Yes using `os.path.join` is better because it joins them with the OS-specific separator. – Farshid T Sep 04 '16 at 09:16
-
1
-
3This answer is now outdated, as the top answer has been edited to use a proper relative path in `os.path.join()`. What is left is the preference to use separate strings for each path element over hardcoding the path separator. – Martijn Pieters May 12 '18 at 18:57
-
1@MartijnPieters Yes, the top answer has been edited to match this in part, but the separate strings is not a preference - separating the stings like this makes it os-independent. – jshrimp29 Jul 03 '19 at 22:39
Consider my code:
import os
def readFile(filename):
filehandle = open(filename)
print filehandle.read()
filehandle.close()
fileDir = os.path.dirname(os.path.realpath('__file__'))
print fileDir
#For accessing the file in the same folder
filename = "same.txt"
readFile(filename)
#For accessing the file in a folder contained in the current folder
filename = os.path.join(fileDir, 'Folder1.1/same.txt')
readFile(filename)
#For accessing the file in the parent folder of the current folder
filename = os.path.join(fileDir, '../same.txt')
readFile(filename)
#For accessing the file inside a sibling folder.
filename = os.path.join(fileDir, '../Folder2/same.txt')
filename = os.path.abspath(os.path.realpath(filename))
print filename
readFile(filename)

- 689
- 6
- 5
-
When I run this in windows, I recieve an error: FileNotFoundError: [Errno 2] No such file or directory: '
' where – lonstar Jul 24 '19 at 05:09has the correct path segments but uses \\ for separators. -
i was able to get a relative path by using ```filename = os.path.abspath('../Folder2/same.txt')``` – Nicholas_Jones Jun 12 '21 at 00:00
See sys.path 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.
Use this path as the root folder from which you apply your relative path
>>> import sys
>>> import os.path
>>> sys.path[0]
'C:\\Python25\\Lib\\idlelib'
>>> os.path.relpath(sys.path[0], "path_to_libs") # if you have python 2.6
>>> os.path.join(sys.path[0], "path_to_libs")
'C:\\Python25\\Lib\\idlelib\\path_to_libs'

- 18,473
- 7
- 40
- 62
-
3That's not necessarily true. Usually sys.path[0] is an empty string or a dot, which is a relative path to the current directory. If you want the current directory, use os.getcwd. – Jason Baker May 27 '09 at 21:54
-
The original poster commented that the current working directory is the wrong place to base the relative path from. You are correct in saying that sys.path[0] is not always valid. – Tom Leys May 28 '09 at 00:56
-
No, `sys.path[0]` is not always set to the parent directory. Python code can be invoked with `-c` or `-m` or via an embedded interpreter, at which point `sys.path[0]` is set to something different altogether. – Martijn Pieters May 12 '18 at 18:58
Instead of using
import os
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')
as in the accepted answer, it would be more robust to use:
import inspect
import os
dirname = os.path.dirname(os.path.abspath(inspect.stack()[0][1]))
filename = os.path.join(dirname, 'relative/path/to/file/you/want')
because using __file__ will return the file from which the module was loaded, if it was loaded from a file, so if the file with the script is called from elsewhere, the directory returned will not be correct.
These answers give more detail: https://stackoverflow.com/a/31867043/5542253 and https://stackoverflow.com/a/50502/5542253

- 1,048,767
- 296
- 4,058
- 3,343

- 773
- 12
- 30
-
5`inspect.stack()` is an *expensive* function to call. It retrieves info for all stack frames, which you then discard and only get the top one for. It basically calls `inspect.getfile()` on the module object, which just returns `module.__file__`. You are far better of just using `__file__`. – Martijn Pieters May 12 '18 at 19:05
From what suggest others and from pathlib documentation, a simple (but not ideal) solution is the following (suppose the file we need to refer to is Test/data/users.csv
):
# Current file location: Tests/src/long/module/subdir/some_script.py
from pathlib import Path
# back to Tests/
PROJECT_ROOT = Path(__file__).parents[4]
# then down to Test/data/users.csv
CSV_USERS_PATH = PROJECT_ROOT / 'data' / 'users.csv'
with CSV_USERS_PATH.open() as users:
print(users.read())
This works but looks a bit odd because if you move some_script.py
around, the path to the root of our project may change (and we would therefore need to change the parents[4]
part).
I think I found a better solution that, based on the same idea.
We will use a file paths.py
to store where the root of the project is, this file will remain at the same location compared to the root directory.
Tests
├── data
│ └── users.csv
└── src
├── long
│ └── module
│ └── subdir
│ └── some_script.py
├── main.py
└── paths.py
Where paths.py
's only responsability is to provide PROJECT_ROOT
:
from pathlib import Path
PROJECT_ROOT = Path(__file__).parents[1]
All scripts can now use paths.PROJECT_ROOT
to express absolute paths from the root of the project. For example in src/long/module/subdir/some_script.py
we could have:
from paths import PROJECT_ROOT
CSV_USERS_PATH = PROJECT_ROOT / 'data' / 'users.csv'
def hello():
with CSV_USERS_PATH.open() as f:
print(f.read())
And everything goes as expected:
~/Tests/src/$ python main.py
/Users/cglacet/Tests/data/users.csv
hello, user
~/Tests/$ python src/main.py
/Users/cglacet/Tests/data/users.csv
hello, user
The main.py
script simply is:
from long.module.subdir import some_script
some_script.hello()

- 8,873
- 4
- 45
- 60
summary of the most important commands
>>> import os
>>> os.path.join('/home/user/tmp', 'subfolder')
'/home/user/tmp/subfolder'
>>> os.path.normpath('/home/user/tmp/../test/..')
'/home/user'
>>> os.path.relpath('/home/user/tmp', '/home/user')
'tmp'
>>> os.path.isabs('/home/user/tmp')
True
>>> os.path.isabs('/tmp')
True
>>> os.path.isabs('tmp')
False
>>> os.path.isabs('./../tmp')
False
>>> os.path.realpath('/home/user/tmp/../test/..') # follows symbolic links
'/home/user'
A detailed description is found in the docs. These are linux paths. Windows should work analogous.

- 9,341
- 4
- 63
- 58
Hi first of all you should understand functions os.path.abspath(path) and os.path.relpath(path)
In short os.path.abspath(path) makes a relative path to absolute path. And if the path provided is itself a absolute path then the function returns the same path.
similarly os.path.relpath(path) makes a absolute path to relative path. And if the path provided is itself a relative path then the function returns the same path.
Below example can let you understand the above concept properly:
suppose i have a file input_file_list.txt which contains list of input files to be processed by my python script.
D:\conc\input1.dic
D:\conc\input2.dic
D:\Copyioconc\input_file_list.txt
If you see above folder structure, input_file_list.txt is present in Copyofconc folder and the files to be processed by the python script are present in conc folder
But the content of the file input_file_list.txt is as shown below:
..\conc\input1.dic
..\conc\input2.dic
And my python script is present in D: drive.
And the relative path provided in the input_file_list.txt file are relative to the path of input_file_list.txt file.
So when python script shall executed the current working directory (use os.getcwd() to get the path)
As my relative path is relative to input_file_list.txt, that is "D:\Copyofconc", i have to change the current working directory to "D:\Copyofconc".
So i have to use os.chdir('D:\Copyofconc'), so the current working directory shall be "D:\Copyofconc".
Now to get the files input1.dic and input2.dic, i will read the lines "..\conc\input1.dic" then shall use the command
input1_path= os.path.abspath('..\conc\input1.dic') (to change relative path to absolute path. Here as current working directory is "D:\Copyofconc", the file ".\conc\input1.dic" shall be accessed relative to "D:\Copyofconc")
so input1_path shall be "D:\conc\input1.dic"

- 51
- 5
This code will return the absolute path to the main script.
import os
def whereAmI():
return os.path.dirname(os.path.realpath(__import__("__main__").__file__))
This will work even in a module.

- 378
- 3
- 11
-
Instead of re-importing, you'd use `sys.modules['__main__'].__file__`. – Martijn Pieters May 12 '18 at 19:05
An alternative which works for me:
this_dir = os.path.dirname(__file__)
filename = os.path.realpath("{0}/relative/file.path".format(this_dir))

- 4,337
- 5
- 24
- 40
Example
Here's an example, tested in Python '3.9.5`:
your current directory: 'c:\project1\code\'
and you want to access the following folder: 'c:\project1\dataset\train\'
.
Then you can access the folder using the following address: '../dataset/train/'
References
If you want some more information about path in Python
, read this:

- 51
- 5
What worked for me is using sys.path.insert
. Then I specified the directory I needed to go. For example I just needed to go up one directory.
import sys
sys.path.insert(0, '../')

- 3,882
- 7
- 48
- 78
-
2This relies on the current working directory, which could be radically different from what you actually want. – Martijn Pieters May 12 '18 at 19:06
I think to work with all systems use "ntpath" instead of "os.path". Today, it works well with Windows, Linux and Mac OSX.
import ntpath
import os
dirname = ntpath.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

- 116
- 6
From C:\Users\xyz\myFolder
to C:\Users\xyz\testdata
:
import os
working_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
# C:\Users\xyz\myFolder
print(working_dir)
updated_working_dir = os.path.join(os.path.realpath(working_dir + '/../'), 'testdata')
# C:\Users\xyz\testdata
print(updated_working_dir)
Output
C:\Users\xyz\myFolder
C:\Users\xyz\testdata

- 1,864
- 21
- 23
Here is my sumup:
First, define the tool function named relpath
, which convert a relative path to current file into a relative path to cwd
import os
relpath = lambda p: os.path.normpath(os.path.join(os.path.dirname(__file__), p))
Then we use it to wrap paths which is relative to current file
path1 = relpath('../src/main.py')
And you can also call sys.path.append()
to import file relative to current file position
sys.path.append(relpath('..')) # so that you can import from upper dir
The full example code : https://gist.github.com/luochen1990/9b1ffa30f5c4a721dab5991e040e3eb1

- 3,689
- 1
- 22
- 37
Say the current archive named "Helper" and the upper directory named "Workshop", and the template files are in \Workshop\Templates, then the relative path in Python is "..\Templates".

- 81
- 4
This a simple way to add a relative path to the system path set . For example, for frequent case when the target directory is one level above (thus, '/../'
) the working directory:
import os
import sys
workingDir = os.getcwd()
targetDir = os.path.join(os.path.relpath(workingDir + '/../'),'target_directory')
sys.path.insert(0,targetDir)
This solution was tested for:
Python 3.9.6 | packaged by conda-forge | (default, Jul 11 2021, 03:37:25) [MSC v.1916 64 bit (AMD64)]

- 47
- 1
- 8
I'm not sure if this applies to some of the older versions, but I believe Python 3.3 has native relative path support.
For example the following code should create a text file in the same folder as the python script:
open("text_file_name.txt", "w+t")
(note that there shouldn't be a forward or backslash at the beginning if it's a relative path)

- 1,285
- 12
- 27
-
right, so this will work from the CWD which is not what the OP asks for. The want to work from the scripts location. – Samie Bencherif Dec 06 '18 at 01:37