Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emit "source-read" events for files read via the include directive #11510

Merged
merged 29 commits into from
Aug 14, 2023
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
2497401
Add test that exposes issue 10678
halldorfannar Jul 24, 2023
1e0c93c
Subclass docutils RSTParser to fix issue
halldorfannar Jul 24, 2023
b61e2bf
Improve test
halldorfannar Jul 24, 2023
552ecd5
Improve test and fix issues uncovered.
halldorfannar Jul 24, 2023
2fad0bc
Add CHANGES entry
halldorfannar Jul 24, 2023
1ab3d66
Address feedback from GitHub CI
halldorfannar Jul 24, 2023
78c1e3f
More clean-up to appease the style gods
halldorfannar Jul 24, 2023
a084948
Trailing whitespaces removed
halldorfannar Jul 24, 2023
4c727ce
Fix unit tests
halldorfannar Jul 25, 2023
1759ebd
Fix formatting in CHANGE entry
halldorfannar Jul 25, 2023
68ca10b
Improve comment
halldorfannar Jul 25, 2023
db5eef4
Use :dudir: to refer to include directive
halldorfannar Jul 25, 2023
a76918f
Revert "Fix unit tests"
halldorfannar Jul 25, 2023
9cd7205
Change approach
halldorfannar Jul 25, 2023
8d2f487
Fix test failure on Windows
halldorfannar Jul 25, 2023
e953025
Merge branch 'issue-10678' of https://github.com/halldorfannar/sphinx…
halldorfannar Jul 25, 2023
9712e58
Add type: ignore to work around known issue
halldorfannar Jul 31, 2023
876e039
Address flake8 issue
halldorfannar Jul 31, 2023
4e7749b
Merge branch '7.1.x' into issue-10678
halldorfannar Jul 31, 2023
3f165cd
Adjust CHANGES
halldorfannar Jul 31, 2023
db8c4e9
Add space to silence flake8
halldorfannar Jul 31, 2023
4e66777
Merge branch '7.1.x' into issue-10678
halldorfannar Aug 2, 2023
3682fb1
Merge branch 'master' into issue-10678
AA-Turner Aug 3, 2023
62584d9
Merge branch 'master' into issue-10678
AA-Turner Aug 5, 2023
c87cf13
Update sphinx/directives/other.py
halldorfannar Aug 7, 2023
fa70d06
Merge branch 'master' into issue-10678
AA-Turner Aug 11, 2023
1dba6ff
Formatting
AA-Turner Aug 11, 2023
16afce6
Merge branch 'master' into issue-10678
AA-Turner Aug 14, 2023
9550b09
Only patch if there are source-read listeners
AA-Turner Aug 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ Features added
* #11572: Improve ``debug`` logging of reasons why files are detected as out of
date.
Patch by Eric Larson.
* #10678: Emit "source-read" events for files read via
AA-Turner marked this conversation as resolved.
Show resolved Hide resolved
the :dudir:`include` directive.
Patch by Halldor Fannar.

Bugs fixed
----------
Expand Down
34 changes: 34 additions & 0 deletions sphinx/directives/other.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from docutils.parsers.rst.directives.admonitions import BaseAdmonition
from docutils.parsers.rst.directives.misc import Class
from docutils.parsers.rst.directives.misc import Include as BaseInclude
from docutils.statemachine import StateMachine

from sphinx import addnodes
from sphinx.domains.changeset import VersionChange # noqa: F401 # for compatibility
Expand All @@ -18,6 +19,7 @@
from sphinx.util.docutils import SphinxDirective
from sphinx.util.matching import Matcher, patfilter
from sphinx.util.nodes import explicit_title_re
from sphinx.util.osutil import os_path
from sphinx.util.typing import OptionSpec

if TYPE_CHECKING:
Expand Down Expand Up @@ -368,6 +370,38 @@ class Include(BaseInclude, SphinxDirective):
"""

def run(self) -> list[Node]:

# To properly emit "source-read" events from included RST text,
# we must patch the ``StateMachine.insert_input()`` method.
# In the future, docutils will hopefully offer a way for Sphinx
# to provide the RST parser to use
# when parsing RST text that comes in via Include directive.
def _insert_input(include_lines, path):
# First, we need to combine the lines back into text so that
# we can send it with the source-read event.
# In docutils 0.18 and later, there are two lines at the end
# that act as markers.
# We must preserve them and leave them out of the source-read event:
text = "\n".join(include_lines[:-2])

# The docname to pass into the source-read event
docname = self.env.path2doc(os_path(path))
# Emit the "source-read" event
arg = [text]
self.env.app.events.emit("source-read", docname, arg)
text = arg[0]

# Split back into lines and reattach the two marker lines
include_lines = text.splitlines() + include_lines[-2:]

# Call the parent implementation.
# Note that this snake does not eat its tail because we patch
# the *Instance* method and this call is to the *Class* method.
return StateMachine.insert_input(self.state_machine, include_lines, path)

# See https://github.com/python/mypy/issues/2427 for details on the mypy issue
self.state_machine.insert_input = _insert_input # type: ignore[method-assign]

if self.arguments[0].startswith('<') and \
self.arguments[0].endswith('>'):
# docutils "standard" includes, do not do path processing
Expand Down
6 changes: 6 additions & 0 deletions tests/roots/test-directive-include/baz/baz.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Baz
===

.. include:: foo.rst

Baz was here.
2 changes: 2 additions & 0 deletions tests/roots/test-directive-include/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
project = 'test-directive-include'
exclude_patterns = ['_build']
1 change: 1 addition & 0 deletions tests/roots/test-directive-include/foo.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The #magical foo.
1 change: 1 addition & 0 deletions tests/roots/test-directive-include/text.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is plain text.
37 changes: 37 additions & 0 deletions tests/test_directive_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,40 @@ def test_toctree_twice(app):
assert_node(doctree[0][0],
entries=[(None, 'foo'), (None, 'foo')],
includefiles=['foo', 'foo'])


@pytest.mark.sphinx(testroot='directive-include')
def test_include_source_read_event(app):
sources_reported = {}

def source_read_handler(app, doc, source):
sources_reported[doc] = source[0]

app.connect("source-read", source_read_handler)
AA-Turner marked this conversation as resolved.
Show resolved Hide resolved
text = (".. include:: baz/baz.rst\n"
" :start-line: 4\n\n"
".. include:: text.txt\n"
" :literal: \n")
app.env.find_files(app.config, app.builder)
restructuredtext.parse(app, text, 'index')
assert "index" in sources_reported
assert "text.txt" not in sources_reported # text was included as literal, no rst parsing
assert "baz/baz" in sources_reported
assert sources_reported["baz/baz"] == "\nBaz was here."


@pytest.mark.sphinx(testroot='directive-include')
def test_include_source_read_event_nested_includes(app):

def source_read_handler(app, doc, source):
text = source[0].replace("#magical", "amazing")
source[0] = text

app.connect("source-read", source_read_handler)
text = (".. include:: baz/baz.rst\n")
app.env.find_files(app.config, app.builder)
doctree = restructuredtext.parse(app, text, 'index')
assert_node(doctree, addnodes.document)
assert len(doctree.children) == 3
assert_node(doctree.children[1], nodes.paragraph)
assert doctree.children[1].rawsource == "The amazing foo."