Search code examples
pythonwindowspathrelative-pathabsolute-path

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.


Solution

  • 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.