Accessing networked file locations with pathlib - python

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'

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)

How Python manages relative path

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

How to resolve relative paths in python?

I have Directory structure like this
projectfolder/fold1/fold2/fold3/script.py
now I'm giving script.py a path as commandline argument of a file which is there in
fold1/fold_temp/myfile.txt
So basically I want to be able to give path in this way
../../fold_temp/myfile.txt
>>python somepath/pythonfile.py -input ../../fold_temp/myfile.txt
Here problem is that I might be given full path or relative path so I should be able to decide and based on that I should be able to create absolute path.
I already have knowledge of functions related to path.
Question 1
Question 2
Reference questions are giving partial answer but I don't know how to build full path using the functions provided in them.
try os.path.abspath, it should do what you want ;)
Basically it converts any given path to an absolute path you can work with, so you do not need to distinguish between relative and absolute paths, just normalize any of them with this function.
Example:
from os.path import abspath
filename = abspath('../../fold_temp/myfile.txt')
print(filename)
It will output the absolute path to your file.
EDIT:
If you are using Python 3.4 or newer you may also use the resolve() method of pathlib.Path. Be aware that this will return a Path object and not a string. If you need a string you can still use str() to convert it to a string.
Example:
from pathlib import Path
filename = Path('../../fold_temp/myfile.txt').resolve()
print(filename)
A practical example:
sys.argv[0] gives you the name of the current script
os.path.dirname() gives you the relative directory name
thus, the next line, gives you the absolute working directory of the current executing file.
cwd = os.path.abspath(os.path.dirname(sys.argv[0]))
Personally, I always use this instead of os.getcwd() since it gives me the script absolute path, independently of the directory from where the script was called.
For Python3, you can use pathlib's resolve functionality to resolve symlinks and .. components.
You need to have a Path object however it is very simple to do convert between str and Path.
I recommend for anyone using Python3 to drop os.path and its messy long function names and stick to pathlib Path objects.
import os
dir = os.path.dirname(__file__)
path = raw_input()
if os.path.isabs(path):
print "input path is absolute"
else:
path = os.path.join(dir, path)
print "absolute path is %s" % path
Use os.path.isabs to judge if input path is absolute or relative, if it is relative, then use os.path.join to convert it to absolute

Save a file depending on the user Python

I try to write a script in Python that saves the file in each user directory.
Example for user 1, 2 and 3.
C:\Users\user1\Documents\ArcGIS\file1.gdb
C:\Users\user2\Documents\ArcGIS\file1.gdb
C:\Users\user3\Documents\ArcGIS\file1.gdb
How can I do this?
As one commenter pointed out, the simplest solution is to use the USERPROFILE environment variable to write the file path. This would look something like:
import os
userprofile = os.environ['USERPROFILE']
path = os.path.join(userprofile, 'Documents', 'ArcGIS', 'file1.gdb')
Or even more simply (with better platform-independence, as this will work on Mac OSX/Linux, too; credit to Abhijit's answer below):
import os
path = os.path.join(os.path.expanduser('~'), 'Documents', 'ArcGIS', 'file1.gdb')
Both of the above may have some portability issues across Windows versions, since Microsoft has been known to change the name of the "Documents" folder back and forth from "My Documents".
If you want a Windows-portable way to get the "Documents" folder, see the code here: https://stackoverflow.com/questions/3858851#3859336
In Python you can use os.path.expanduser to get the User's home directory.
>>> import os
>>> os.path.expanduser("~")
This is a platform independent way of determining the user's home directory.
You can then concatenate the result to create your final path
os.path.join(os.path.expanduser("~"), 'Documents', 'ArcGIS', 'file1.gdb')
You want to use the evironment variable HOME, something like this:
import os
homeDir = os.environ["HOMEPATH"]
file = open(homeDir+"Documents\ArcGIS\file1.gdb")
file.write("Hello, World")
file.close()
Notice that I've used HOMEPATH considering you're using Windows, it may be wrong depending on your OS. Take a look at this: http://en.wikipedia.org/wiki/Environment_variable

python os.path.realpath not working properly

I have following code:
os.chdir(os.path.dirname(os.path.realpath(__file__)) + "/../test")
path.append(os.getcwd())
os.chdir(os.path.dirname(os.path.realpath(__file__)))
Which should add /../test to python path, and it does so, and it all runs smoothly afterwards on eclipse using PyDev.
But when I lunch same app from console second os.chdir does something wrong, actually the wrong thing is in os.path.realpath(__file__) cus it returns ../test/myFile.py in stead of ../originalFolder/myFile.py. Of course I can fix this by using fixed os.chdir("../originalFolder") but that seems a bit wrong to me, but this works on both, eclipse and console.
P.S. I'm using os.getcwd() actually because I want to make sure there isn't such folder already added, otherwise I wouldn't have to switch dir's at all
So is there anything wrong with my approach or I have messed something up? or what? :)
Thanks in advance! :)
Take a look what is value of __file__. It doesn't contain absolute path to your script, it's a value from command line, so it may be something like "./myFile.py" or "myFile.py". Also, realpath() doesn't make path absolute, so realpath("myFile.py") called in different directory will still return "myFile.py".
I think you should do ssomething like this:
import os.path
script_dir = os.path.dirname(os.path.abspath(__file__))
target_dir = os.path.join(script_dir, '..', 'test')
print(os.getcwd())
os.chdir(target_dir)
print(os.getcwd())
os.chdir(script_dir)
print(os.getcwd())
On my computer (Windows) I have result like that:
e:\parser>c:\Python27\python.exe .\rp.py
e:\parser
e:\test
e:\parser
e:\parser>c:\Python27\python.exe ..\parser\rp.py
e:\parser
e:\test
e:\parser
Note: If you care for compatibility (you don't like strange path errors) you should use os.path.join() whenever you combine paths.
Note: I know my solution is dead simple (remember absolute path), but sometimes simplest solutions are best.

Categories