Skip to content

Sphinx 8.2.0: relative path for html_static_path induce copy error (windows) #13376

@mutricyl

Description

@mutricyl

Describe the bug

Hello,

I had no issue with generating my doc with sphinx 8.1.3 but upgrading to 8.2.0 the following warning message appeared:

copying assets... 
copying static files... 
Writing evaluated template result to C:\CALC\DEV\MCI\doc\_build\html\_static\basic.css
Writing evaluated template result to C:\CALC\DEV\MCI\doc\_build\html\_static\documentation_options.js
Writing evaluated template result to C:\CALC\DEV\MCI\doc\_build\html\_static\language_data.js
Writing evaluated template result to C:\CALC\DEV\MCI\doc\_build\html\_static\js\versions.js
copying static files: failed
WARNING: cannot copy static file OSError(22, 'La syntaxe du nom de fichier, de répertoire ou de volume est incorrecte')
copying extra files... 
copying extra files: done
copying assets: done
writing output... [100%] user

Investigating a little bit, it showed that my html_static_path was not copied.

extract of my conf.py:

html_theme = 'sphinx_rtd_theme'
html_static_path = ['../_static']

# Change the default css style to allow for wider "text column" and wrap word
# in tables.
html_style = 'css/mystyle.css'

Checking the sphinx.util.fileutil.copy_asset function and particularly

for root, dirs, files in os.walk(source, followlinks=True):
reldir = _relative_path(Path(root), source).as_posix()
for dir in dirs.copy():
if excluded(posixpath.join(reldir, dir)):
dirs.remove(dir)
else:
ensuredir(posixpath.join(destination, reldir, dir))
it looks like _relative_path function should always return a relative path otherwise when you join destination with reldir and dir the resulting path is not valid which creates the OSError above.

May I suggest to add pathlib.Path().resolve() within _relative_path :

def _relative_path(path: Path, root: Path, /) -> Path:
    """Return a relative filepath to *path* from the given *root* directory.

    This is an alternative of ``Path.relative_to``.
    It returns the original path if *path* and *root* are on different drives,
    which may happen on Windows.
    """
    path = path.resolve()
    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))
    return path.relative_to(root, walk_up=True)

How to Reproduce

mkdir source
mkdir static
echo "test" > source\index.rst
echo "" > static\static.css
echo html_static_path = ['../static'] > source\conf.py
sphinx-build -M html source build
(...)
WARNING: Failed to copy a file in html_static_file: C:\CALC\DEV\sphinx-bug\source\..\static/static.css: OSError(22, 'La syntaxe du nom de fichier, de répertoire ou de volume est incorrecte', None, 123, None)
(...)

Environment Information

Platform:              win32; (Windows-10-10.0.19045-SP0)
Python version:        3.12.9 | packaged by Anaconda, Inc. | (main, Feb  6 2025, 18:49:16) [MSC v.1929 64 bit (AMD64)])
Python implementation: CPython
Sphinx version:        8.2.0
Docutils version:      0.21.2
Jinja2 version:        3.1.4
Pygments version:      2.18.0

Sphinx extensions

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions