How to normalize a relative path using pathlib - python

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:\projects\code
I want to read this file which is one level up:
G:\projects\data\sales.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.

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

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:\Users\isik\Desktop\Python\MessAround\project\module
C:\Users\isik\Desktop\Python\MessAround\project
C:\Users\isik\Desktop\Python\MessAround\project\hello.py
with this file structure
-project
-module
-__init__.py
-hello.py
-__init__.py
while the code is located inside project.module.__init__.py

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

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.

Related

How to get the full path of a file in python including the subdirectory?

I tried every method, but it simply doesn't work. I have a file that is within a subdirectory and that subdirectory lies within a directory. Calling something like
os.path.abspath(__file__))
only yields
directory\\file
but I need
directory\\subdirectory\\file
There should be an easy way to do this, right? I have no idea why abspath doesn't recognize the subdirectory.
from pathlib import Path
my_path = Path("my_file.txt")
full_path = Path.resolve()
Then you can convert full_path to a string if you need it as such.
You should look at the pathlib module

Python folder paths on synched pcs

I use .py files on two different pcs and synch the files using google drive.
As I handle files quite often with subfolders I use the complete path to read csv
passport = pd.read_csv(r'C:\Users\turbo\Google Drive\Studium\Master_thesis\Python\Databases\passport_uzb.csv')
However, when switching pcs I have to change the path manually since for my second pc its:
C:\Users\turbo\My Drive\Studium\Master_thesis\Python\Databases
so the only difference really is 'Google Drive' =/= 'My Drive'
Is there a work around using the complete filepath to read files?
You can use a relative path to access the CSV instead of an absolute one. The pathlib module is useful for this. For example, assuming your script is directly inside the ...Python/Databases folder, you can compute the path to the CSV like so, using the __file__ module attribute:
from pathlib import Path
# this is a path object that always refers to the script in which it is defined
this_file = Path(__file__).resolve()
# this path refers to .../Python/Databases, no matter where it is located
this_folder = this_file.parent
csv_path = this_folder / "passport_uzb.csv"
passport = pd.read_csv(csv_path)
Edit: no matter where your script is located, you can use some combination of .parent and / "child" to construct a relative path that will work. If your script is in ...Python/Databases/nasapower then simply add another .parent:
this_file = Path(__file__).resolve()
nasapower_folder = this_file.parent
databases_folder = nasapower_folder.parent
Or you can use the .parents sequence to get there faster:
databases_folder = Path(__file__).resolve().parents[1]
Likewise, for the output folder:
output_folder = Path(__file__).resolve().parent / "json"

How to use pathlib to process paths that begin with ~?

I am writing a cli-tool that needs some path as input.
I am writing this tool in python and would like to use no python interpreter below 3.6. Using the packagepathlibseems to be the modern way to go when dealing with paths in python. So I would like to leave os and os.path behind if possible.
It seems like pathlib interprets the path ~/test/ as a relative path to the current working directory, the code below shows it
import pathlib
test_path = pathlib.Path('~/test')
absolute_path = test_path.absolute()
print(f"{str(test_path):>31}\n{str(absolute_path):>31}")
# output:
# ~/test
# /home/myUser/~/test
How can I use pathlib to recognize every path starting with ~ as an absolute path and automatically expand ~ into the users home directory?
The answer is easy, use .expanduser() on your Path object instead of .absolute()and it will replace ~ with the home directory of the user running the script, the result is also an absolute path only if ~ is at the beginning:
import pathlib
test_path = pathlib.Path('~/test')
absolute_path = test_path.expanduser()
# If ~ is somewhere in the middle of the path, use .resolve() to get an absolute path.
print(f"{str(test_path):>31}\n{str(absolute_path):>31}")
# output:
# ~/test
# /home/myUser/test

How to display a variable without a specific part?

So, i have a variable, for example dir = "Crypter.aes". I need to variable like dir, but without .aes. What gotta I do for that? I use directory parser, that make many dir with file name in that directory, and for each file I need to remove a certain part at the end - .aes
This is a task for the os.path module in the standard library.
import os.path
dir, _ = os.path.splitext("Crypter.aes")
If you're working a lot with file paths, you also might want to take a look at the pathlib module.
from pathlib import Path
dir = Path("Crypter.aes").stem

os.path moving through directories

i have this structure in my code.
app
src
script.py
data
data.ptk
i need to open the file "data.ptk" from "scrip.py", using os.path i'm able to extract the script path.
my_path = os.path.abspath(os.path.dirname(__file__))
But flowing the structure i need to go back 2 directories and then enter the "data" directory to open the file.
The easy way would be to decompose the string my_path with a split("/"), remove the last 2 words and add "data" ...
But I do not think it's the right way
The script.py need to be independent of the OS, that is the reason i'm not able to "hard code" the directory where de pkl file is placed
Any suggestions? thanks.
To elaborate on my comment more, you can see the documentation for pathlib here: https://docs.python.org/3/library/pathlib.html?highlight=pathlib#module-pathlib. It is a stock part of python3 (not sure about python2). I think the following would work:
from pathlib import Path
scriptPath = Path(__file__).absolute() # the absolute() is not strictly necessary
srcPath = scriptPath.parent
appPath = srcPath.parent
commonDirectory = appPath.parent # this could have been shortened with scriptPath.parent.parent.parent
dataPath = commonDirectory / 'data'
dtkFile = dataPath / 'data.ptk'

Categories

Resources