Any elegant way to get relative path in Python? - python

Say I want to delete 'Core.dll' after 'git pull', so I write a hook.
import os
dir = os.path.dirname(__file__)
try:
os.remove(os.path.abspath(dir+os.sep+".."+os.sep+".."+os.sep+"Assets"+os.sep+"Plugins"+os.sep+"Core.dll"))
except OSError:
pass
Say the hook path is 'E:\client\.git\hooks', the file I want to delete is in 'E:\client\Assets\Plugins\Core.dll'.
I think my way is very silly, is there any elegant way to get the relative path?

Using pathlib:
from pathlib import Path
(Path(__file__).absolute().parent.parent.parent/'Assets'/'Plugins'/'Core.dll').unlink()

Antti's solution is the best in Python 3. For Python 2, you could use os.pardir and os.path.join:
os.path.abspath(os.path.join(d, os.pardir, os.pardir, "Assets", "Plugins", "Core.dll"))

os.path.relpath would be what you asked for. You should also be using os.path.join instead of that long list of + and sep. In Python 3's pathlib, there's relative_to. It appears your code is trying to apply a relative path, not get it in relative form. In that case, joinpath and normpath or realpath might help.

More readable solution:
import os
from contextlib import suppress
with suppress(OSError):
dir = os.path.dirname(__file__)
while '.git' in dir:
dir = os.path.dirname(dir)
os.remove(
os.path.join(
dir,
'Assets',
'Plugins',
'Core.dll'
)
)

Related

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

Python joining current directory and parent directory with os.path.join

I want to do join the current directory path and a relative directory path goal_dir somewhere up in the directory tree, so I get the absolute path to the goal_dir. This is my attempt:
import os
goal_dir = os.path.join(os.getcwd(), "../../my_dir")
Now, if the current directory is C:/here/I/am/, it joins them as C:/here/I/am/../../my_dir, but what I want is C:/here/my_dir. It seems that os.path.join is not that intelligent.
How can I do this?
You can use normpath, realpath or abspath:
import os
goal_dir = os.path.join(os.getcwd(), "../../my_dir")
print goal_dir # prints C:/here/I/am/../../my_dir
print os.path.normpath(goal_dir) # prints C:/here/my_dir
print os.path.realpath(goal_dir) # prints C:/here/my_dir
print os.path.abspath(goal_dir) # prints C:/here/my_dir
consider to use os.path.abspath this will evaluate the absolute path
or One can use os.path.normpath this will return the normalized path (Normalize path, eliminating double slashes, etc.)
One should pick one of these functions depending on requirements
In the case of abspath In Your example, You don't need to use os.path.join
os.path.abspath("../../my_dir")
os.path.normpath should be used if you are interested in the relative path.
>>> os.path.normpath("../my_dir/../my_dir")
'../my_dir'
Other references for handling with file paths:
pathlib - Object-oriented filesystem paths
os.path— Common pathname manipulations
Lately, I discovered pathlib.
from pathlib import Path
cwd = Path.cwd()
goal_dir = cwd.parent.parent / "my_dir"
Or, using the file of the current script:
cwd = Path(__file__).parent
goal_dir = cwd.parent.parent / "my_dir"
In both cases, the absolute path in simplified form can be found like this:
goal_dir = goal_dir.resolve()

How to use "/" (directory separator) in both Linux and Windows in Python?

