How Python manages relative path - python

I can't find out how to find a relative path in Python. The code only allows me to use the absolute path.
What I want
config = configparser.ConfigParser()
config.read('..\\main.ini',)
print(config.sections())
FilePaths = config['data']
DictionaryFilePath = FilePaths['DictionaryFilePath']
print(DictionaryFilePath)
what it forces me to do
config = configparser.ConfigParser()
config.read('C:\\Users\\***confendential***\\OneDrive\\文档\\Python\\Chinese for practice\\ChineseWords\\app\\main.ini',)
print(config.sections())
FilePaths = config['data']
DictionaryFilePath = FilePaths['DictionaryFilePath']
print(DictionaryFilePath)
Any Ideas???
Is it Onedrive?

There are already some answers that cover this here, for example.
To summarise, if you just do
config.read('..\\main.ini',)
then your program expects a file, main.ini to be located in the parent directory of wherever you executed the program from.
What you usually want is to specify a path relative to the location of the file that is executing.
You can get the path to that file with __file__ and then manipulate it with the os.path module (see this answer)
In your case, assuming that your main.ini is in the parent directory of the script you are running,you could do
inifile = os.path.join(os.path.dirname(os.path.dirname(__file__)), "main.ini")
config.read(inifile)
Another thing to note in your case, is it could be useful to actually check that the ini file is loaded. If the file is not found it just returns an empty object, so you can check this and print a message or error.
Hope this is helpful. The other linked answers give some more useful info on these ideas.

I think it is just the onedrive. It is forcing you to use a strait forward path

Related

Convert a relative path (mp3) from a master file path (playlist) using python pathlib

I have three files
My python file running in an unimportant different folder: C:\DD\CC\BB\AA\code.py
A playlist file "C:\ZZ\XX\Playlist.pls" which points to ....\mp3\song.mp3
The C:\mp3\song.mp3 file.
What I want is to get the location of the mp3 as an absolute path. But every attemp I try I get everything related to whenever the code.py file is.
import pathlib
plMaster = pathlib.Path(r"C:\ZZ\XX\Playlist.pls")
plSlave = pathlib.Path(r"..\..\mp3\song.mp3")
I have tried plSlave.absolute() and gives me "C:\DD\CC\BB\AA....\mp3\song.mp3"
Using relative_to doesn't work. I feel like I am doing such an easy task but I must be missing something because I can't find any function that lets me set the reference to compute the relative path.
Note: I already have parsed the pls file, and have the string r"....\mp3\song.mp3" extracted. I just need to get the path "C:\mp3\song.mp3" knowing that they are relative to the pls. (Not relative to the code.py)
If you're using a Windows version of Python, this is fairly easy. You can join the directory of plMaster (plMaster.parent) with the relative path of plSlave, then resolve the path using resolve(). You can use strict=False to force the resolve even if the path components aren't found.
This worked for me:
>>> plMaster = pathlib.Path(r"C:\ZZ\XX\Playlist.pls")
>>> plSlave = pathlib.Path(r"..\..\mp3\song.mp3")
>>> plMaster.parent.joinpath(plSlave).resolve(strict=False)
WindowsPath('C:/mp3/song.mp3')
If you're on a Unix version of Python, using Windows paths, I couldn't get this to work no matter what I tried, even using pathlib.PureWindowsPath().
Might well be a better method here, but you can use pathlib.Path.parents and pathlib.Path.parts to extract some useful info here and get where you are going
new_relative_path = r"..\..\mp3\song.mp3" #however you got this from reading your .pls file or whatever
pls_path = pathlib.Path(r'C:\ZZ\XX\Playlist.pls')
relative_save = pathlib.Path(new_relativePath)
n = relative_save.parts.count('..')
new_path = pls_path.parents[n-1].joinpath(*relative_save.parts[n:])
The key thing here is that you are going to navigate up the original path (the pls_path) n times (so n-1 since we start at 0), and then you are going to append to that whatever your new relative path is, stripping the '..' segments from the beginning of it.
Whilst I was waiting for other answers I manage to figure it out ditching pathlib and using os instead.
import os
plMaster = r"C:\ZZ\XX\Playlist.pls"
plSlave = r"..\..\mp3\song.mp3"
os.chdir(os.path.dirname(plMaster))
os.path.abspath(plSlave)

