Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

os.path.join - can I get consistency between Windows and Cygwin?

I would quite like a set of filename components that will give me consistent and "nice-looking" filenames on both Windows and Cygwin. Here's what I've tried:

  Input                                Windows      Cygwin
1 os.path.join('c:', 'foo', 'bar')     c:foo\bar    c:/foo/bar
2 os.path.join('c:\\', 'foo', 'bar')   c:\foo\bar   c:\/foo/bar
3 os.path.join('c:/', 'foo', 'bar')    c:/foo\bar   c:/foo/bar

1 isn't what I want on Windows, I do want an absolute path, not relative to the current directory.

2 and 3 both work, but are not (I hereby define) "nice-looking" since they mix up forward and backward slashes on one platform or the other. My error and logging messages will be more readable if I can avoid this.

Option 4 is to define myself a driveroot variable equal to c:\ on Windows and /cygdrive/c on Cygwin. Or a function taking a drive letter and returning same. But I'd also prefer to avoid per-platform special cases between these two.

Can I have everything I want (join identical path components, to give a result that refers to the same absolute path on both platforms, and doesn't mix path separators on either platform)? Or do I have to compromise somewhere?

[Edit: in case it helps, the main use case is that c:\foo is a path that I know about at configuration time, whereas bar (and further components) are computed later. So my actual code currently looks a bit more like this:

dir = os.path.join('c:\\', 'foo')

# some time later

os.path.join(dir, 'bar')

That's using option 2, which results in "nice" reporting of filenames in Windows, but "not nice" reporting of filenames in Cygwin. What I want to avoid, if it's possible, is:

if this_is_cygwin():
    dir = '/cygdrive/c/foo'
else:
    dir = 'c:\\foo'

]

like image 253
Steve Jessop Avatar asked May 12 '11 11:05

Steve Jessop


1 Answers

Edit: David pointed out that my understanding of 'current directory' on Windows is wrong. Sorry. However, try using os.path.abspath to get nice pretty paths, or os.path.normpath if you don't need absolute paths.

In method 1,

os.path.join('c:', 'foo', 'bar')

The output, c:foo\bar, is correct. This means the path foo\bar below the current directory on c:, which is not the same thing as the root directory. os.path.join is doing exactly what you tell it to, which is to take c: (the current directory on drive c) and add some extra bits to it.

In method 2,

os.path.join(r'c:\', 'foo', 'bar')

The output for Cygwin is correct, because in Cygwin, c:\ is not the root of a drive.

What you want is the os.abspath function. This will give you the absolute, normalized version of the path that you give to it.

However: You won't get the same string on Cygwin and Windows. I hope you're not looking for that.

like image 51
Dietrich Epp Avatar answered Sep 25 '22 01:09

Dietrich Epp