I have written a code in python which uses / to make a particular file in a folder, if I want to use the code in windows it will not work, is there a way by which I can use the code in Windows and Linux.
In python I am using this code:
pathfile=os.path.dirname(templateFile)
rootTree.write(''+pathfile+'/output/log.txt')
When I will use my code in suppose windows machine my code will not work.
How do I use "/" (directory separator) in both Linux and Windows?
Use os.path.join().
Example: os.path.join(pathfile,"output","log.txt").
In your code that would be: rootTree.write(os.path.join(pathfile,"output","log.txt"))
Use:
import os
print os.sep
to see how separator looks on a current OS.
In your code you can use:
import os
path = os.path.join('folder_name', 'file_name')
You can use os.sep:
>>> import os
>>> os.sep
'/'
os.path.normpath(pathname) should also be mentioned as it converts / path separators into \ separators on Windows. It also collapses redundant uplevel references... i.e., A/B and A/foo/../B and A/./B all become A/B. And if you are Windows, these all become A\B.
If you are fortunate enough to be running Python 3.4+, you can use pathlib:
from pathlib import Path
path = Path(dir, subdir, filename) # returns a path of the system's path flavour
or, equivalently,
path = Path(dir) / subdir / filename
Some useful links that will help you:
os.sep
os.path
os.pathsep
Do a import os and then use os.sep
You can use "os.sep "
import os
pathfile=os.path.dirname(templateFile)
directory = str(pathfile)+os.sep+'output'+os.sep+'log.txt'
rootTree.write(directory)
Don't build directory and file names your self, use python's included libraries.
In this case the relevant one is os.path. Especially join which creates a new pathname from a directory and a file name or directory and split that gets the filename from a full path.
Your example would be
pathfile=os.path.dirname(templateFile)
p = os.path.join(pathfile, 'output')
p = os.path.join( p, 'log.txt')
rootTree.write(p)
If someone is looking for something like this:
He/she wants to know the parent directory and then go to the sub-folders and maybe than to a specific file. If so, I use the following approach.
I am using python 3.9 as of now. So in that version, we have the os module for handling such tasks. So, for getting the parent directory:
parent_dir = os.path.pardir
It's a good coding practice to not hardcode the file path separators (/ or \). Instead, use the operating system dependant mechanism provided by the above-mentioned os module. It makes your code very much reusable for other purposes/people. It goes like this (just an example) :
path = os.path.pardir + os.sep + 'utils' + os.sep + 'properties.ini'
print(f'The path to my global properties file is :: {path}')
Output:
..\utils\properties.ini
You can surely look at the whole documentation here : https://docs.python.org/3/library/os.html
I use pathlib for most things, so I like: pathlib.os.sep.
Usually pathlib is the better choice if you don't need os!

Manipulating paths in python

I am writing a python script 2.5 in Windows whose CurrentDir = C:\users\spring\projects\sw\demo\753\ver1.1\011\rev120\source my file is test.py. From this path I would like to access files in this path: C:\users\spring\projects\sw\demo\753\ver1.1\011\rev120\Common\
I tried using os.path.join but it does not work and I from the docs I understand why.
So what could be the best pythonic solution for this?
currentdir = os.getcwd()
config_file_path = os.path.join(currentdir,"\\..\\Common")
Your problem can be solved by using os.path.join, but you're not using it properly.
currentdir = os.getcwd()
config_file_path = os.path.join(currentdir,"\\..\\Common")
"\\..\\Common" is not a relative path, as it starts with \.
You need to join with ..\\Common, which is a relative path.
Please note that os.path.join is not a simple string concatenation function, you don't need to insert the in-between antislashes.
So fixed code would be :
config_file_path = os.path.join(currentdir,"..\\Common")
or, alternatively :
config_file_path = os.path.join(currentdir, "..", "Common")
from os.path import dirname, join
join(dirname(dirname(__file__)), 'Common')
should work.
Try this:
joined = os.path.join('C:\\users\\spring\\projects\\sw\\demo\\753\\ver1.1\\011\\rev120\\source', '..\\Common\\')
# 'C:\\users\\spring\\projects\\sw\\demo\\753\\ver1.1\\011\\rev120\\source\\..\\Common\\'
canonical = os.path.realpath(joined)
# 'C:\\users\\spring\\projects\\sw\\demo\\753\\ver1.1\\011\\rev120\\Common'

How to get an absolute file path in Python

