71

I'd like to construct an absolute path in python, while at the same time staying fairly oblivious of things like path-separator.

edit0: for instance there is a directory on the root of my filesystem /etc/init.d (or C:\etc\init.d on w32), and I want to construct this only from the elements etc and init.d (on w32, I probably also need a disk-ID, like C:)

In order to not having to worry about path-separators, os.join.path() is obviously the tool of choice. But it seems that this will only ever create relative paths:

 print("MYPATH: %s" % (os.path.join('etc', 'init.d'),)
 MYPATH: etc/init.d

Adding a dummy first-element (e.g. '') doesn't help anything:

 print("MYPATH: %s" % (os.path.join('', 'etc', 'init.d'),)
 MYPATH: etc/init.d

Making the first element absolute obviously helps, but this kind of defeats the idea of using os.path.join()

 print("MYPATH: %s" % (os.path.join('/etc', 'init.d'),)
 MYPATH: /etc/init.d

edit1: using os.path.abspath() will only try to convert a relative path into an absolute path. e.g. consider running the following in the working directory /home/foo:

 print("MYPATH: %s" % (os.path.abspath(os.path.join('etc', 'init.d')),)
 MYPATH: /home/foo/etc/init.d

So, what is the standard cross-platform way to "root" a path?

 root = ??? # <--
 print("MYPATH: %s" % (os.path.join(root, 'etc', 'init.d'),)
 MYPATH: /etc/init.d

edit2: the question really boils down to: since the leading slash in /etc/init.d makes this path an absolute path, is there a way to construct this leading slash programmatically? (I do not want to make assumptions that a leading slash indicates an absolute path)

umläute
  • 28,885
  • 9
  • 68
  • 122
  • 1
    I'm not sure I'm reading your question correctly, but could you simply: `os.path.abspath('python.exe')` which on my windows machine returns `'C:\\Python27\\python.exe'` – Brad Jul 02 '13 at 15:18
  • i've updated the question to (hopefully) clarify what i want. – umläute Jul 02 '13 at 15:40
  • 1
    btw, relevant near-duplicate: http://stackoverflow.com/questions/12041525/a-system-independent-way-using-python-to-get-the-root-directory-drive-on-which-p – Christoph Jul 02 '13 at 16:19
  • None of these answers work for me. How can I join `root_dir="C:/Users/folder"` with `filename="data/file1.txt"` to get an absolute path? In not-windows it's easy with just `os.path.join(root_dir, filename)`, but I can't find a solution in Windows. – mikey Jun 09 '20 at 20:41

5 Answers5

96

Using os.sep as root worked for me:

path.join(os.sep, 'python', 'bin')

Linux: /python/bin

Windows: \python\bin

Adding path.abspath() to the mix will give you drive letters on Windows as well and is still compatible with Linux:

path.abspath(path.join(os.sep, 'python', 'bin'))

Linux: /python/bin

Windows: C:\python\bin

girardc79
  • 1,058
  • 7
  • 6
  • 3
    Seems to work on Linux and Win, so +1. But *feels* wrong. Might break on some other obscure system, but I can think of none. Still feels like python should give us an explicit way to do that. This depends on absolute paths starting with the path-separator. – kratenko Aug 09 '16 at 09:40
4

I think you can use os.path.normpath. Here's what I get on Windows:

>>> os.path.normpath("/etc/init.d")
'\\etc\\init.d'

I'm not sure exactly what the right thing to do with the drive prefix is, but I think leaving it off means something like "keep using the drive I'm on now," which is probably what you want. Maybe someone more familiar with Windows can clarify?

Jack O'Connor
  • 10,068
  • 4
  • 48
  • 53
  • 1
    this is the right answer, let python do the work of figuring out which platform you're on – hobs Aug 17 '18 at 05:47
  • I agree with the sentiment, yet this uses a fully qualified path and NOT `os.path.join()`. While it is useful to know, it does not qualify as a solution. – Nomen Nescio Nov 19 '20 at 20:07
2

so the solution i came up with, is to construct the root of the filesystem by following a given file to it's root:

def getRoot(file=None):
  if file is None:
      file='.'
  me=os.path.abspath(file)
  drive,path=os.path.splitdrive(me)
  while 1:
    path,folder=os.path.split(path)
    if not folder:
       break
  return drive+path

 os.path.join(getRoot(), 'etc', 'init.d')
umläute
  • 28,885
  • 9
  • 68
  • 122
  • could even be simpler: drive,path=os.path.splitdrive(me) if not drive: return os.path.split(path)[0] else: return drive – Christoph Jul 02 '13 at 16:20
  • hmm, i'm sure that my solution is not the most pythonic way; but your solution will return `/foo/bar/baz` if the file evaulates to `/foo/bar/baz` (basically the problem you mentioned for Ansuman's answer) – umläute Jul 02 '13 at 16:30
  • darn it, you're right. got misled by another answer on SO >. – Christoph Jul 03 '13 at 07:49
  • 1
    I find this interesting but I am somewhat puzzled on the reason why it is still the accepted answer. – Patrick Trentin Mar 28 '19 at 12:28
1

So you can do a check for running os by sys.platfrom

on windows

>>> sys.platform
'win32'

on linux

>>> sys.platform
'linux2'

then

if sys.platform == 'win32':
    ROOT = os.path.splitdrive(os.path.abspath('.'))[0]
elif sys.platform == 'linux2':
    ROOT = os.sep

Please note that 'linux2' may not cover all linux distros

Ansuman Bebarta
  • 7,011
  • 6
  • 27
  • 44
  • no, i really want the ROOT of my filesystem (regardless where the python modules are located). `os.path.abspath('foo')` will return (e.g.) `/home/me/foo` (if i run it within `/home/me`) while i really need `/foo` (or `C:\\foo`) – umläute Jul 02 '13 at 15:32
  • i've updated the question to clarify why `os.path.abspath()` does not seem to help me. – umläute Jul 02 '13 at 15:41
  • If you want to have a ROOT which is not based on file and same ROOT for all files in a specific project. Than you can store the ROOT (a string value) in a config file or you can define a ROOT by hardcoded values in all the file. I have added this in my answer. – Ansuman Bebarta Jul 02 '13 at 15:54
  • the question is: what makes `/etc` an absolute path? (obviously the `/` prefix, but is there a programmatic way to get this suffix?) – umläute Jul 02 '13 at 15:56
  • OK. I think I got it. There is os.path.splitdrive() which returns you the drive os.path.splitdrive(os.path.abspath('.')) but on linux it will not return you the root ie. '/' – Ansuman Bebarta Jul 02 '13 at 16:03
  • doesn't work for if you're deeper in a directory tree, e.g.: In [3]: os.path.split(os.path.abspath('.')) Out[3]: ('/home', 'username') – Christoph Jul 02 '13 at 16:13
  • hmm, this will give me nothing on osx and gnu/hurd; with "cross-platform" i had "not having to care about the platform" in mind, not "discussing each platform manually" – umläute Jul 02 '13 at 16:35
-1

you could try with os.path.splitdrive to get the name of your drive/filesystem, then join this with your foo string.

http://docs.python.org/2/library/os.path.html#os.path.splitdrive

something like (untested!)

(drive, tail) = os.path.splitdrive(os.getcwd())
os.path.join(drive, 'foo')

should do the trick.

Christoph
  • 5,480
  • 6
  • 36
  • 61
  • 1
    doesn't work on linux - drive gets set to '' and joining with that doesn't give a rooted path – mheyman Feb 07 '17 at 17:46