How to normalize a relative path using pathlib
Question:
I’m trying to use relative paths in Python, and I want to put my csv files in a separate folder from my python code.
My python program is in the following folder:
G:projectscode
I want to read this file which is one level up:
G:projectsdatasales.csv
How do I specify a path using pathlib that is one level up from my current working folder? I don’t want to change the current working folder.
I tried this:
from pathlib import Path
file = Path.cwd() /'..'/'data'/'sales.csv'
But now the ‘file’ variable equals this:
'G:/projects/code/../data/sales.csv'
I read through the docs and either it isn’t explained there or I’m just missing it.
Answers:
Do you mean “read my csv files”?
The import
keyword has a different meaning in Python (you import only other Python modules).
In any case, in order to read a file located one folder above your Python file, you can use this:
import os
filePath = os.path.dirname(__file__)+'/../'+fileName
fileDesc = open(filePath)
fileData = fileDesc.read()
fileDesc.close()
...
print(
Path(__file__).parent, # the folder
Path(__file__).parent.parent, # the folder's parent
sep='n'
)
print(
Path(
Path(__file__).parent.parent, 'hello.py'
)
)
results in
C:UsersisikDesktopPythonMessAroundprojectmodule
C:UsersisikDesktopPythonMessAroundproject
C:UsersisikDesktopPythonMessAroundprojecthello.py
with this file structure
-project
-module
-__init__.py
-hello.py
-__init__.py
while the code is located inside project.module.__init__.py
Although it’s not a problem that your path includes ‘..’ (you can still use this path to open files, etc. in Python), you can normalize the path using resolve()
:
from pathlib import Path
path = Path.cwd() / '..' / 'data' / 'sales.csv'
print(path) # WindowsPath('G:/projects/code/../data/sales.csv')
print(path.resolve()) # WindowsPath('G:/projects/data/sales.csv')
NB: I personally would name a variable that contains a path path
, not file
. So you could later on do file = open(path)
.
here is an example I used:
import json
from pathlib import Path
def read_files(folder_name, file_name):
base_path = Path.cwd().joinpath('configs','resources')
path = base_path.joinpath(folder_name,file_name)
open_file = open(path,'r')
return json.load(open_file.read())
This is pretty old, but I happened on it looking for something else.
Oddly you never got a direct, obvious, answer — you want the parent
property:
from pathlib import Path
file = Path.cwd().parent / 'data' / 'sales.csv'
Note that some of the answers that say you want __file__
rather than the current working directory may be correct (depending on your use case), in which case it’s:
from pathlib import Path
file = Path(__file__).parent.parent / 'data' / 'sales.csv'
(parent of the python file is the code dir, parent of that is the projects dir.
However, It’s not great practice to refer to your data by its relative path to your code — I think using the cwd is a better option — though what you should do is pass the path to the data in to the script via sys.argv
.
I’m trying to use relative paths in Python, and I want to put my csv files in a separate folder from my python code.
My python program is in the following folder:
G:projectscode
I want to read this file which is one level up:
G:projectsdatasales.csv
How do I specify a path using pathlib that is one level up from my current working folder? I don’t want to change the current working folder.
I tried this:
from pathlib import Path
file = Path.cwd() /'..'/'data'/'sales.csv'
But now the ‘file’ variable equals this:
'G:/projects/code/../data/sales.csv'
I read through the docs and either it isn’t explained there or I’m just missing it.
Do you mean “read my csv files”?
The import
keyword has a different meaning in Python (you import only other Python modules).
In any case, in order to read a file located one folder above your Python file, you can use this:
import os
filePath = os.path.dirname(__file__)+'/../'+fileName
fileDesc = open(filePath)
fileData = fileDesc.read()
fileDesc.close()
...
print(
Path(__file__).parent, # the folder
Path(__file__).parent.parent, # the folder's parent
sep='n'
)
print(
Path(
Path(__file__).parent.parent, 'hello.py'
)
)
results in
C:UsersisikDesktopPythonMessAroundprojectmodule
C:UsersisikDesktopPythonMessAroundproject
C:UsersisikDesktopPythonMessAroundprojecthello.py
with this file structure
-project
-module
-__init__.py
-hello.py
-__init__.py
while the code is located inside project.module.__init__.py
Although it’s not a problem that your path includes ‘..’ (you can still use this path to open files, etc. in Python), you can normalize the path using resolve()
:
from pathlib import Path
path = Path.cwd() / '..' / 'data' / 'sales.csv'
print(path) # WindowsPath('G:/projects/code/../data/sales.csv')
print(path.resolve()) # WindowsPath('G:/projects/data/sales.csv')
NB: I personally would name a variable that contains a path path
, not file
. So you could later on do file = open(path)
.
here is an example I used:
import json
from pathlib import Path
def read_files(folder_name, file_name):
base_path = Path.cwd().joinpath('configs','resources')
path = base_path.joinpath(folder_name,file_name)
open_file = open(path,'r')
return json.load(open_file.read())
This is pretty old, but I happened on it looking for something else.
Oddly you never got a direct, obvious, answer — you want the parent
property:
from pathlib import Path
file = Path.cwd().parent / 'data' / 'sales.csv'
Note that some of the answers that say you want __file__
rather than the current working directory may be correct (depending on your use case), in which case it’s:
from pathlib import Path
file = Path(__file__).parent.parent / 'data' / 'sales.csv'
(parent of the python file is the code dir, parent of that is the projects dir.
However, It’s not great practice to refer to your data by its relative path to your code — I think using the cwd is a better option — though what you should do is pass the path to the data in to the script via sys.argv
.