Can you set cwd for abspath? - python

I am trying to expand out a relative path into an absolute path. The relative path will sometimes in include a . which will need to be expanded out from the current working directory. I was wondering if the any standard functions in Python accept a cwd kwarg, like subprocess.popen does.
Optimal Solution
abs_path = os.path.abspath(rel_path, cwd=special_cwd)
Current Solution
# Capture current working directory
previous_cwd = os.getcwd()
# Change to the new working directory
os.chdir(new_cwd)
# Convert relative path to absolute path
abs_path = os.path.abspath(rel_path)
# Change back to previous working directory
os.chdir(previous_cwd)
The current solution seems clunky, is there a better way to accomplish this?

The current solution seems clunky, is there a better way to accomplish this?
You can write your own code as a context manager which changes the directory and then changes back:
>>> from contextlib import contextmanager
>>> #contextmanager
... def cwd(path):
... from os import getcwd, chdir
... cwd = getcwd()
... chdir(path)
... yield
... chdir(cwd)
then the actual code will look much cleaner:
>>> os.getcwd()
'/home/user'
>>> with cwd('/usr/share'):
... print(os.path.abspath('./test'))
...
/usr/share/test
>>> os.getcwd()
'/home/user'

Related

import image in python, my program cant work if i move program folder in different place if I want it to run, I have to change my code

i have problem on my program, I import images, and it works but behind that success there is something missing for me.
Check out the following code snippet:
# python 3
from PIL import Image
from PIL import ImageTk
pathdesign_img = "D:/Python/Project1/image/design/
self.logo_Tbar_img = ImageTk.PhotoImage(Image.open(pathdesign_img+'Mlogo.jpg'))
self.logo_Tbar = tk.Label(self.bar_Tbar, image=self.logo_Tbar_img, bg="#DA291C")
self.logo_Tbar.pack(side=tk.LEFT, fill=tk.BOTH)
The code works but when I want to move all my program folders to diffrent place example: C:\User\. My program cannot run and if I want it to run, I have to change pathdesign_img = "C:/User/....". Is there any code that I need to change or add, so that my program can run in any folder, without having to change pathdesign_img
Yeah, paths relative to your app's directory are the correct solution, but when passing them forward to be used it is always advisable to use absolute paths.
So, you use absolute paths relative to your app's directory.
It can be easy as:
import os
dirpath = os.path.abspath("images")
# os.path.abspath() will return the absolute path of the directory images
# that resides in the current working directory which you can discover with
# os.getcwd() and manipulate using os.chdir()
# Note that the current working directory may be manipulated from the OS.
# In the Windows's case you can specify it under properties of the shortcut
# and/or the executable. By the default it is the same directory where
# the executable lives, in this case, your script.
imagepath = os.path.join(dirpath, "<some_image>.jpg")
That is how it should be done. It is cross-platform, good practice, and will not give you trouble with paths.
However, if you are planning to bundle your app into a e.g. EXE, you need to be much craftier than that. That's because the *.exe bundled app is actually a ZIP file with some additions.
In this case the imagepath will look like:
>>> print (imagepath)
C:\Program Files\Yours_app_folder\yourapp.exe\images\your_image.jpg
which, of course is an invalid path for the OS. In these cases I do the following.
I create a module called whereiam or whereami (the name depends on how I feel I guess) in which I put a var or function that gets me the correct path to my app's directory. E.g.
import os, sys
def root ():
# If the app is only a script, this will result in mydir
# being a path to the directory where the 'whereiam' module lives:
me = os.path.abspath(__file__)
mydir = os.path.dirname(me)
# If the app is bundled then sys.executable points to it instead
# of Python interpreter, so first check for that
if mydir.startswith(sys.executable):
# Then we first get the directory where our app lives:
mydir = os.path.dirname(sys.executable)
# And if our whereiam is in a subdirectory, we find it by excluding
# the executable's filename from the path:
# by appending the rest to the mydir
l = len(sys.executable)
mydir = os.path.join(mydir.rstrip(os.sep), me[l:].lstrip(os.sep))
return mydir
Then in your main module you just do:
import whereiam
import os
dirpath = whereiam.root()
images = os.path.join(dirpath, "images")
imagepath = os.path.join(images, "<your_image>.jpg")
# And you can then open imagepath with PIL or whatever being sure that it will be found if it is there
Yes, it should be possible. I assume that your python-file or jupyter-notebook is in the folder "D:/Python/Project1", whereas your image is in the folder "D:/Python/Project1/image/design". Then you could do:
pathdesign_img = "image/design/"
In short, what this does: In the folder that you are already in, it searches for a folder called "image" and in that folder for a sub-folder called "design".

