diff --git a/CHANGES b/CHANGES index 184365670af..70eaf1094f4 100644 --- a/CHANGES +++ b/CHANGES @@ -58,6 +58,7 @@ Features added * LaTeX: new key ``'fvset'`` for :confval:`latex_elements`. For XeLaTeX/LuaLaTeX its default sets ``fanvyvrb`` to use normal, not small, fontsize in code-blocks (refs: #4793) +* Improve warning messages during including (refs: #4818) Bugs fixed ---------- diff --git a/sphinx/directives/other.py b/sphinx/directives/other.py index 4509994359f..81cf64dc0c0 100644 --- a/sphinx/directives/other.py +++ b/sphinx/directives/other.py @@ -7,6 +7,8 @@ :license: BSD, see LICENSE for details. """ +from contextlib import contextmanager + from docutils import nodes from docutils.parsers.rst import directives from docutils.parsers.rst.directives.admonitions import BaseAdmonition @@ -25,7 +27,7 @@ if False: # For type annotation - from typing import Any, Dict, List, Tuple # NOQA + from typing import Any, Dict, Generator, List, Tuple # NOQA from sphinx.application import Sphinx # NOQA @@ -426,6 +428,7 @@ class Include(BaseInclude, SphinxDirective): def run(self): # type: () -> List[nodes.Node] + current_filename = self.env.doc2path(self.env.docname) if self.arguments[0].startswith('<') and \ self.arguments[0].endswith('>'): # docutils "standard" includes, do not do path processing @@ -433,7 +436,27 @@ def run(self): rel_filename, filename = self.env.relfn2path(self.arguments[0]) self.arguments[0] = filename self.env.note_included(filename) - return BaseInclude.run(self) + with patched_warnings(self, current_filename): + return BaseInclude.run(self) + + +@contextmanager +def patched_warnings(directive, parent_filename): + # type: (BaseInclude, unicode) -> Generator[None, None, None] + """Add includee filename to the warnings during inclusion.""" + try: + original = directive.state_machine.insert_input + + def insert_input(input_lines, source): + # type: (Any, unicode) -> None + source += ' ' % parent_filename + original(input_lines, source) + + # patch insert_input() temporarily + directive.state_machine.insert_input = insert_input + yield + finally: + directive.state_machine.insert_input = original def setup(app):