Skip to content

🐛 Resolve links to documents that are symlinks - #1227

Open
nazarli-shabnam wants to merge 1 commit into
executablebooks:masterfrom
nazarli-shabnam:fix/1055-symlinked-doc-link
Open

nazarli-shabnam wants to merge 1 commit into
executablebooks:masterfrom
nazarli-shabnam:fix/1055-symlinked-doc-link

Conversation

@nazarli-shabnam

Copy link
Copy Markdown

Fixes #1055

Problem

A link to a document that is a symlink to a file outside the source directory is not rendered as a link. With docs/linked.md -> ../README.md, both of these

[Section title](linked.md#target-section)
[Section title](project:linked.md#target-section)

warn Unknown source document '/path/to/project/README' [myst.xref_missing].

render_link_project and render_link_unknown find the target with BuildEnvironment.relfn2path, which ends with .resolve() and so follows the symlink. Sphinx registers the document under the path of the symlink (docs/linked.md), so the resolved path (README.md) is not a document.

Fix

Add SphinxRenderer._link_target_path, which builds the absolute path the same way relfn2path does (a leading / is relative to the source directory, otherwise relative to the current document) but with os.path.normpath instead of .resolve(), and use it in the two places that look up a document from a link. relfn2path is still used by the include directive in mocking.py; following the symlink is fine there because it reads the file.

Tests

tests/test_sphinx/test_symlinked_docs.py builds a small project in tmp_path where docs/linked.md is a symlink to ../README.md, and checks that both link forms build without the warning and give href="linked.html#target-section". It is skipped where symlinks are not available. The project is created at run time because a symlink cannot be committed reliably (Windows checkouts).

  • Before the fix: both cases fail with Unknown source document '.../project/README'.
  • After the fix: both pass.
  • pytest tests with pip install -e ".[testing]" in a python:3.12 container (Sphinx 9.1.1, docutils 0.22.4): 1512 passed, 3 failed. The 3 failures were linkify tests, because I had not installed the linkify extra. With .[testing,linkify], pytest tests/test_renderers/test_myst_config.py tests/test_sphinx tests/test_html: 132 passed.

Not verified

  • Only Python 3.12 with Sphinx 9.1.1 was run, not the Sphinx 8 or Python 3.11/3.13/3.14 tox environments.
  • ruff, mypy and pre-commit were not run (not installed on my machine); I kept to the surrounding style and added type annotations.
  • Only a symlink to a file outside the source directory was tested. A symlink to a file inside it already worked and is covered by the existing tests only indirectly.
  • I did not add a CHANGELOG.md entry: the file has no unreleased section and recent fix PRs did not touch it.

AI disclosure

Claude (Anthropic) helped investigate the cause, write the fix and the test, and draft this description. I reviewed the diff.

A link such as `[text](doc.md#id)`, or `project:doc.md#id`, to a document
that is a symlink to a file outside the source directory warned
"Unknown source document" and was not rendered as a link.

The link target was found with `BuildEnvironment.relfn2path`, which
resolves symlinks. Sphinx registers the document under the path of the
symlink, so the path of its target is not a document.

Compute the absolute path of the target without following symlinks, in
the two places that look up a document from a link.

Closes executablebooks#1055

This branch has not been deployed

No deployments
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.

References to sections in symlinked files can fail

1 participant