10

Can all paths in a Python program use ".." (for the parent directory) and / (for separating path components), and still work whatever the platform?

On one hand, I have never seen such a claim in the documentation (I may have missed it), and the os and os.path modules do provide facilities for handling paths in a platform agnostic way (os.pardir, os.path.join,…), which lets me think that they are here for a reason.

On the other hand, you can read on StackOverflow that "../path/to/file" works on all platforms…

So, should os.pardir, os.path.join and friends always be used, for portability purposes, or are Unix path names always safe (up to possible character encoding issues)? or maybe "almost always" safe (i.e. working under Windows, OS X, and Linux)?

jww
  • 97,681
  • 90
  • 411
  • 885
Eric O. Lebigot
  • 91,433
  • 48
  • 218
  • 260

7 Answers7

11

I've never had any problems with using .., although it might be a good idea to convert it to an absolute path using os.path.abspath. Secondly, I would recommend always using os.path.join whereever possible. There are a lot of corner cases (aside from portability issues) in joining paths, and it's good not to have to worry about them. For instance:

>>> '/foo/bar/' + 'qux'
'/foo/bar/qux'
>>> '/foo/bar' + 'qux'
'/foo/barqux'
>>> from os.path import join
>>> join('/foo/bar/', 'qux')
'/foo/bar/qux'
>>> join('/foo/bar', 'qux')
'/foo/bar/qux'

You may run into problems with using .. if you're on some obscure platforms, but I can't name any (Windows, *nix, and OS X all support that notation).

Jason Baker
  • 192,085
  • 135
  • 376
  • 510
6

"Almost always safe" is right. All of the platforms you care about probably work ok today and I don't think they will be changing their conventions any time soon.

However Python is very portable and runs on a lot more than the usual platforms. The reason for the os module is to help smooth things over it a platform does have different requirements.

Is there a good reason for you to not use the os functions?

os.pardir is self documenting whereas ".." isn't, and os.pardir might be easier to grep for

Here is some docs from python 1.6 when Mac was still different for everything

OS routines for Mac, DOS, NT, or Posix depending on what system we're on.

This exports: - all functions from posix, nt, dos, os2, mac, or ce, e.g. unlink, stat, etc. - os.path is one of the modules posixpath, ntpath, macpath, or dospath - os.name is 'posix', 'nt', 'dos', 'os2', 'mac', or 'ce' - os.curdir is a string representing the current directory ('.' or ':') - os.pardir is a string representing the parent directory ('..' or '::') - os.sep is the (or a most common) pathname separator ('/' or ':' or '\') - os.altsep is the alternate pathname separator (None or '/') - os.pathsep is the component separator used in $PATH etc - os.linesep is the line separator in text files (' ' or ' ' or ' ') - os.defpath is the default search path for executables

Programs that import and use 'os' stand a better chance of being portable between different platforms. Of course, they must then only use functions that are defined by all platforms (e.g., unlink and opendir), and leave all pathname manipulation to os.path (e.g., split and join).

Ranjith Ramachandra
  • 10,399
  • 14
  • 59
  • 96
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • The reason why I was thinking of bypassing os.path and co. is that it is simpler and quite clear to write "../dir1/dir2/dir3/file" instead of using os.path.join(os.pardir, ['dir1', 'dir2', 'dir3', 'file'])! – Eric O. Lebigot Oct 27 '09 at 21:58
  • @EOL I can't think of too many real programs that need that. Perhaps it makes sense to move a path like that out into a config file. – John La Rooy Oct 27 '09 at 22:58
  • @gnibbler My programs analyze thousands of sets of data, and store results in conventional locations, where directory names are computed from the "name" of each data set. But yeah, os.path.join(os.pardir,…) is almost as short as the direct path coding. – Eric O. Lebigot Oct 28 '09 at 08:49
  • Is the fact that Python on Windows accepts "/" in paths documented somewhere? I can't find this… – Eric O. Lebigot Nov 22 '14 at 14:30
  • 1
    @EOL, It's not Python - it's in the [windows api](http://msdn.microsoft.com/en-us/library/aa365247.aspx) "Note File I/O functions in the Windows API convert "/" to "\" as part of converting the name to an NT-style name, except when using the "\\?\" prefix as detailed in the following sections." – John La Rooy Nov 22 '14 at 18:24
  • Thanks! I wish that the Python doc said that Python follows this convention—in principle it does not have too, even though not following it would complicate things for no good reason. :) The emphasis on the general `os.sep`, `os.join()`, etc. features made me wonder whether `/` had to work on Windows. Now I see that these facilities are mostly for more obscure operating systems (non-Windows, non-Unix/Linux/OS X). – Eric O. Lebigot Nov 23 '14 at 02:59
3

Within python, using / will always work. You will need to be aware of the OS convention if you want to execute a command in a subshell

myprog = "/path/to/my/program"
os.system([myprog, "-n"])                           # 1
os.system([myprog, "C:/input/file/to/myprog"])      # 2

Command #1 will probably work as expected.
Command #2 might not work if myprog is a Windows command and expects to parse its command line arguments to get a Windows file name.

mob
  • 117,087
  • 18
  • 149
  • 283
  • 1
    just a side note - never use `os.system` to run programs. it takes a string (not a list as you used), and needlessy invokes a shell. Use the `subprocess` module instead. – nosklo Oct 28 '09 at 10:46
3

Windows supports / as a path separator. The only incompatibilities between Unix filenames and Windows filenames are:

  • the allowed characters in filenames
  • the special names and
  • case sensitivity

Windows is more restrictive in the first two accounts (this is, it has more forbidden characters and more special names), while Unix is typically case sensitive. There are some answers here listing exactly what are these characters and names. I'll see if I can find them.

Now, if your development environment comes with a function to create or manipulate paths, you should use it, it's there for a reason, y'know. Especially given that there are a lot more platforms than Windows and Unix.

Answering your first question, yes ../dir/file will work, unless they hit some of the above mentioned incompatibilities.

Community
  • 1
  • 1
Vinko Vrsalovic
  • 330,807
  • 53
  • 334
  • 373
3

It works on Windows, so if you define "whatever the platform" to be Unix and Windows, you're fine.

On the other hand, Python also runs on VMS, RISC OS, and other odd platforms that use completely different filename conventions. However, it's probable that trying to get your application to run on VMS, blind, is kind of silly anyway - "premature portability is the root of some relatively minor evil"

I like using the os.path functions anyway because they are good for expressing intent - instead of just a string concatenation, which might be done for any of a million purposes, it reads very explicitly as a path manipulation.

Jack Lloyd
  • 8,215
  • 2
  • 37
  • 47
1

OS/X and Linux are both Unix compatible, so by definition they use the format you gave at the beginning of the question. Windows allows "/" in addition to "\" so that programs could be interchangeable with Xenix, a Unix variant that Microsoft was trying out a long time ago, and that compatibility has been carried forward to the present. Thus it works too.

I don't know how many other platforms Python has been ported to, and I can't speak for them.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
0

As others have said, a forward slash will work in all cases, but you're better off creating a list of path segments and os.path.join()-ing them.

jcdyer
  • 18,616
  • 5
  • 42
  • 49