Python os.path.join on Windows

PythonWindowsPath Manipulation

Python Problem Overview


I am trying to learn python and am making a program that will output a script. I want to use os.path.join, but am pretty confused. According to the docs if I say:

os.path.join('c:', 'sourcedir')

I get "C:sourcedir". According to the docs, this is normal, right?

But when I use the copytree command, Python will output it the desired way, for example:

import shutil
src = os.path.join('c:', 'src')
dst = os.path.join('c:', 'dst')
shutil.copytree(src, dst)

Here is the error code I get:

WindowsError: [Error 3] The system cannot find the path specified: 'C:src/.'

If I wrap the os.path.join with os.path.normpath I get the same error.

If this os.path.join can't be used this way, then I am confused as to its purpose.

According to the pages suggested by Stack Overflow, slashes should not be used in join—that is correct, I assume?

Python Solutions


Solution 1 - Python

To be even more pedantic, the most python doc consistent answer would be:

mypath = os.path.join('c:', os.sep, 'sourcedir')

Since you also need os.sep for the posix root path:

mypath = os.path.join(os.sep, 'usr', 'lib')

Solution 2 - Python

Windows has a concept of current directory for each drive. Because of that, "c:sourcedir" means "sourcedir" inside the current C: directory, and you'll need to specify an absolute directory.

Any of these should work and give the same result, but I don't have a Windows VM fired up at the moment to double check:

"c:/sourcedir"
os.path.join("/", "c:", "sourcedir")
os.path.join("c:/", "sourcedir")

Solution 3 - Python

To be pedantic, it's probably not good to hardcode either / or \ as the path separator. Maybe this would be best?

mypath = os.path.join('c:%s' % os.sep, 'sourcedir')

or

mypath = os.path.join('c:' + os.sep, 'sourcedir')

Solution 4 - Python

The reason os.path.join('C:', 'src') is not working as you expect is because of something in the documentation that you linked to:

> Note that on Windows, 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.

As ghostdog said, you probably want mypath=os.path.join('c:\\', 'sourcedir')

Solution 5 - Python

For a system-agnostic solution that works on both Windows and Linux, no matter what the input path, one could use os.path.join(os.sep, rootdir + os.sep, targetdir)

On WIndows:

>>> os.path.join(os.sep, "C:" + os.sep, "Windows")
'C:\\Windows'

On Linux:

>>> os.path.join(os.sep, "usr" + os.sep, "lib")
'/usr/lib'

Solution 6 - Python

I'd say this is a (windows)python bug.

Why bug?

I think this statement should be True

os.path.join(*os.path.dirname(os.path.abspath(__file__)).split(os.path.sep))==os.path.dirname(os.path.abspath(__file__))

But it is False on windows machines.

Solution 7 - Python

to join a windows path, try

mypath=os.path.join('c:\\', 'sourcedir')

basically, you will need to escape the slash

Solution 8 - Python

You have a few possible approaches to treat path on Windows, from the most hardcoded ones (as using raw string literals or escaping backslashes) to the least ones. Here follows a few examples that will work as expected. Use what better fits your needs.

In[1]: from os.path import join, isdir

In[2]: from os import sep

In[3]: isdir(join("c:", "\\", "Users"))
Out[3]: True

In[4]: isdir(join("c:", "/", "Users"))
Out[4]: True

In[5]: isdir(join("c:", sep, "Users"))
Out[5]: True

Solution 9 - Python

Consent with @georg-

I would say then why we need lame os.path.join- better to use str.join or unicode.join e.g.

sys.path.append('{0}'.join(os.path.dirname(__file__).split(os.path.sep)[0:-1]).format(os.path.sep))

Solution 10 - Python

answering to your comment : "the others '//' 'c:', 'c:\' did not work (C:\\ created two backslashes, C:\ didn't work at all)"

On windows using os.path.join('c:', 'sourcedir') will automatically add two backslashes \\ in front of sourcedir.

To resolve the path, as python works on windows also with forward slashes -> '/', simply add .replace('\\','/') with os.path.join as below:-

os.path.join('c:\\', 'sourcedir').replace('\\','/')

e.g: os.path.join('c:\\', 'temp').replace('\\','/')

output : 'C:/temp'

Solution 11 - Python

The proposed solutions are interesting and offer a good reference, however they are only partially satisfying. It is ok to manually add the separator when you have a single specific case or you know the format of the input string, but there can be cases where you want to do it programmatically on generic inputs.

With a bit of experimenting, I believe the criteria is that the path delimiter is not added if the first segment is a drive letter, meaning a single letter followed by a colon, no matter if it corresponds to a real unit.

For example:

import os
testval = ['c:','c:\\','d:','j:','jr:','data:']

for t in testval:
    print ('test value: ',t,', join to "folder"',os.path.join(t,'folder'))

> test value: c: , join to "folder" c:folder > test value: c:\ , join to "folder" c:\folder > test value: d: , join to "folder" d:folder > test value: j: , join to "folder" j:folder > test value: jr: , join to "folder" jr:\folder > test value: data: , join to "folder" data:\folder

A convenient way to test for the criteria and apply a path correction can be to use os.path.splitdrive comparing the first returned element to the test value, like t+os.path.sep if os.path.splitdrive(t)[0]==t else t.

Test:

for t in testval:
    corrected = t+os.path.sep if os.path.splitdrive(t)[0]==t else t
    print ('original: %s\tcorrected: %s'%(t,corrected),' join corrected->',os.path.join(corrected,'folder'))

> original: c: corrected: c:\ join corrected-> c:\folder > original: c:\ corrected: c:\ join corrected-> c:\folder > original: d: corrected: d:\ join corrected-> d:\folder > original: j: corrected: j:\ join corrected-> j:\folder > original: jr: corrected: jr: join corrected-> jr:\folder > original: data: corrected: data: join corrected-> data:\folder

it can be probably be improved to be more robust for trailing spaces, and I have tested it only on windows, but I hope it gives an idea. See also https://stackoverflow.com/questions/182253/os-path-can-you-explain-this-behavior for interesting details on systems other then windows.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFrank E.View Question on Stackoverflow
Solution 1 - PythonAndreasTView Answer on Stackoverflow
Solution 2 - PythonRoger PateView Answer on Stackoverflow
Solution 3 - PythonMatt BallView Answer on Stackoverflow
Solution 4 - PythonSmasheryView Answer on Stackoverflow
Solution 5 - PythonScott GiganteView Answer on Stackoverflow
Solution 6 - PythongeorgView Answer on Stackoverflow
Solution 7 - Pythonghostdog74View Answer on Stackoverflow
Solution 8 - PythonMarco GomezView Answer on Stackoverflow
Solution 9 - PythonSIslamView Answer on Stackoverflow
Solution 10 - PythonPratulView Answer on Stackoverflow
Solution 11 - PythonVincenzoooView Answer on Stackoverflow