Accessing networked file locations with pathlib

I'm trying to test a program using Python's pathlib module. With the os module, you used to be able to access networked drives by just following the same url-like form. But for some reason, you can't do this with pathlib. Or at least I can't figure out how to do it.
With the os module, all one would have to do is:
path = os.path.join(r'//server-01', 'directory', 'filename.txt')
But if you try to do this with the pathlib module, one could try something like:
path = Path('//server-01', 'directory', 'filename.txt')
If I'm on a Windows machine, path will resolve to:
>> WindowsPath('/server-01/directory/filename.txt)
And if I were to say path.exists() I will of course get False. Because yes, /server-01 does NOT exist, however //server-01 does exist.
Ideally of course, the result I expect to get when I run path.exists() is True and if I were to display path it would look something like:
>> WindowsPath('//server-01/directory/filename.txt')
Update
It's kind of hacky, but it works I guess, regardless I'd like to know the right way to do it.
In order to get to the network location you can:
os.chdir(join(r'//server-01', 'directory', 'filename.txt'))
path = Path()
path = path.resolve()
The result is something like:
>> WindowsPath('//server-01/directory/filename.txt')
path.exists()
>> True
If anyone knows the better way to do it, let me know.
If you create your path as:
path = Path('//server-01/directory/filename.txt')
instead of comma separating each directory it will work.
The server name by itself is not a valid component of a UNC path. You must also include a share. So path = Path('//server-01/directory', 'file') will work. It should resolve and return True when you run path.exists().
Microsoft docs here: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dfsc/149a3039-98ce-491a-9268-2f5ddef08192
after several attempts, I think you can visit the smb folder/file with pathlib by:
folder = pathlib.Path('//server/')
file = pathlib.Path('//server/') / 'relative/path/to/file'
# or
file = pathlib.Path('//server/relative/path/to/file')
the key is that if you want to visit a smb folder, the arg should end with '/'.
Instantiating path as a PureWindowsPath should do the trick:
path = PureWindowsPath("//server-01", "directory", "file") # '\\\\server-01\\directory\\file'

What is the pythonic way to get file handles from the command line with relative or absolute paths?

When I write a command line script in python, I'm assuming that it can be invoked from anywhere. This seems to cause incongruity when I want to pass a list of files into the script.
Passing the files using a list or wildcard arguments (whether expanded by bash under *nix or glob.glob with Windows) will return either a relative path or an absolute one, depending on how the file path was described, but this seems to give two different behaviors which have to either be checked or harmonized.
If the script is in the same directory as the files to be imported, this isn't really a problem, but if the script is in a different directory, it seems like you need to grab the absolute path first:
import os,sys,glob
for arg in sys.argv[1:]:
file_list = glob.glob(arg)
for fn in file_list:
print("File Reference: {}".format(os.path.abspath(fn)))
> pwd
/Users/user1/Desktop/script_dir/
> cd ~/Desktop
> script_dir/test.py test_dir/*.csv /Users/user1/Desktop/test_dir/*.txt
File Reference: /Users/user1/Desktop/test_dir/temp1.csv
File Reference: /Users/user1/Desktop/test_dir/temp2.csv
File Reference: /Users/user1/Desktop/test_dir/temp1.txt
File Reference: /Users/user1/Desktop/test_dir/temp2.txt
Assuming the program continued on to do something with the files, it would then manipulate them by absolute path. Is this the correct thing to do here? It seems weirdly klugy, and I can seem to find any references that lay this out.

Weird python file path behavior

I have this folder structure, within edi_standards.py I want to open csv/transaction_groups.csv
But the code only works when I access it like this os.path.join('standards', 'csv', 'transaction_groups.csv')
What I think it should be is os.path.join('csv', 'transaction_groups.csv') since both edi_standards.py and csv/ are on the same level in the same folder standards/
This is the output of printing __file__ in case you doubt what I say:
>>> print(__file__)
~/edi_parser/standards/edi_standards.py
when you're running a python file, the python interpreter does not change the current directory to the directory of the file you're running.
In your case, you're probably running (from ~/edi_parser):
standards/edi_standards.py
For this you have to hack something using __file__, taking the dirname and building the relative path of your resource file:
os.path.join(os.path.dirname(__file__),"csv","transaction_groups.csv")
Anyway, it's good practice not to rely on the current directory to open resource files. This method works whatever the current directory is.
I do agree with Answer of Jean-Francois above,
I would like to mention that os.path.join does not consider the absolute path of your current working directory as the first argument
For example consider below code
>>> os.path.join('Functions','hello')
'Functions/hello'
See another example
>>> os.path.join('Functions','hello','/home/naseer/Python','hai')
'/home/naseer/Python/hai'
Official Documentation
states that whenever we have given a absolute path as a argument to the os.path.join then all previous path arguments are discarded and joining continues from the absolute path argument.
The point I would like to highlight is we shouldn't expect that the function os.path.join will work with relative path. So You have to submit absolute path to be able to properly locate your file.

Where does python look for files in a script? [duplicate]

This question already has answers here:
How do I get the parent directory in Python?
(21 answers)
Closed 9 years ago.
So I've just coded this class for a title screen and it works well. However, one of the people I'm working with on the project mentioned that I shouldn't use:
os.chdir(os.getcwd() + "/..")
resource = (os.getcwd() + "/media/file name")
to get to the super directory. He did mention something about the pythonpath though. We're using Eclipse if this is of some help.
For more context we're making a multi-platform game so we can't just synchronize our directories and hard-code it (although we are using git so the working directory is synchronized). Basically, I need some way to get from a script file in a "src' folder to a "media" folder that's next to it (AKA There's a super (project) folder with both "src" and "media" folders in it).
Any help would be greatly appreciated, but please don't say "google it" because I tried that before coming here (I don't know if that's a frequent thing here, but I've seen it too many times elsewhere...when I've googled for answers, sorry if I sound jerkish for saying that)
Python programs do have the concept of a current working directory, which is generally the directory from which the script was run. This is "where they look for files" with a relative path.
However, since your program can be run from a different folder than the one it is in, your directory of reference needs to instead refer to the directory your script is in (the current directory is not related to the location of your script, in general). The directory where your script is found is obtained with
script_dir = os.path.dirname(__file__)
Note that this path can be relative (possibly empty), so it is still important that the current working directory of your script be the same as the directory when your script was read by the python interpreter (which is when __file__ is set). It is important to convert the possibly relative script_dir into an absolute path if the current working directory is changed later in the code:
# If script_dir is relative, the current working directory is used, here. This is correct if the current
# working directory is the same as when the script was read by the Python interpreter (which is
# when __file__ was set):
script_dir = os.path.abspath(script_dir)
You can then get to the directory media in the parent directory with the platform-independent
os.path.join(script_dir, os.path.pardir, 'media')
In fact os.path.pardir (or equivalently os.pardir) is the platform-independent parent directory convention, and os.path.join() simply joins paths in a platform independent way.
I'd recommend something like:
import os.path
base_folder = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
media_folder = os.path.join(base_folder, "media")
src_folder = os.path.join(base_folder, "src")
resource = os.path.join(media_folder, "filename")
for path in [base_folder, media_folder, src_folder, resource]:
print path
The main ingredients are:
__file__: gets the path to the current source file (unlike sys.argv[0], which gives the path the script that was called)
os.path.split(): splits a path into the relative file/folder name and the base folder containing it. Using it twice as in base_folder = ... will give the parent directory.
os.path.join: OS-independent and correct combination of path names. Is aware of missing or multiple /s or \s
Consider using os.path.dirname() and os.path.join(). These should work in a platform independent way.

Categories