Given a path such as "mydir/myfile.txt", how do I find the file's absolute path in Python? E.g. on Windows, I might end up with:
"C:/example/cwd/mydir/myfile.txt"
>>> import os
>>> os.path.abspath("mydir/myfile.txt")
'C:/example/cwd/mydir/myfile.txt'
Also works if it is already an absolute path:
>>> import os
>>> os.path.abspath("C:/example/cwd/mydir/myfile.txt")
'C:/example/cwd/mydir/myfile.txt'
You could use the new Python 3.4 library pathlib. (You can also get it for Python 2.6 or 2.7 using pip install pathlib.) The authors wrote: "The aim of this library is to provide a simple hierarchy of classes to handle filesystem paths and the common operations users do over them."
To get an absolute path in Windows:
>>> from pathlib import Path
>>> p = Path("pythonw.exe").resolve()
>>> p
WindowsPath('C:/Python27/pythonw.exe')
>>> str(p)
'C:\\Python27\\pythonw.exe'
Or on UNIX:
>>> from pathlib import Path
>>> p = Path("python3.4").resolve()
>>> p
PosixPath('/opt/python3/bin/python3.4')
>>> str(p)
'/opt/python3/bin/python3.4'
Docs are here: https://docs.python.org/3/library/pathlib.html
import os
os.path.abspath(os.path.expanduser(os.path.expandvars(PathNameString)))
Note that expanduser is necessary (on Unix) in case the given expression for the file (or directory) name and location may contain a leading ~/(the tilde refers to the user's home directory), and expandvars takes care of any other environment variables (like $HOME).
Install a third-party path module (found on PyPI), it wraps all the os.path functions and other related functions into methods on an object that can be used wherever strings are used:
>>> from path import path
>>> path('mydir/myfile.txt').abspath()
'C:\\example\\cwd\\mydir\\myfile.txt'
Update for Python 3.4+ pathlib that actually answers the question:
from pathlib import Path
relative = Path("mydir/myfile.txt")
absolute = relative.absolute() # absolute is a Path object
If you only need a temporary string, keep in mind that you can use Path objects with all the relevant functions in os.path, including of course abspath:
from os.path import abspath
absolute = abspath(relative) # absolute is a str object
This always gets the right filename of the current script, even when it is called from within another script. It is especially useful when using subprocess.
import sys,os
filename = sys.argv[0]
from there, you can get the script's full path with:
>>> os.path.abspath(filename)
'/foo/bar/script.py'
It also makes easier to navigate folders by just appending /.. as many times as you want to go 'up' in the directories' hierarchy.
To get the cwd:
>>> os.path.abspath(filename+"/..")
'/foo/bar'
For the parent path:
>>> os.path.abspath(filename+"/../..")
'/foo'
By combining "/.." with other filenames, you can access any file in the system.
Today you can also use the unipath package which was based on path.py: http://sluggo.scrapping.cc/python/unipath/
>>> from unipath import Path
>>> absolute_path = Path('mydir/myfile.txt').absolute()
Path('C:\\example\\cwd\\mydir\\myfile.txt')
>>> str(absolute_path)
C:\\example\\cwd\\mydir\\myfile.txt
>>>
I would recommend using this package as it offers a clean interface to common os.path utilities.
You can use this to get absolute path of a specific file.
from pathlib import Path
fpath = Path('myfile.txt').absolute()
print(fpath)
Given a path such as mydir/myfile.txt, how do I find the file's absolute path relative to the current working directory in Python?
I would do it like this,
import os.path
os.path.join( os.getcwd(), 'mydir/myfile.txt' )
That returns '/home/ecarroll/mydir/myfile.txt'
if you are on a mac
import os
upload_folder = os.path.abspath("static/img/users")
this will give you a full path:
print(upload_folder)
will show the following path:
>>>/Users/myUsername/PycharmProjects/OBS/static/img/user
In case someone is using python and linux and looking for full path to file:
>>> path=os.popen("readlink -f file").read()
>>> print path
abs/path/to/file

Categories