175e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chenimport os 275e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chenimport sys 375e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen 475e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chentry: 575e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen from functools import wraps 675e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chenexcept ImportError: 775e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen # only needed for Python 2.4 875e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen def wraps(_): 975e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen def _wraps(func): 1075e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen return func 1175e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen return _wraps 1275e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen 1375e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen__unittest = True 1475e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen 1575e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chendef _relpath_nt(path, start=os.path.curdir): 1675e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen """Return a relative version of a path""" 1775e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen 1875e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen if not path: 1975e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen raise ValueError("no path specified") 2075e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen start_list = os.path.abspath(start).split(os.path.sep) 2175e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen path_list = os.path.abspath(path).split(os.path.sep) 2275e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen if start_list[0].lower() != path_list[0].lower(): 2375e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen unc_path, rest = os.path.splitunc(path) 2475e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen unc_start, rest = os.path.splitunc(start) 2575e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen if bool(unc_path) ^ bool(unc_start): 2675e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)" 2775e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen % (path, start)) 2875e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen else: 2975e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen raise ValueError("path is on drive %s, start on drive %s" 3075e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen % (path_list[0], start_list[0])) 3175e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen # Work out how much of the filepath is shared by start and path. 3275e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen for i in range(min(len(start_list), len(path_list))): 3375e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen if start_list[i].lower() != path_list[i].lower(): 3475e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen break 3575e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen else: 3675e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen i += 1 3775e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen 3875e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:] 3975e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen if not rel_list: 4075e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen return os.path.curdir 4175e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen return os.path.join(*rel_list) 4275e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen 4375e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen# default to posixpath definition 4475e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chendef _relpath_posix(path, start=os.path.curdir): 4575e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen """Return a relative version of a path""" 4675e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen 4775e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen if not path: 4875e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen raise ValueError("no path specified") 4975e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen 5075e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen start_list = os.path.abspath(start).split(os.path.sep) 5175e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen path_list = os.path.abspath(path).split(os.path.sep) 5275e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen 5375e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen # Work out how much of the filepath is shared by start and path. 5475e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen i = len(os.path.commonprefix([start_list, path_list])) 5575e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen 5675e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:] 5775e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen if not rel_list: 5875e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen return os.path.curdir 5975e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen return os.path.join(*rel_list) 6075e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen 6175e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chenif os.path is sys.modules.get('ntpath'): 6275e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen relpath = _relpath_nt 6375e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chenelse: 6475e28f942c1b9f9c6d5a0d5f2efd037cbbc9fc74Johnny Chen relpath = _relpath_posix 65