Python Pathlib escaping string stored in variable - python

I'm on windows and have an api response that includes a key value pair like
object = {'path':'/my_directory/my_subdirectory/file.txt'}
I'm trying to use pathlib to open and create that structure relative to the current working directory as well as a user supplied directory name in the current working directory like this:
output = "output_location"
path = pathlib.Path.cwd().joinpath(output,object['path'])
print(path)
What this gives me is this
c:\directory\my_subdirectory\file.txt
Whereas I'm looking for it to output something like:
'c:\current_working_directory\output_location\directory\my_subdirectory\file.txt'
The issue is because the object['path'] is a variable I'm not sure how to escape it as a raw string. And so I think the escapes are breaking it. I can't guarantee there will always be a leading slash in the object['path'] value so I don't want to simply trim the first character.
I was hoping there was an elegant way to do this using pathlib that didn't involve ugly string manipulation.

Try lstrip('/')
You want to remove your leading slash whenever it’s there, because pathlib will ignore whatever comes before it.

import pathlib
object = {'path': '/my_directory/my_subdirectory/file.txt'}
output = "output_location"
# object['path'][1:] removes the initial '/'
path = pathlib.PureWindowsPath(pathlib.Path.cwd()).joinpath(output,object[
'path'][1:])
# path = pathlib.Path.cwd().joinpath(output,object['path'])
print(path)

Related

How do I put a variable in a path

I'm trying to store a path in a variable. see below
target = r"C:\Users\User\CodeProjects\WebSafer"
However, I need it to be dynamic. Not hardcoded to my username, so I get the login username by doing:
val = os.getlogin()
So I need to put the variable val in the path. But every time I tried doing it I always get a truncating/syntax error. Please help me! Below is the code snippet:
print("No copy found...making a copy\n")
val = os.getlogin()
original = r"C:\*******\********\*******\***\****"
target = r"C:\Users\User\CodeProjects\WebSafer"
shutil.copy(original, target)
The "*" are just for privacy reasons, there actually replaced with the right path location to what I'm copying.
What I have tried so far:
target = r"C:\Users\{val}\CodeProjects\WebSafer".format(val = os.getlogin)
target = r"C:\Users\{}\CodeProjects\WebSafer".format(val)
target = rf"C:\Users\{val}\CodeProjects\WebSafer".format(val = os.getlogin)
target = rf"C:\Users\{}\CodeProjects\WebSafer".format(val)
Don't mix f with .format, this is working for me:
import os
val = os.getlogin()
print(rf"C:\Users\{val}\CodeProjects\WebSafer")
And I think better way is:
import os.path
from pathlib import Path
home = str(Path.home())
print(os.path.join(home, "CodeProjects\WebSafer"))
Then if you encounter some error when copying, you need clarify what you want to copy, copy a file, or a folder, if a folder, should it go to within the dest folder, or overwrite dest folder?
You may want try different methods such as
shutil.copy, shutil.copytree, and different parameters.
"r" means the string will be treated as raw string so try removing that and using escaped characters target = "C:\\Users\\{val}\\CodeProjects\\WebSafer".format(val = os.getlogin)
You can use f-string (to directly enter your variable) and r-string (to enter the path without escape characters like \) together.
val = os.getlogin() # Returns username
target = fr"C:\Users\{val}\CodeProjects\WebSafer"
If you're getting a No such file or directory error, it means that the actual file or folder does not exist. Check the actual path to ensure every part (Your Username, CodeProjects, Websafer) exists on your computer.
In case you don't know if your user will have that folder on their system, you can use a try-except block to alert the user or to revert to some default folder instead.

How to manipulate directory paths to work across multiple OS?

I'm writing a python script which has to internally create output path from the input path. However, I am facing issues to create the path which I can use irrespective of OS.
I have tried to use os.path.join and it has its own limitations.
Apart from that, I think simple string concatenation is not the way to go.
Pathlib can be an option but I am not allowed to use it.
import os
inputpath = "C:\projects\django\hereisinput"
lastSlash = left.rfind("\\")
# This won't work as os path join stops at a slash
outputDir = os.path.join(left[:lastSlash], "\internal\morelevel\outputpath")
OR
OutDir = left[:lastSlash] + "\internal\morelevel\outputpath"
Expected output path :
C:\projects\django\internal\morelevel\outputpath
Also, the above code doesn't do it OS Specific where in Linux, the slash will be different.
Is os.sep() some option ?
From the documentation os.path.join can join "one or more path components...". So you could split "\internal\morelevel\outputpath" up into each of its components and pass all of them to your os.path.join function instead. That way you don't need to "hard-code" the separator between the path components. For example:
paths = ("internal", "morelevel", "outputpath")
outputDir = os.path.join(left[:lastSlash], *paths)
Remember that the backslash (\) is a special character in Python so your strings containing singular backslashes wouldn't work as you expect them to! You need to escape them with another \ in front.
This part of your code lastSlash = left.rfind("\\") might also not work on any operating system. You could rather use something like os.path.split to get the last part of the path that you need. For example, _, lastSlash = os.path.split(left).
Assuming your original path is "C:\projects\django\hereisinput", your other part of the path as "internal\morelevel\outputpath" (notice this is a relative path, not absolute), you could always move your primary back one folder (or more) and then append the second part. Do note that your first path needs to contain only folders and can be absolute or relative, while your second path must always be relative for this hack to work
path_1 = r"C:\projects\django\hereisinput"
path_2 = r"internal\morelevel\outputpath"
path_1_one_folder_down = os.path.join(path_1, os.path.pardir)
final_path = os.path.join(path_1_one_folder_down, path_2)
'C:\\projects\\django\\hereisinput\\..\\internal\\morelevel\\outputpath'

Python find out if a folder exists

