finefoot
finefoot

Reputation: 11232

Convert Windows relative path to POSIX relative path so I can join POSIX absolute path and Windows relative path

I'm looking for a platform-independent solution. Everything works on Linux because os.walk already returns POSIX paths. However, if I'm on Windows I might get the following two paths:

abspath = "/x/y/z" # given path for a remote server which uses POSIX paths
relpath = "a\\b\\c" # acquired from local file system via os.walk, so it uses slash or backslash depending on the platform

The desired result of the joined path for this example would be:

'/x/y/z/a/b/c'

However, naturally, using posixpath.join results in:

>>> posixpath.join(abspath, relpath)
'/x/y/z/a\\b\\c'

So when I'm on Windows and have a relative path like a\\b\\c, I think it might make sense to convert it to a POSIX relative path a/b/c first, so I am able to use posixpath.join afterwards?

However, I don't believe simply replacing every backslash with a slash is best practice - or is it? I couldn't find any function which provides such a conversion.

Upvotes: 3

Views: 2810

Answers (2)

finefoot
finefoot

Reputation: 11232

Instead of using os which depends on the platform, or posixpath which will only work with POSIX paths, Python's pathlib module seems to be a good choice here:

This module offers classes representing filesystem paths with semantics appropriate for different operating systems

Here is a solution for the example from the question above:

import pathlib
def example(abspath, relpath):
    abspath = pathlib.PurePosixPath(abspath)
    relpath = pathlib.PurePath(relpath)
    return str(abspath / relpath)

pathlib.PurePosixPath is being used for abspath because the final path is supposed to be a POSIX path and pathlib.PurePath works on both Windows and Linux:

pathlib.PurePath - A generic class that represents the system’s path flavour (instantiating it creates either a PurePosixPath or a PureWindowsPath)

An example call on Linux might look like:

>>> import platform
>>> platform.system()
'Linux'
>>> example("/x/y/z", "a/b/c")
'/x/y/z/a/b/c'

An example call on Windows might look like:

>>> import platform
>>> platform.system()
'Windows'
>>> example("/x/y/z", "a\\b\\c")
'/x/y/z/a/b/c'

So it produces the correct POSIX path on both platforms.

Upvotes: 2

abdusco
abdusco

Reputation: 11091

Try using pathlib.Path, it handles the tricky parts of manipulating paths across platforms.

https://docs.python.org/3/library/pathlib.html

from pathlib import Path, PosixPath


if __name__ == '__main__':
    BASE_DIR = Path('/path/to/base')
    rel_path = r'path\to\rel'
    print(BASE_DIR)
    print(rel_path)
    print(BASE_DIR / rel_path)

output:

\path\to\base
path\to\rel
\path\to\base\path\to\rel

Upvotes: 3

Related Questions