Reading file using relative path in python project
Relative paths are relative to current working directory.
If you do not your want your path to be, it must be absolute.
But there is an often used trick to build an absolute path from current script: use its __file__
special attribute:
from pathlib import Path
path = Path(__file__).parent / "../data/test.csv"
with path.open() as f:
test = list(csv.reader(f))
This requires python 3.4+ (for the pathlib module).
If you still need to support older versions, you can get the same result with:
import csv
import os.path
my_path = os.path.abspath(os.path.dirname(__file__))
path = os.path.join(my_path, "../data/test.csv")
with open(path) as f:
test = list(csv.reader(f))
[2020 edit: python3.4+ should now be the norm, so I moved the pathlib version inspired by jpyams' comment first]
Relative paths in Python
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.
How to refer to relative paths of resources when working with a code repository
Try to use a filename relative to the current files path. Example for './my_file':
fn = os.path.join(os.path.dirname(__file__), 'my_file')
In Python 3.4+ you can also use pathlib:
fn = pathlib.Path(__file__).parent / 'my_file'
Is there a way to read in files with a path that's relative to the repo and not contingent on where that file is saved on your computer?
I ended up answer my own question and figured out what I think is probably the easiest (in terms of the least number of lines of code) to do it.
When defining a path, '../', takes you back one directory. So the number of directories that you need to go back to means that you need to have the same amount of '../', at the beginning of the path.
In my case, I needed to go back to three directories.
df = pd.read_csv("../../datas/CompleteData/FULL_SF1.csv")
Link to a similar answer: https://stackoverflow.com/a/43600253/14735826
Relative address in python
My Project
some_file.py
Resources
bg.png
music.mp3
Folder
another_file.py
If you want to access your resources from some_file.py, the relative path would be ./Resources/...
but if you want to use resources from another_file.py you would do ../Resources/...
.
So in your case if you want to access ENV file from test1.py, its relative location would be ./config/ENV
, but if you want to access it from test2.py, its relative location would be ../../config/ENV
.
Remember ../
means going up one level and ./
means the same level.
Edits:
Here you've the fixed path config/ENV
. Passing that fixed path in relative_path()
gives you the relative path address.
# proj
# config
# ENV
#
# folder1
# config
# some_other_file.txt
#
# UI
# test2.py
#
# test1.py
import os
def relative_path(path):
# Get the parent directory of the
# file that you need the relative
# path for.
my_dir = path.split('/')[0]
# Recursively match the directory
# in the given path. if the match
# not found go up one level.
def match_dir(c_path):
c_path = os.path.split(c_path)[0]
if my_dir in os.listdir(c_path) and (
os.path.isfile(
os.path.join(c_path, path)
)
):
# this whole if-block can be omitted
# if the folder you're trying to access
# is on the same level, this just prepends
# with './'. I added this just for
# aesthetic reason.
if os.path.basename(__file__) in os.listdir(c_path):
return './' + path
return path
return "../" + match_dir(c_path)
return match_dir(
os.path.realpath(__file__)
)
# Getting relative path from test2.py
print(relative_path("config/ENV"))
print(relative_path("config/some_other_file.txt"))
# Try running this from test1.py
print(relative_path("config/ENV")) # './config/ENV'
This isn't very much optimized. Just a general idea.
Related Topics
Replace Values in List Using Python
Importing Variables from Another File
Python Selenium Click on Button
Get Md5 Hash of Big Files in Python
Matplotlib Plots: Removing Axis, Legends and White Spaces
Python's Most Efficient Way to Choose Longest String in List
How to Get a Value of Datetime.Today() in Python That Is "Timezone Aware"
Pandas Dataframe: Replace Nan Values with Average of Columns
How to Zip Two Differently Sized Lists, Repeating the Shorter List
Convert Pandas.Series from Dtype Object to Float, and Errors to Nans
Why Do Integers in Database Row Tuple Have an 'L' Suffix
Making a String Out of a String and an Integer in Python
Find Shortest Matches Between Two Strings
How to Write a Python Module/Package