Fix `_relative_path()` for unresolved paths

This commit is contained in:
Adam Turner committed 2025-02-21 23:19:10 +00:00
1 parent 1a3d1def22
commit 58e64d4016
4 files changed
+22 -2

No files matched your search

+2
View File
@@ -25,6 +25,8 @@ Bugs fixed
Patch by Dave Hoese.
* #13382: Napoleon: Use the right valid types for configuration values.
Patch by Adam Turner.
* 13376: Fix copying assets from a relative :confval:`html_static_path` entry.
Patch by Adam Turner.
Testing
-------
+2 -1
View File
@@ -140,7 +140,8 @@ def copy_asset(
return
for root, dirs, files in os.walk(source, followlinks=True):
reldir = _relative_path(Path(root), source).as_posix()
root_p = Path(root)
reldir = _relative_path(root_p, source).as_posix()
for dir in dirs.copy():
if excluded(posixpath.join(reldir, dir)):
dirs.remove(dir)
+6 -1
View File
@@ -177,9 +177,14 @@ def _relative_path(path: Path, root: Path, /) -> Path:
It returns the original path if *path* and *root* are on different drives,
which may happen on Windows.
"""
# Path.relative_to() requires fully-resolved paths (no '..').
if '..' in path.parts:
path = path.resolve()
if '..' in root.parts:
root = root.resolve()
if path.anchor != root.anchor or '..' in root.parts:
# If the drives are different, no relative path exists.
# Path.relative_to() requires fully-resolved paths (no '..').
return path
if sys.version_info[:2] < (3, 12):
return Path(os.path.relpath(path, root))
+12
View File
@@ -84,6 +84,10 @@ def test_copy_asset(tmp_path):
(source / '_templates' / 'sidebar.html.jinja').write_text(
'sidebar: {{var2}}', encoding='utf8'
)
sibling = tmp_path / 'sibling'
sibling.mkdir(parents=True, exist_ok=True)
sibling.joinpath('spam').mkdir(parents=True, exist_ok=True)
sibling.joinpath('spam', 'ham').touch()
# copy a single file
assert not (tmp_path / 'test1').exists()
@@ -126,6 +130,14 @@ def test_copy_asset(tmp_path):
assert (destdir / '_templates' / 'layout.html').exists()
assert not (destdir / '_templates' / 'sidebar.html').exists()
# copy sibling
assert not (tmp_path / 'test4').exists()
copy_asset(source / '../sibling', tmp_path / 'test4')
assert (tmp_path / 'test4').is_dir()
assert (tmp_path / 'test4' / 'spam').is_dir()
assert (tmp_path / 'test4' / 'spam' / 'ham').is_file()
assert (tmp_path / 'test4' / 'spam' / 'ham').read_bytes() == b''
@pytest.mark.sphinx('html', testroot='html_assets')
def test_copy_asset_template(app: SphinxTestApp) -> None: