Skip to content

fix: preserve symlink for include directive in relfn2path - #14638

Draft
aryansk wants to merge 1 commit into
sphinx-doc:masterfrom
aryansk:fix-symlink-toctree-14520
Draft

fix: preserve symlink for include directive in relfn2path#14638
aryansk wants to merge 1 commit into
sphinx-doc:masterfrom
aryansk:fix-symlink-toctree-14520

Conversation

@aryansk

@aryansk aryansk commented Aug 24, 2026

Copy link
Copy Markdown

Fixes #14520

Problem

Within doc/index.rst, we are including a doc/README.rst file, which is actually a symlink to the same file in the root directory. This layout works well until Sphinx 7, but starts failing on Sphinx 8 when running with -W: doc/README.rst: WARNING: document isn't included in any toctree [toc.not_included].

Demo: https://github.com/tech-writing/sphinx-symlink-regressiondoc/README.rst -> ../README.rst with .. include:: README.rst in doc/index.rst.

Change

  • In sphinx/environment/__init__.py:relfn2path — change Path(...).resolve() to Path(os.path.normpath(...)) (via Path(...).absolute() + os.path.normpath) so abs_fn stays as doc/README.rst (the symlink path inside srcdir) rather than resolving to ../README.rst outside srcdir. This preserves rel_fn as README.rst and note_included correctly maps to the README docname found via discover (which finds README.rst in doc as a file).

Keep unrelated cleanup out of this PR.

Why this approach

Sphinx 8 changed relfn2path to use Path.resolve() which follows symlinks. For doc/README.rst -> ../README.rst, resolve() makes abs_fn the target outside srcdir, so _relative_path becomes ../README.rst and path2doc fails to map to README. Using normpath without resolving keeps the symlink path inside srcdir, matching discover's README docname and fixing toc.not_included.

Testing

command: cd /tmp/sphinx-symlink-demo/doc && uv run --with='sphinx==7.*' sphinx-build -b html . _build7 -W
result: build succeeded (0 warnings)

command: cd /tmp/sphinx-symlink-demo/doc && uv run --with='sphinx==8.*' sphinx-build -b html . _build8 -W
result: 1 warning [toc.not_included] (repro)

command: PYTHONPATH=/tmp/sphinx-14520/repo uv run --with='sphinx==8.*' python -m sphinx -b html /tmp/sphinx-symlink-demo/doc /tmp/sphinx-14520/_build_test -W
result: build succeeded (0 warnings) with patched relfn2path

command: git diff --check
result: clean

Documentation and release impact

  • User-facing behavior fixed (include directive with symlinked README)
  • Changelog/release note needed: bug fix
  • Migration or compatibility note needed
  • No documentation impact

Review notes

  • Known limitations: none beyond symlink include
  • Follow-up issue, if any: none
  • Security/licensing considerations: none

Fixes sphinx-doc#14520

Sphinx 8 changed relfn2path to use Path.resolve() which follows
symlinks. For doc/README.rst -> ../README.rst (outside doc srcdir),
abs_fn resolved to the target outside doc, so rel_fn became
../README.rst and note_included failed to map it to the README docname
found via discover (README from doc/README.rst). This caused
'toc.not_included' warnings for symlinked README included via
.. include::.

Change relfn2path to use os.path.normpath without resolving symlinks,
so abs_fn stays as doc/README.rst (the symlink path) and rel_fn is
README.rst, correctly mapping to the README docname.

Validation: demo https://github.com/tech-writing/sphinx-symlink-regression
now builds with -W on Sphinx 8.2.3 and patched 9.1.1 (was 1 warning
before, 0 after); git diff --check clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Regression with Sphinx 8 and symlinks: document isn't included in any toctree [toc.not_included]

1 participant