The Question :
342 people think this question is useful
The below code will not join, when debugged the command does not store the whole path but just the last entry.
os.path.join('/home/build/test/sandboxes/', todaystr, '/new_sandbox/')
When I test this it only stores the /new_sandbox/
part of the code.
The Question Comments :
The Answer 1
453 people think this answer is useful
The latter strings shouldn’t start with a slash. If they start with a slash, then they’re considered an “absolute path” and everything before them is discarded.
Quoting the Python docs for os.path.join
:
If a component is an absolute path, all previous components are thrown away and joining continues from the absolute path component.
Note on Windows, the behaviour in relation to drive letters, which seems to have changed compared to earlier Python versions:
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
.
The Answer 2
152 people think this answer is useful
The idea of os.path.join()
is to make your program cross-platform (linux/windows/etc).
Even one slash ruins it.
So it only makes sense when being used with some kind of a reference point like
os.environ['HOME']
or os.path.dirname(__file__)
.
The Answer 3
75 people think this answer is useful
os.path.join()
can be used in conjunction with os.path.sep
to create an absolute rather than relative path.
os.path.join(os.path.sep, 'home','build','test','sandboxes',todaystr,'new_sandbox')
The Answer 4
27 people think this answer is useful
Do not use forward slashes at the beginning of path components, except when refering to the root directory:
os.path.join('/home/build/test/sandboxes', todaystr, 'new_sandbox')
see also: http://docs.python.org/library/os.path.html#os.path.join
The Answer 5
21 people think this answer is useful
To help understand why this surprising behavior isn’t entirely terrible, consider an application which accepts a config file name as an argument:
config_root = "/etc/myapp.conf/"
file_name = os.path.join(config_root, sys.argv[1])
If the application is executed with:
$ myapp foo.conf
The config file /etc/myapp.conf/foo.conf
will be used.
But consider what happens if the application is called with:
$ myapp /some/path/bar.conf
Then myapp
should use the config file at /some/path/bar.conf
(and not /etc/myapp.conf/some/path/bar.conf
or similar).
It may not be great, but I believe this is the motivation for the absolute path behaviour.
The Answer 6
12 people think this answer is useful
It’s because your '/new_sandbox/'
begins with a /
and thus is assumed to be relative to the root directory. Remove the leading /
.
The Answer 7
9 people think this answer is useful
Try combo of split("/")
and *
for strings with existing joins.
import os
home = '/home/build/test/sandboxes/'
todaystr = '042118'
new = '/new_sandbox/'
os.path.join(*home.split("/"), todaystr, *new.split("/"))
How it works…
split("/")
turns existing path into list: ['', 'home', 'build', 'test', 'sandboxes', '']
*
in front of the list breaks out each item of list its own parameter
The Answer 8
8 people think this answer is useful
To make your function more portable, use it as such:
os.path.join(os.sep, 'home', 'build', 'test', 'sandboxes', todaystr, 'new_sandbox')
or
os.path.join(os.environ.get("HOME"), 'test', 'sandboxes', todaystr, 'new_sandbox')
The Answer 9
3 people think this answer is useful
Try with new_sandbox
only
os.path.join('/home/build/test/sandboxes/', todaystr, 'new_sandbox')
The Answer 10
2 people think this answer is useful
do it like this, without too the extra slashes
root="/home"
os.path.join(root,"build","test","sandboxes",todaystr,"new_sandbox")
The Answer 11
0 people think this answer is useful
Note that a similar issue can bite you if you use os.path.join()
to include an extension that already includes a dot, which is what happens automatically when you use os.path.splitext()
. In this example:
components = os.path.splitext(filename)
prefix = components[0]
extension = components[1]
return os.path.join("avatars", instance.username, prefix, extension)
Even though extension
might be .jpg
you end up with a folder named “foobar” rather than a file called “foobar.jpg”. To prevent this you need to append the extension separately:
return os.path.join("avatars", instance.username, prefix) + extension
The Answer 12
0 people think this answer is useful
you can strip
the '/'
:
>>> os.path.join('/home/build/test/sandboxes/', todaystr, '/new_sandbox/'.strip('/'))
'/home/build/test/sandboxes/04122019/new_sandbox'
The Answer 13
0 people think this answer is useful
I’d recommend to strip from the second and the following strings the string os.path.sep
, preventing them to be interpreted as absolute paths:
first_path_str = '/home/build/test/sandboxes/'
original_other_path_to_append_ls = [todaystr, '/new_sandbox/']
other_path_to_append_ls = [
i_path.strip(os.path.sep) for i_path in original_other_path_to_append_ls
]
output_path = os.path.join(first_path_str, *other_path_to_append_ls)
The Answer 14
0 people think this answer is useful
os.path.join("a", *"/b".split(os.sep))
'a/b'
a fuller version:
import os
def join (p, f, sep = os.sep):
f = os.path.normpath(f)
if p == "":
return (f);
else:
p = os.path.normpath(p)
return (os.path.join(p, *f.split(os.sep)))
def test (p, f, sep = os.sep):
print("os.path.join({}, {}) => {}".format(p, f, os.path.join(p, f)))
print(" join({}, {}) => {}".format(p, f, join(p, f, sep)))
if __name__ == "__main__":
# /a/b/c for all
test("\\a\\b", "\\c", "\\") # optionally pass in the sep you are using locally
test("/a/b", "/c", "/")
test("/a/b", "c")
test("/a/b/", "c")
test("", "/c")
test("", "c")