From cf7da1843c45a4c2df7a749f7886a2d2ba0ee92a Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 19:25:40 +0200 Subject: Adding upstream version 7.2.6. Signed-off-by: Daniel Baumann --- sphinx/io.py | 189 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 sphinx/io.py (limited to 'sphinx/io.py') diff --git a/sphinx/io.py b/sphinx/io.py new file mode 100644 index 0000000..4874fdf --- /dev/null +++ b/sphinx/io.py @@ -0,0 +1,189 @@ +"""Input/Output files""" +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +import docutils +from docutils import nodes +from docutils.core import Publisher +from docutils.io import FileInput, Input, NullOutput +from docutils.readers import standalone +from docutils.transforms.references import DanglingReferences +from docutils.writers import UnfilteredWriter + +from sphinx import addnodes +from sphinx.transforms import AutoIndexUpgrader, DoctreeReadEvent, SphinxTransformer +from sphinx.transforms.i18n import ( + Locale, + PreserveTranslatableMessages, + RemoveTranslatableInline, +) +from sphinx.transforms.references import SphinxDomains +from sphinx.util import logging +from sphinx.util.docutils import LoggingReporter +from sphinx.versioning import UIDTransform + +if TYPE_CHECKING: + from docutils.frontend import Values + from docutils.parsers import Parser + from docutils.transforms import Transform + + from sphinx.application import Sphinx + from sphinx.environment import BuildEnvironment + + +logger = logging.getLogger(__name__) + + +class SphinxBaseReader(standalone.Reader): + """ + A base class of readers for Sphinx. + + This replaces reporter by Sphinx's on generating document. + """ + + transforms: list[type[Transform]] = [] + + def __init__(self, *args: Any, **kwargs: Any) -> None: + from sphinx.application import Sphinx + if len(args) > 0 and isinstance(args[0], Sphinx): + self._app = args[0] + self._env = self._app.env + args = args[1:] + + super().__init__(*args, **kwargs) + + def setup(self, app: Sphinx) -> None: + self._app = app # hold application object only for compatibility + self._env = app.env + + def get_transforms(self) -> list[type[Transform]]: + transforms = super().get_transforms() + self.transforms + + # remove transforms which is not needed for Sphinx + unused = [DanglingReferences] + for transform in unused: + if transform in transforms: + transforms.remove(transform) + + return transforms + + def new_document(self) -> nodes.document: + """ + Creates a new document object which has a special reporter object good + for logging. + """ + document = super().new_document() + document.__class__ = addnodes.document # replace the class with patched version + + # substitute transformer + document.transformer = SphinxTransformer(document) + document.transformer.set_environment(self.settings.env) + + # substitute reporter + reporter = document.reporter + document.reporter = LoggingReporter.from_reporter(reporter) + + return document + + +class SphinxStandaloneReader(SphinxBaseReader): + """ + A basic document reader for Sphinx. + """ + + def setup(self, app: Sphinx) -> None: + self.transforms = self.transforms + app.registry.get_transforms() + super().setup(app) + + def read(self, source: Input, parser: Parser, settings: Values) -> nodes.document: + self.source = source + if not self.parser: + self.parser = parser + self.settings = settings + self.input = self.read_source(settings.env) + self.parse() + return self.document + + def read_source(self, env: BuildEnvironment) -> str: + """Read content from source and do post-process.""" + content = self.source.read() + + # emit "source-read" event + arg = [content] + env.events.emit('source-read', env.docname, arg) + return arg[0] + + +class SphinxI18nReader(SphinxBaseReader): + """ + A document reader for i18n. + + This returns the source line number of original text as current source line number + to let users know where the error happened. + Because the translated texts are partial and they don't have correct line numbers. + """ + + def setup(self, app: Sphinx) -> None: + super().setup(app) + + self.transforms = self.transforms + app.registry.get_transforms() + unused = [PreserveTranslatableMessages, Locale, RemoveTranslatableInline, + AutoIndexUpgrader, SphinxDomains, DoctreeReadEvent, + UIDTransform] + for transform in unused: + if transform in self.transforms: + self.transforms.remove(transform) + + +class SphinxDummyWriter(UnfilteredWriter): + """Dummy writer module used for generating doctree.""" + + supported = ('html',) # needed to keep "meta" nodes + + def translate(self) -> None: + pass + + +def SphinxDummySourceClass(source: Any, *args: Any, **kwargs: Any) -> Any: + """Bypass source object as is to cheat Publisher.""" + return source + + +class SphinxFileInput(FileInput): + """A basic FileInput for Sphinx.""" + def __init__(self, *args: Any, **kwargs: Any) -> None: + kwargs['error_handler'] = 'sphinx' + super().__init__(*args, **kwargs) + + +def create_publisher(app: Sphinx, filetype: str) -> Publisher: + reader = SphinxStandaloneReader() + reader.setup(app) + + parser = app.registry.create_source_parser(app, filetype) + if parser.__class__.__name__ == 'CommonMarkParser' and parser.settings_spec == (): + # a workaround for recommonmark + # If recommonmark.AutoStrictify is enabled, the parser invokes reST parser + # internally. But recommonmark-0.4.0 does not provide settings_spec for reST + # parser. As a workaround, this copies settings_spec for RSTParser to the + # CommonMarkParser. + from docutils.parsers.rst import Parser as RSTParser + + parser.settings_spec = RSTParser.settings_spec + + pub = Publisher( + reader=reader, + parser=parser, + writer=SphinxDummyWriter(), + source_class=SphinxFileInput, + destination=NullOutput(), + ) + # Propagate exceptions by default when used programmatically: + defaults = {"traceback": True, **app.env.settings} + # Set default settings + if docutils.__version_info__[:2] >= (0, 19): + pub.get_settings(**defaults) + else: + pub.settings = pub.setup_option_parser(**defaults).get_default_values() + return pub -- cgit v1.2.3