alphanumeric
alphanumeric

Reputation: 19329

Is it expected behavior with os.path.join()

Example1 where path2 starts with '/' results to /dir2/dir3/ (missing path1)

path1='/Volumes/disk1/'
path2='/dir2/dir3/'
print os.path.join(path1,path2)

Example2 where path2 does NOT start with '/' results to proper /Volumes/disk1/dir2/dir3/:

path1='/Volumes/disk1/'
path2='dir2/dir3/'
print os.path.join(path1,path2)

Question: I thought the purpose of os.path.join() is allow us to avoid extra work of tedious work of verifying if it's mac, windows or linux file path: one command does it all. But now if I would have to watch if path2 starts or does not start with '/' (or '\') it ruins every hope I had and brings ton of extra code... What is the solution? I don't want to do this ugliness:

if path2 and path2.replace('\\','/')[1:] and path2.replace('\\','/').startswith('/'):
    path2=path2[1:]

Upvotes: 2

Views: 712

Answers (2)

bcorso
bcorso

Reputation: 47078

In order to work without the hassle of checking separators you have to start without them or remove them completely before passing to os.path.join() . In the code below, I show 3 ways you can do this (Live Ideone Example to play with).

Individual Directories

import os
print os.path.join('Volumes', 'disk1', 'dir2', 'dir3')

Split Paths Then Join

path1 = '/Volumes/disk1/'
path2 = '/dir2/dir3/'

import os
# this will convert to the same as above:
# i.e., os.path.join('Volumes', 'disk1', 'dir2', 'dir3')
print os.path.join(*(path1.split(os.sep) + path2.split(os.sep)))

Custum Join Function

Using the above code, you can write a custom join() that works for either single- or multi- path strings:

def join(*paths):
    import os
    return os.path.join(*[part for path in paths for part in path.split(os.sep)])

path1 = '/Volumes/disk1/'
path2 = '/dir2/dir3/'

print join(path1, path2)

Output:

'Volumes/disk1/dir2/dir3'

Upvotes: 1

aruisdante
aruisdante

Reputation: 9085

Direct form the documentation,

Join one or more path components intelligently. If any component is an absolute path, all previous components (on Windows, including the previous drive letter, if there was one) are thrown away, and joining continues.

You're seeing the behavior you are because you are passing it an absolute path (a path that starts with a '/'). Your program needs to be able to handle the difference between the two, and if it's the thing generating the paths, make sure it's probably creating an absolute path when you want that, and a relative one when you want that.

Explanation of why this is useful

Consider the following. I have a command line interface that asks the user to specify a path for file output. In my documentation, I say the following:

path: Path to an output file. If relative, will be placed inside ~/Documents.

Now in my code, all I need to do is:

out_path = os.path.join('~','Documents', path)

and now out_path will always contain the correct path. If the user specifies volume_1/output.txt, the file will wind up in ~/Documents/volume_1/output.text. If they specify /mnt/volume_1/output.text it will wind up in /mnt/volume_1/output.text, because the absolute path overrides the relative portion we provide as a default.

Upvotes: 1

Related Questions