How get path of specific parent directory in python

I have path = "dir1/dir2/dir3/file.py"
I need a way to get the full path to dir2 i.e. dir1/dir2.
something like findparent(path, 'dir2').
You can split the path by the target directory, take the first element from the list, and then add the target directory to the target path.
path = "dir1/dir2/dir3/file.py"
def findparent(path: str, dir_: str) -> str:
return path.split(dir_)[0] + dir_
print(findparent(path, 'dir2'))
# dir1/dir2
If you use pathlib and the path actually exists:
path.resolve().parent
Just path.parent also works, purely syntactically, but has some caveats as mentioned in the docs.
To find one specific part of the parent hierarchy, you could iteratively call parent, or search path.parents for the name you need.
Check this out! How to get the parent dir location
My favorite is
from pathlib import Path
Path(__file__).parent.parent.parent # ad infinitum
You can even write a loop to get to dir2, something like this..
from pathlib import Path
goal_dir = "dir2"
current_dir = Path(__file__)
for i in range(10):
if current_dir == goal_dir:
break
current_dir = current_dir.parent
Note: This solution is not the best, you might want to use a while-loop instead and check if there is actually a parent. If you are at root level and there is no parent, then it doesn't exist. But, assuming it exists and you don't have a tree deeper than 10 levels, this works.
Assuming your current work directory is at the same location as your dir1, you can do:
import os
os.path.abspath("dir1/dir2")

How to change to a specific folder using cmd without caring about the whole path?

I am at a specific folder lets say users/personal/project/scripts. Is there a way to go to the project folder without caring about what is before /project, that is without caring about the users/personal/ in a python script?
I am looking for a way, other than
import os
os.chdir('..')
You can use split of os.path module.
import os
import os.path
some_path = '/users/personal/project/scripts'
base_path, child = os.path.split(some_path)
os.chdir(base_path)
You can use the os module with the os.cwd() and os.path.abspath(os.path.join(path, os.pardir)) in order to achieve this. GeeksforGeeks has a great article, which has multiple answers to your question:
https://www.geeksforgeeks.org/get-parent-of-current-directory-using-python/
METHOD 1:
import os
# get current directory
path = os.getcwd()
print("Current Directory", path)
print()
# parent directory
parent = os.path.dirname(path)
print("Parent directory", parent)
METHOD 2:
import os
# get current directory
path = os.getcwd()
print("Current Directory", path)
# prints parent directory
print(os.path.abspath(os.path.join(path, os.pardir)))
METHOD 3:
import os.path
# function to get parent
def getParent(path, levels = 1):
common = path
# Using for loop for getting
# starting point required for
# os.path.relpath()
for i in range(levels + 1):
# Starting point
common = os.path.dirname(common)
# Parent directory upto specified
# level
return os.path.relpath(path, common)
path = 'D:/Pycharm projects / GeeksforGeeks / Nikhil / gfg.txt'
print(getParent(path, 2))
Keep in mind, that you can put these into functions and repeat them the number of parent directories up you need to go, for example you could turn method 1 into:
import os
def get_parent_directory(num_of_parent_directories_to_go_up=1): # Defaults the number of parent directories to go up to one, which mean go one directory up
current_path = os.getcwd()
for i in range(num_of_parent_directories_to_go_up):
current_path = os.path.dirname(current_path)
return current_path
This will output the parent directory of how many times you put into it, which defaults to one.
Example 1:
INPUT: users/personal/project/scripts
CODE: get_parent_directory()
OUTPUT: users/personal/project/
Example 2:
INPUT: users/personal/project/scripts
CODE: get_parent_directory(2)
OUTPUT: users/personal/
Ans you can see how this would go on. Furthermore, this does not error if you give a number larger than parent directories exist and will instead return the root path.
In the function or with what is returned from the example function I provided, you can use os.chdir(path_from_function_here) to change your working directory.
you can use os.getcwd() to get the current path, then find out how many level to go back to project folder, then goto project folder using os.chdir
this will works across variable level deep inside project directory.
for example, current directory either in /users/personal/project/scripts or /users/personal/project/scripts/lib also will back to /users/personal/project
os.path.sep ensure this will works in both windows/linux
curdir = os.getcwd().split(os.path.sep)
project_back_idx = len(curdir) - curdir.index('project') - 1
os.chdir(os.path.sep.join(['..'] * project_back_idx))
# 1 level back - os.chdir('..')
# 2 level back - os.chdir('..//..') and so on

Check whether or not directory is in path

