diff --git a/sphinx/builders/html/__init__.py b/sphinx/builders/html/__init__.py
index 0dd25fbb644..9a1001fceaf 100644
--- a/sphinx/builders/html/__init__.py
+++ b/sphinx/builders/html/__init__.py
@@ -20,7 +20,6 @@
from docutils.core import Publisher
from docutils.frontend import OptionParser
from docutils.io import DocTreeInput, StringOutput
-from docutils.utils import relative_path
from sphinx import __display_version__, package_dir
from sphinx import version_info as sphinx_version
@@ -56,6 +55,7 @@
from sphinx.util.osutil import (
SEP,
_last_modified_time,
+ _relative_path,
copyfile,
ensuredir,
relative_uri,
@@ -795,7 +795,7 @@ def copy_image_files(self) -> None:
def copy_download_files(self) -> None:
def to_relpath(f: str) -> str:
- return relative_path(self.srcdir, f)
+ return _relative_path(Path(f), self.srcdir).as_posix()
# copy downloadable files
if self.env.dlfiles:
diff --git a/sphinx/environment/collectors/asset.py b/sphinx/environment/collectors/asset.py
index e7d976682b0..44f72294520 100644
--- a/sphinx/environment/collectors/asset.py
+++ b/sphinx/environment/collectors/asset.py
@@ -5,10 +5,10 @@
import os
import os.path
from glob import glob
+from pathlib import Path
from typing import TYPE_CHECKING
from docutils import nodes
-from docutils.utils import relative_path
from sphinx import addnodes
from sphinx.environment.collectors import EnvironmentCollector
@@ -16,6 +16,7 @@
from sphinx.util import logging
from sphinx.util.i18n import get_image_filename_for_language, search_image_for_language
from sphinx.util.images import guess_mimetype
+from sphinx.util.osutil import _relative_path
if TYPE_CHECKING:
from docutils.nodes import Node
@@ -110,14 +111,14 @@ def collect_candidates(
) -> None:
globbed: dict[str, list[str]] = {}
for filename in glob(imgpath):
- new_imgpath = relative_path(os.path.join(env.srcdir, 'dummy'), filename)
+ new_imgpath = _relative_path(Path(filename), env.srcdir)
try:
mimetype = guess_mimetype(filename)
if mimetype is None:
basename, suffix = os.path.splitext(filename)
mimetype = 'image/x-' + suffix[1:]
if mimetype not in candidates:
- globbed.setdefault(mimetype, []).append(new_imgpath)
+ globbed.setdefault(mimetype, []).append(new_imgpath.as_posix())
except OSError as err:
logger.warning(
__('image file %s not readable: %s'),
diff --git a/sphinx/environment/collectors/dependencies.py b/sphinx/environment/collectors/dependencies.py
index 30701314be3..d77731218b1 100644
--- a/sphinx/environment/collectors/dependencies.py
+++ b/sphinx/environment/collectors/dependencies.py
@@ -2,14 +2,11 @@
from __future__ import annotations
-import os
-import os.path
+from pathlib import Path
from typing import TYPE_CHECKING
-from docutils.utils import relative_path
-
from sphinx.environment.collectors import EnvironmentCollector
-from sphinx.util.osutil import fs_encoding
+from sphinx.util.osutil import _relative_path, fs_encoding
if TYPE_CHECKING:
from docutils import nodes
@@ -38,8 +35,7 @@ def merge_other(
def process_doc(self, app: Sphinx, doctree: nodes.document) -> None:
"""Process docutils-generated dependency info."""
- cwd = os.getcwd()
- frompath = os.path.join(os.path.normpath(app.srcdir), 'dummy')
+ cwd = Path.cwd()
deps = doctree.settings.record_dependencies
if not deps:
return
@@ -48,7 +44,7 @@ def process_doc(self, app: Sphinx, doctree: nodes.document) -> None:
# one relative to the srcdir
if isinstance(dep, bytes):
dep = dep.decode(fs_encoding)
- relpath = relative_path(frompath, os.path.normpath(os.path.join(cwd, dep)))
+ relpath = _relative_path(cwd / dep, app.srcdir)
app.env.note_dependency(relpath)
diff --git a/sphinx/ext/intersphinx/_resolve.py b/sphinx/ext/intersphinx/_resolve.py
index be279b8c350..0dbab63dc69 100644
--- a/sphinx/ext/intersphinx/_resolve.py
+++ b/sphinx/ext/intersphinx/_resolve.py
@@ -2,12 +2,11 @@
from __future__ import annotations
-import posixpath
import re
+from pathlib import Path
from typing import TYPE_CHECKING, cast
from docutils import nodes
-from docutils.utils import relative_path
from sphinx.addnodes import pending_xref
from sphinx.deprecation import _deprecation_warning
@@ -16,6 +15,7 @@
from sphinx.locale import _, __
from sphinx.transforms.post_transforms import ReferencesResolver
from sphinx.util.docutils import CustomReSTDispatcher, SphinxRole
+from sphinx.util.osutil import _relative_path
if TYPE_CHECKING:
from collections.abc import Iterable
@@ -42,7 +42,7 @@ def _create_element_from_result(
proj, version, uri, dispname = data
if '://' not in uri and node.get('refdoc'):
# get correct path in case of subdirectories
- uri = posixpath.join(relative_path(node['refdoc'], '.'), uri)
+ uri = (_relative_path(Path(), Path(node['refdoc']).parent) / uri).as_posix()
if version:
reftitle = _('(in %s v%s)') % (proj, version)
else:
diff --git a/sphinx/util/fileutil.py b/sphinx/util/fileutil.py
index acd52b07674..d5e2e2692d5 100644
--- a/sphinx/util/fileutil.py
+++ b/sphinx/util/fileutil.py
@@ -7,11 +7,9 @@
from pathlib import Path
from typing import TYPE_CHECKING, Any
-from docutils.utils import relative_path
-
from sphinx.locale import __
from sphinx.util import logging
-from sphinx.util.osutil import copyfile, ensuredir
+from sphinx.util.osutil import _relative_path, copyfile, ensuredir
if TYPE_CHECKING:
from collections.abc import Callable
@@ -125,7 +123,8 @@ def copy_asset(
:param onerror: The error handler.
:param bool force: Overwrite the destination file even if it exists.
"""
- if not os.path.exists(source):
+ source = Path(source)
+ if not source.exists():
return
if renderer is None:
@@ -134,14 +133,14 @@ def copy_asset(
renderer = SphinxRenderer()
ensuredir(destination)
- if os.path.isfile(source):
+ if source.is_file():
copy_asset_file(
source, destination, context=context, renderer=renderer, force=force
)
return
for root, dirs, files in os.walk(source, followlinks=True):
- reldir = relative_path(source, root)
+ reldir = _relative_path(Path(root), source).as_posix()
for dir in dirs.copy():
if excluded(posixpath.join(reldir, dir)):
dirs.remove(dir)