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