Python os.path.join() mangling absolute path in Windows - python

I'm new to Python and I'm trying to access a file with a full path represented by the following:
'X:/01 File Folder/MorePath/Data/Test/myfile.txt'
Every time I try to build the full string using os.path.join, it ends up slicing out everything between the drive letter and the second path string, like so:
import os
basePath = 'X:/01 File Folder/MorePath'
restofPath = '/Data/Test/myfile.txt'
fullPath = os.path.join(basePath,restofPath)
gives me:
'X:/Data/Test/myfile.txt'
as the fullPath name.
Can anyone tell me what I'm doing wrong? Does it have something to do with the digits near the beginning of the base path name?

The / at the beginning of your restofPath means "start at the root directory." So os.path.join() helpfully does that for you.
If you don't want it to do that, write your restofPath as a relative directory, i.e., Data/Test/myfile.txt, rather than an absolute one.
If you are getting your restofPath from somewhere outside your program (user input, config file, etc.), and you always want to treat it as relative even if the user is so gauche as to start the path with a slash, you can use restofPath.lstrip(r"\/").

Related

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'

How do I create a string containing the filepath of my python program?

We are creating a python program that executes specific macros within Polyworks based on user input into the program. Right now the code is:
roto.command.CommandExecute('MACRO EXEC("C:\\RotoWorks\\Macros\\CentrifugalCompressor")')
However this assumes that our program is always installed in C:\RotoWorks. Ideally, our app is portable. I'm sure theres a way to retrieve the filepath that Rotoworks is stored in, then just concatenate the rest of the filepath to the end. How do I do this?
You can retrieve the path from the __file__ attribute of the file. Use os.path.abspath on that attribute to retrieve the absolute path of the file and then os.path.dirname to retrieve the containing directory:
import os
file_directory = os.path.dirname(os.path.abspath(__file__))
path = os.path.join(file_directory, other_path) # join directory to an inner path
roto.command.CommandExecute('MACRO EXEC({})'.format(path))
Use os.path.dirname recursively to move out as many directories as you want.

missing slash in os.path.join result from tkinter filedialog

What's wrong with the way I'm joining my path here?
Everything but the first item in the list will be properly joined.
I'm grabbing a path from a filedialog in tkinter.
i.e filedialog.askdirectory()
Example Path:
PATH = "C:/MyUserName/Desktop/SomeDir"
What I'm doing:
os.path.join(*(PATH.split("/") + ["somefile.txt"]))
This will print out the following:
C:MyUserName/Desktop/SomeDir/somefile.txt
Why does it lose the first /?
I needed to convert my initial path using os.normpath I was getting a filedialog input from tkinter and then trying to use the above path style / code in the question to access / create files.
Because of the bad join / seperators on windows it was causing errors.
You are using Windows, right?
From the Docs:
On Windows, the drive letter is not reset when an absolute path component (e.g., r'\foo') is encountered. If a component contains a drive letter, all previous components are thrown away and the drive letter is reset. Note that since there is a current directory for each drive, os.path.join("c:", "foo") represents a path relative to the current directory on drive C: (c:foo), not c:\foo.
This means that c:foo is in fact a correct path. Try os.path.abspath('c:foo') and os.path.abspath('c:\\foo') to see the difference. The first path is a relative path on the c drive and the second one is an absolute path.
Windows keeps a current path for all drives. C:MyUserName/Desktop/SomeDir/somefile.txt and C:/MyUserName/Desktop/SomeDir/somefile.txt are both valid and there is no way for ntpath.join to know whether you wanted the drive-relative or drive-absolute path.

Why can't "os.path.getsize" work with a regular string

When I run the following everything works fine.
import os
fileSize=os.path.getsize("/Users/Richard/Desktop/Schedule.doc")
print fileSize
When I run the following however i get the error "no such file or directory". Does os.path.getsize not accept variable stings?
I want as the following because it will be easier to copy, past and edit in multiple programs.
import os
fileName ="Schedule.doc"
path = os.path.join('Users','Richard', 'Desktop')
filelocation = os.path.join(path, fileName)
fileSize=os.path.getsize(filelocation)
print fileSize
Try printing filelocation. You'll find that it doesn't start with a slash. The os.path.join commands you issued built a relative path, so Python is looking for Users/Richard/Desktop/Schedule.doc relative to the current directory.
os.path.join('/Users', ...), with the first argument starting with a slash, should get you an absolute path.

What directory does os.path.join start at?

I made a script in the past to mass rename any file greater than x characters in a directory. When I made that script I had a source directory which you would need to input manually. Any file that was over x characters in that directory would be stripped of it's extension, renamed, then the extension would be re added and it would use os.path.join to join the source and the newly created filename+ext. I'm now making another script and used os.path.join("Folder in the current dir", "file in that dir"). Because this worked I'm guessing that when os.path.join is called with just a foldername and no full path in it's first parameter it starts it's search from the directory that the script it was run in? Just wondering if this is correct.
os.path.join has nothing to do with any actual filesystem, and does not "start" anywhere. It simply joins two arbitrary paths, whether they exist or not.
What os.path.join does is to just join path elements the system-compatible way, taking into effect the particular directory separator character, etc., into account. It's a simple string manipulation tool.
So the returned result simply starts from whatever you give to it as the first argument.

Categories

Resources