I was able to implement your root_relative_path function using a combination of the posixpath and the pathlib modules. The result is
- Platform independent (as long as the root path corresponds to the current platform)
- The path can begin with
/
, ./
, or ../
- And the path will be normalized using all of the techniques covered by the normpath function which includes resolving
..
s.
from pathlib import Path
import posixpath
def root_relative_path(root : str, path : str) -> str:
''' Calculates the relative path with respect to the root.
Any ".."s in the relative path will be resolved,
but not in a way that would cause the relative path to go beyond the root. '''
# posixpath.normpath doesn't work as expected if the path doesn't start with a slash, so we make sure it does
if not path.startswith('/'):
path = '/' + path
# The normalization process includes resolving any ".."s
# we're only using posixpath for the relative portion of the path, the outcome will still be platform independent
path = posixpath.normpath(path)
# Remove the beginning slash so that we're not trying to join two absolute paths
path = path[1:]
joined = Path(root) / path
# Per the OPs requirements the result needed to be a string,
# But if you're allowed to use Pathlib objects, you could just return joined without converting it to a string
return str(joined)