[python] Relative paths in Python

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?

This question is related to python relative-path path

The answer is


It's 2018 now, and Python have already evolve 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 script
  • src_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 it's relative path to the mod_path.

Now let's solve this with the 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 just that simple. :D


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)

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'

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, '../')

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


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.


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


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"


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)


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.


From what suggest others and from pathlib documentation, a simple and clear solution is the following (suppose the file we need to refer to: Test/data/users.csv:

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

Now this looks a bit odd to me, because if you move some_script.py around, the path to the root of our project may change (we would need to modify parents[4]). On the other hand I found a solution that I prefer based on the same idea.

Suppose we have the following directory structure:

Tests
+-- data
¦  +-- users.csv
+-- src
   +-- long
   ¦  +-- module
   ¦     +-- subdir
   ¦        +-- some_script.py
   +-- main.py
   +-- paths.py

The paths.py file will be responsible for storing the root location of our projet:

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

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

A simple solution would be

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

An alternative which works for me:

this_dir = os.path.dirname(__file__) 
filename = os.path.realpath("{0}/relative/file.path".format(this_dir))

you need os.path.realpath (sample below adds the parent directory to your path)

import sys,os
sys.path.append(os.path.realpath('..'))

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)

Examples related to python

programming a servo thru a barometer Is there a way to view two blocks of code from the same file simultaneously in Sublime Text? python variable NameError Why my regexp for hyphenated words doesn't work? Comparing a variable with a string python not working when redirecting from bash script is it possible to add colors to python output? Get Public URL for File - Google Cloud Storage - App Engine (Python) Real time face detection OpenCV, Python xlrd.biffh.XLRDError: Excel xlsx file; not supported Could not load dynamic library 'cudart64_101.dll' on tensorflow CPU-only installation

Examples related to relative-path

webpack: Module not found: Error: Can't resolve (with relative path) Reading file using relative path in python project How to import a CSS file in a React Component How to open my files in data_folder with pandas using relative path? Relative path in HTML Failed to load resource: the server responded with a status of 404 (Not Found) How does Java resolve a relative path in new File()? relative path in BAT script How to define a relative path in java Relative imports for the billionth time

Examples related to path

Get Path from another app (WhatsApp) How to serve up images in Angular2? How to create multiple output paths in Webpack config Setting the correct PATH for Eclipse How to change the Jupyter start-up folder Setting up enviromental variables in Windows 10 to use java and javac How do I edit $PATH (.bash_profile) on OSX? Can't find SDK folder inside Android studio path, and SDK manager not opening Get the directory from a file path in java (android) Graphviz's executables are not found (Python 3.4)