I am trying to find out if a folder exists but for some reason cannot.
I am generating a string, and use os.path.isdir to find out if a folder with that string`s name already exists. The thing is - I get 'False' regardless.
import os
my_Folder_Name = 'some_string' #This is a string that I generate
print(os.path.isdir("\\" + my_Folder_Name)) #Even if this folder exists - I get False
What am I doing wrong here?
import os
my_Folder_Name = 'some_string' #This is a string that I generate
print(os.path.isdir(my_Folder_Name))
remove "//". Why are you using "//"?
Either use the relative path or the absolute one. Don't append '\' to your folder path.
print(os.path.isdir(my_folder_name))
(Sorry to digress, but variable names follow snake case convention in python. So if you can change that too, other python programmers would be happier)

Get folder name of the file in Python

In Python what command should I use to get the name of the folder which contains the file I'm working with?
"C:\folder1\folder2\filename.xml"
Here "folder2" is what I want to get.
The only thing I've come up with is to use os.path.split twice:
folderName = os.path.split(os.path.split("C:\folder1\folder2\filename.xml")[0])[1]
Is there any better way to do it?
You can use dirname:
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().
And given the full path, then you can split normally to get the last portion of the path. For example, by using basename:
os.path.basename(path)
Return the base name of pathname path. This is the second element of
the pair returned by passing path to the function split(). Note that
the result of this function is different from the Unix basename
program; where basename for '/foo/bar/' returns 'bar', the basename()
function returns an empty string ('').
All together:
>>> import os
>>> path=os.path.dirname("C:/folder1/folder2/filename.xml")
>>> path
'C:/folder1/folder2'
>>> os.path.basename(path)
'folder2'
You are looking to use dirname. If you only want that one directory, you can use os.path.basename,
When put all together it looks like this:
os.path.basename(os.path.dirname('dir/sub_dir/other_sub_dir/file_name.txt'))
That should get you "other_sub_dir"
The following is not the ideal approach, but I originally proposed,using os.path.split, and simply get the last item. which would look like this:
os.path.split(os.path.dirname('dir/sub_dir/other_sub_dir/file_name.txt'))[-1]
this is pretty old, but if you are using Python 3.4 or above use PathLib.
# using OS
import os
path=os.path.dirname("C:/folder1/folder2/filename.xml")
print(path)
print(os.path.basename(path))
# using pathlib
import pathlib
path = pathlib.PurePath("C:/folder1/folder2/filename.xml")
print(path.parent)
print(path.parent.name)
os.path.dirname is what you are looking for -
os.path.dirname(r"C:\folder1\folder2\filename.xml")
Make sure you prepend r to the string so that its considered as a raw string.
Demo -
In [46]: os.path.dirname(r"C:\folder1\folder2\filename.xml")
Out[46]: 'C:\\folder1\\folder2'
If you just want folder2 , you can use os.path.basename with the above, Example -
os.path.basename(os.path.dirname(r"C:\folder1\folder2\filename.xml"))
Demo -
In [48]: os.path.basename(os.path.dirname(r"C:\folder1\folder2\filename.xml"))
Out[48]: 'folder2'
you can use pathlib
from pathlib import Path
Path(r"C:\folder1\folder2\filename.xml").parts[-2]
The output of the above was this:
'folder2'
You could get the full path as a string then split it into a list using your operating system's separator character.
Then you get the program name, folder name etc by accessing the elements from the end of the list using negative indices.
Like this:
import os
strPath = os.path.realpath(__file__)
print( f"Full Path :{strPath}" )
nmFolders = strPath.split( os.path.sep )
print( "List of Folders:", nmFolders )
print( f"Program Name :{nmFolders[-1]}" )
print( f"Folder Name :{nmFolders[-2]}" )
print( f"Folder Parent:{nmFolders[-3]}" )
The output of the above was this:
Full Path :C:\Users\terry\Documents\apps\environments\dev\app_02\app_02.py
List of Folders: ['C:', 'Users', 'terry', 'Documents', 'apps', 'environments', 'dev', 'app_02', 'app_02.py']
Program Name :app_02.py
Folder Name :app_02
Folder Parent:dev
I made an improvement on the solutions available, namely the snippet that works with all of,
File
Directory with a training slash
Directory without a training slash
My solution is,
from pathlib import Path
def path_lastname(s):
Path(s).with_name("foo").parts[-2]
Explanation
Path(s) - Creates a custom Path object out of s without resolving it.
.with_name("foo") - Adds a fake file foo to the path
.parts[-2] returns second last part of the string. -1 part will be foo
I'm using 2 ways to get the same response:
one of them use:
os.path.basename(filename)
due to errors that I found in my script I changed to:
Path = filename[:(len(filename)-len(os.path.basename(filename)))]
it's a workaround due to python's '\\'

os.path.join producing an extra forward slash

I am trying to join an absolute path and variable folder path depending on the variable run. However when I use the following code it inserts a forward slash after a string, which I don't require. How can I remove the slash after Folder_?
import os
currentwd = os.getcwd()
folder = '001'
run_folder = os.path.join(currentwd, 'Folder_', folder)
print run_folder
The output I get using this code is:
/home/xkr/Workspace/Folder_/001
You are asking os.path.join() to take multiple path elements and join them. It is doing its job.
Don't use os.path.join() to produce filenames; just use concatenation:
run_folder = os.path.join(currentwd, 'Folder_' + folder)
or use string formatting; the latter can give you such nice features such as automatic padding of integers:
folder = 1
run_folder = os.path.join(currentwd, 'Folder_{:03d}'.format(folder))
That way you can increment folder past 10 or 100 and still have the correct number of leading zeros.
Note that you don't have to use os.getcwd(); you could also use os.path.abspath(), it'll make relative paths absolute based on the current working directory:
run_folder = os.path.abspath('Folder_' + folder)

Categories

Resources