I'm trying to write a Python function to accomplish the following: given a path and directory, return True only if directory appears somewhere in path.
For example consider the following example:
path = 'Documents/Pictures/random/old/test_image.jpg'
dir = 'random'
This should return True, since the directory random/ occurs somewhere along the path. On the other hand, the following example should return False:
path = 'Documents/Pictures/random_pictures/old/test_image.jpg'
dir = 'random`
This is because the directory random/ does not appear in the path, random_pictures/ does.
Is there a smarter way to do this than simply doing something like this:
def is_in_directory(path, dir):
return '/{0}/'.format(dir) in path
Perhaps with an os or os.path module?
You can use os.path.split to get the directory path then split them and check for existence :
>>> dir = 'random'
>>> dir in os.path.split(path)[0].split('/')
True
And as #LittleQ suggested as a better way you can split your base path with os.path.sep
>>> dir in os.path.split(path)[0].split(s.path.sep)
True
split using os.path.sep os.path.dirname:
from os.path import sep,dirname
def is_in_directory(p, d):
return d in dirname(p).split(sep)
os.path.dirname(path)ΒΆ
Return the directory name of pathname path. This is the first element of the pair returned by passing path to the function split().

How can I extract the folder path from file path in Python?

I would like to get just the folder path from the full path to a file.
For example T:\Data\DBDesign\DBDesign_93_v141b.mdb and I would like to get just T:\Data\DBDesign (excluding the \DBDesign_93_v141b.mdb).
I have tried something like this:
existGDBPath = r'T:\Data\DBDesign\DBDesign_93_v141b.mdb'
wkspFldr = str(existGDBPath.split('\\')[0:-1])
print wkspFldr
but it gave me a result like this:
['T:', 'Data', 'DBDesign']
which is not the result that I require (being T:\Data\DBDesign).
Any ideas on how I can get the path to my file?
You were almost there with your use of the split function. You just needed to join the strings, like follows.
>>> import os
>>> '\\'.join(existGDBPath.split('\\')[0:-1])
'T:\\Data\\DBDesign'
Although, I would recommend using the os.path.dirname function to do this, you just need to pass the string, and it'll do the work for you. Since, you seem to be on windows, consider using the abspath function too. An example:
>>> import os
>>> os.path.dirname(os.path.abspath(existGDBPath))
'T:\\Data\\DBDesign'
If you want both the file name and the directory path after being split, you can use the os.path.split function which returns a tuple, as follows.
>>> import os
>>> os.path.split(os.path.abspath(existGDBPath))
('T:\\Data\\DBDesign', 'DBDesign_93_v141b.mdb')
WITH PATHLIB MODULE (UPDATED ANSWER)
One should consider using pathlib for new development. It is in the stdlib for Python3.4, but available on PyPI for earlier versions. This library provides a more object-orented method to manipulate paths <opinion> and is much easier read and program with </opinion>.
>>> import pathlib
>>> existGDBPath = pathlib.Path(r'T:\Data\DBDesign\DBDesign_93_v141b.mdb')
>>> wkspFldr = existGDBPath.parent
>>> print wkspFldr
Path('T:\Data\DBDesign')
WITH OS MODULE
Use the os.path module:
>>> import os
>>> existGDBPath = r'T:\Data\DBDesign\DBDesign_93_v141b.mdb'
>>> wkspFldr = os.path.dirname(existGDBPath)
>>> print wkspFldr
'T:\Data\DBDesign'
You can go ahead and assume that if you need to do some sort of filename manipulation it's already been implemented in os.path. If not, you'll still probably need to use this module as the building block.
The built-in submodule os.path has a function for that very task.
import os
os.path.dirname('T:\Data\DBDesign\DBDesign_93_v141b.mdb')
Here is the code:
import os
existGDBPath = r'T:\Data\DBDesign\DBDesign_93_v141b.mdb'
wkspFldr = os.path.dirname(existGDBPath)
print wkspFldr # T:\Data\DBDesign
Here is my little utility helper for splitting paths int file, path tokens:
import os
# usage: file, path = splitPath(s)
def splitPath(s):
f = os.path.basename(s)
p = s[:-(len(f))-1]
return f, p
Anyone trying to do this in the ESRI GIS Table field calculator interface can do this with the Python parser:
PathToContainingFolder =
"\\".join(!FullFilePathWithFileName!.split("\\")[0:-1])
so that
\Users\me\Desktop\New folder\file.txt
becomes
\Users\me\Desktop\New folder
I use this to change the current working directory to a folder;
from os import chdir
from os.path import realpath
from os.path import dirname
chdir(realpath(dirname(argv[0])))
chdir changes the working directory. I doubt you'll need this.
realpath follows symlinks.
dirname returns just the path
argv is the command line used to execute the program

Categories