4

Consider the following:

>>> from django.conf import settings
>>> import os
>>> settings.VIRTUAL_ENV
'C:/Users/Marcin/Documents/oneclickcos'
>>> settings.EXTRA_BASE
'/oneclickcos/'
>>> os.path.join(settings.VIRTUAL_ENV,settings.EXTRA_BASE)
'/oneclickcos/'

As you can imagine, I neither expect nor want the concatenation of 'C:/Users/Marcin/Documents/oneclickcos' and '/oneclickcos/' to be '/oneclickcos/'.

Oddly enough, reversing the path components once again shows python ignoring the first path component:

>>> os.path.join(settings.EXTRA_BASE,settings.VIRTUAL_ENV)
'C:/Users/Marcin/Documents/oneclickcos'

While this works something like expected:

>>> os.path.join('/foobar',settings.VIRTUAL_ENV,'barfoo')
'C:/Users/Marcin/Documents/oneclickcos\\barfoo'

I am of course, running on Windows (Windows 7), with the native python.

Why is this happening, and what can I do about it?

2 Answers 2

8

That's pretty much how os.path.join is defined (quoting the docs):

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 I'd say it's usually a good thing, as it avoids creating invalid paths. If you want to avoid this behavior, don't feed it absolute paths. Yes, starting with a slash qualifies as absolute path. A quick and dirty solution is just removing the leading slash (settings.EXTRA_BASE.lstrip('/') if you want to do it programmatically).

Sign up to request clarification or add additional context in comments.

3 Comments

OK, thanks, but in what sense is '/foo/' an absolute path on windows? This strikes me as surprising, and platform-inconsistent behaviour.
It's a drive-absolute path. It would actually make sense to keep the drive letter from the first element: os.path.join('C:\\Users\\Marcin', '\\oneclickos\\') -> 'C:\\oneclickos\\' but that's not how it works.
It isn't inconsistent at all if you ask me. Starting with a directory seperator means absolute path on many (all?) other platforms as well. You may object to the lack of a drive letter, but my memory and Wikipedia say it's perfectly valid and simply refers to an absolute path on the same drive.
4

Remove the leading / from the second string:

>>> os.path.join('C:/Users/Marcin/Documents/oneclickcos', 'oneclickos/')
'C:/Users/Marcin/Documents/oneclickcos\\oneclickos/'

This is because os.path.join discards all previous components once it meets an absolute path, and /oneclickos/ is an absolute path.

Here's an excerpt from the doc of os.path.join:

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. [...]

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.