From d4a84e3fc81b920be4ab07f9be0b54e62c8e8286 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Wed, 9 Oct 2024 01:23:07 +0100 Subject: [PATCH] tmp --- sphinx/builders/__init__.py | 17 ++-- sphinx/directives/__init__.py | 9 +- sphinx/domains/__init__.py | 7 +- sphinx/domains/python/__init__.py | 15 ++-- sphinx/environment/__init__.py | 1 + sphinx/testing/restructuredtext.py | 9 +- sphinx/util/docutils.py | 82 +++++++++++-------- .../test_directive_object_description.py | 7 +- tests/test_markup/test_markup.py | 5 +- 9 files changed, 82 insertions(+), 70 deletions(-) diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py index 1420417380d..22253c55b25 100644 --- a/sphinx/builders/__init__.py +++ b/sphinx/builders/__init__.py @@ -605,22 +605,23 @@ def merge(docs: list[str], otherenv: bytes) -> None: @final def read_doc(self, docname: str, *, _cache: bool = True) -> None: """Parse a file and add/update inventory entries for the doctree.""" - self.env.prepare_settings(docname) + env = self.env + env.prepare_settings(docname) # Add confdir/docutils.conf to dependencies list if exists docutilsconf = os.path.join(self.confdir, 'docutils.conf') if os.path.isfile(docutilsconf): - self.env.note_dependency(docutilsconf) + env.note_dependency(docutilsconf) - filename = str(self.env.doc2path(docname)) + filename = str(env.doc2path(docname)) filetype = get_filetype(self.app.config.source_suffix, filename) publisher = self.app.registry.get_publisher(self.app, filetype) - self.env.temp_data['_parser'] = publisher.parser + env.temp_data['_parser'] = publisher.parser # record_dependencies is mutable even though it is in settings, # explicitly re-initialise for each document publisher.settings.record_dependencies = DependencyList() with ( - sphinx_domains(self.env), + sphinx_domains(domains=env.domains, temp_data=env.temp_data), rst.default_role(docname, self.config.default_role), ): # set up error_handler for the target document @@ -632,11 +633,11 @@ def read_doc(self, docname: str, *, _cache: bool = True) -> None: doctree = publisher.document # store time of reading, for outdated files detection - self.env.all_docs[docname] = time.time_ns() // 1_000 + env.all_docs[docname] = time.time_ns() // 1_000 # cleanup - self.env.temp_data.clear() - self.env.ref_context.clear() + env.temp_data.clear() + env.ref_context.clear() self.write_doctree(docname, doctree, _cache=_cache) diff --git a/sphinx/directives/__init__.py b/sphinx/directives/__init__.py index 181c6f81a07..07d2178f940 100644 --- a/sphinx/directives/__init__.py +++ b/sphinx/directives/__init__.py @@ -358,13 +358,8 @@ class DefaultDomain(SphinxDirective): def run(self) -> list[Node]: domain_name = self.arguments[0].lower() - # if domain_name not in env.domains: - # # try searching by label - # for domain in env.domains.sorted(): - # if domain.label.lower() == domain_name: - # domain_name = domain.name - # break - self.env.temp_data['default_domain'] = self.env.domains.get(domain_name) + default_domain = self.env.domains.get(domain_name) + self.env.temp_data['default_domain'] = default_domain return [] diff --git a/sphinx/domains/__init__.py b/sphinx/domains/__init__.py index 3f21078c6c5..921808927b1 100644 --- a/sphinx/domains/__init__.py +++ b/sphinx/domains/__init__.py @@ -107,6 +107,7 @@ class Domain: data_version = 0 def __init__(self, env: BuildEnvironment) -> None: + domaindata = env.domaindata self.env: BuildEnvironment = env self._role_cache: dict[str, Callable] = {} self._directive_cache: dict[str, Callable] = {} @@ -119,13 +120,13 @@ def __init__(self, env: BuildEnvironment) -> None: self.roles = dict(self.roles) self.indices = list(self.indices) - if self.name not in env.domaindata: + if self.name not in domaindata: assert isinstance(self.initial_data, dict) new_data = copy.deepcopy(self.initial_data) new_data['version'] = self.data_version - self.data = env.domaindata[self.name] = new_data + self.data = domaindata[self.name] = new_data else: - self.data = env.domaindata[self.name] + self.data = domaindata[self.name] if self.data['version'] != self.data_version: raise OSError('data of %r domain out of date' % self.label) for name, obj in self.object_types.items(): diff --git a/sphinx/domains/python/__init__.py b/sphinx/domains/python/__init__.py index 24dfc2a5756..d41dc495e6a 100644 --- a/sphinx/domains/python/__init__.py +++ b/sphinx/domains/python/__init__.py @@ -560,16 +560,13 @@ class PythonModuleIndex(Index): shortname = _('modules') domain: PythonDomain - def generate(self, docnames: Iterable[str] | None = None, - ) -> tuple[list[tuple[str, list[IndexEntry]]], bool]: + def generate( + self, docnames: Iterable[str] | None = None + ) -> tuple[list[tuple[str, list[IndexEntry]]], bool]: doc_names = frozenset(docnames) if docnames is not None else None - content: dict[str, list[IndexEntry]] = {} # list of prefixes to ignore - ignores: list[str] = sorted( - self.domain.env.config['modindex_common_prefix'], key=len, reverse=True - ) - + ignores: list[str] = sorted(self.domain.modindex_common_prefix, key=len, reverse=True) # list of all modules, sorted by module name modules = sorted(self.domain.modules.items(), key=lambda t: t[0].lower()) @@ -706,6 +703,10 @@ class PythonDomain(Domain): PythonModuleIndex, ] + def __init__(self, env: BuildEnvironment) -> None: + super().__init__(env) + self.modindex_common_prefix = env.config.modindex_common_prefix + @property def objects(self) -> dict[str, ObjectEntry]: return self.data.setdefault('objects', {}) # fullname -> ObjectEntry diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index b17c1ee453b..be2bdd99436 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -264,6 +264,7 @@ def setup(self, app: Sphinx) -> None: ) # setup domains (must do after all initialization) self.domains._setup() + _a = 1 # Initialise config. # The old config is self.config, restored from the pickled environment. diff --git a/sphinx/testing/restructuredtext.py b/sphinx/testing/restructuredtext.py index 620e8483492..e3c9aa60dfd 100644 --- a/sphinx/testing/restructuredtext.py +++ b/sphinx/testing/restructuredtext.py @@ -9,20 +9,21 @@ def parse(app: Sphinx, text: str, docname: str = 'index') -> nodes.document: """Parse a string as reStructuredText with Sphinx application.""" + env = app.env try: - app.env.temp_data['docname'] = docname + env.temp_data['docname'] = docname reader = SphinxStandaloneReader() reader.setup(app) parser = RSTParser() parser.set_application(app) - with sphinx_domains(app.env): + with sphinx_domains(domains=env.domains, temp_data=env.temp_data): return publish_doctree( text, str(app.srcdir / f'{docname}.rst'), reader=reader, parser=parser, settings_overrides={ - 'env': app.env, + 'env': env, 'gettext_compact': True, 'input_encoding': 'utf-8', 'output_encoding': 'unicode', @@ -30,4 +31,4 @@ def parse(app: Sphinx, text: str, docname: str = 'index') -> nodes.document: }, ) finally: - app.env.temp_data.pop('docname', None) + env.temp_data.pop('docname', None) diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index 87823bd69fd..14a75ee7723 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -19,7 +19,7 @@ from docutils.utils import Reporter, unescape from sphinx.errors import SphinxError -from sphinx.locale import _, __ +from sphinx.locale import __ from sphinx.util import logging from sphinx.util.parsing import nested_parse_to_nodes @@ -37,6 +37,7 @@ from sphinx.builders import Builder from sphinx.config import Config + from sphinx.domains import _DomainsContainer from sphinx.environment import BuildEnvironment from sphinx.util.typing import RoleFunction @@ -262,52 +263,42 @@ class sphinx_domains(CustomReSTDispatcher): markup takes precedence. """ - def __init__(self, env: BuildEnvironment) -> None: - self.env = env + def __init__( + self, *, domains: _DomainsContainer, temp_data: dict[str, Any] + ) -> None: + self.domains = domains + self.temp_data = temp_data super().__init__() - def lookup_domain_element(self, type: str, name: str) -> Any: - """Lookup a markup element (directive or role), given its name which can - be a full name (with domain). - """ - name = name.lower() + def directive( + self, + directive_name: str, + language_module: ModuleType, + document: nodes.document, + ) -> tuple[type[Directive] | None, list[system_message]]: + domain_name, _, name = directive_name.lower().rpartition(':') # explicit domain given? - if ':' in name: - domain_name, name = name.split(':', 1) - if domain_name in self.env.domains: - domain = self.env.get_domain(domain_name) - element = getattr(domain, type)(name) + if domain_name: + if domain_name in self.domains: + element = self.domains[domain_name].directive(name) if element is not None: return element, [] else: - logger.warning( - _('unknown directive or role name: %s:%s'), domain_name, name - ) + logger.warning(__('unknown directive name: %s'), directive_name.lower()) # else look in the default domain else: - def_domain = self.env.temp_data.get('default_domain') - if def_domain is not None: - element = getattr(def_domain, type)(name) + default_domain = self.temp_data.get('default_domain') + if default_domain is not None: + element = default_domain.directive(name) if element is not None: return element, [] # always look in the std domain - element = getattr(self.env.domains.standard_domain, type)(name) + element = self.domains.standard_domain.directive(name) if element is not None: return element, [] - raise ElementLookupError - - def directive( - self, - directive_name: str, - language_module: ModuleType, - document: nodes.document, - ) -> tuple[type[Directive] | None, list[system_message]]: - try: - return self.lookup_domain_element('directive', directive_name) - except ElementLookupError: - return super().directive(directive_name, language_module, document) + return super().directive(directive_name, language_module, document) def role( self, @@ -316,10 +307,29 @@ def role( lineno: int, reporter: Reporter, ) -> tuple[RoleFunction, list[system_message]]: - try: - return self.lookup_domain_element('role', role_name) - except ElementLookupError: - return super().role(role_name, language_module, lineno, reporter) + domain_name, _, name = role_name.lower().rpartition(':') + # explicit domain given? + if domain_name: + if domain_name in self.domains: + element = self.domains[domain_name].role(name) + if element is not None: + return element, [] + else: + logger.warning(__('unknown role name: %s'), role_name.lower()) + # else look in the default domain + else: + default_domain = self.temp_data.get('default_domain') + if default_domain is not None: + element = default_domain.role(name) + if element is not None: + return element, [] + + # always look in the std domain + element = self.domains.standard_domain.role(name) + if element is not None: + return element, [] + + return super().role(role_name, language_module, lineno, reporter) class WarningStream: diff --git a/tests/test_directives/test_directive_object_description.py b/tests/test_directives/test_directive_object_description.py index 7f3ffba633a..41aac6e2c91 100644 --- a/tests/test_directives/test_directive_object_description.py +++ b/tests/test_directives/test_directive_object_description.py @@ -18,10 +18,11 @@ def _doctree_for_test(builder: Builder, docname: str) -> nodes.document: - builder.env.prepare_settings(docname) + env = builder.env + env.prepare_settings(docname) publisher = create_publisher(builder.app, 'restructuredtext') - with sphinx_domains(builder.env): - publisher.set_source(source_path=str(builder.env.doc2path(docname))) + with sphinx_domains(domains=env.domains, temp_data=env.temp_data): + publisher.set_source(source_path=str(env.doc2path(docname))) publisher.publish() return publisher.document diff --git a/tests/test_markup/test_markup.py b/tests/test_markup/test_markup.py index 9eb0b83fa89..5295bd14c56 100644 --- a/tests/test_markup/test_markup.py +++ b/tests/test_markup/test_markup.py @@ -24,6 +24,7 @@ @pytest.fixture def settings(app): + env = app.builder.env texescape.init() # otherwise done by the latex builder with warnings.catch_warnings(): warnings.filterwarnings('ignore', category=DeprecationWarning) @@ -35,10 +36,10 @@ def settings(app): ) settings = optparser.get_default_values() settings.smart_quotes = True - settings.env = app.builder.env + settings.env = env settings.env.temp_data['docname'] = 'dummy' settings.contentsname = 'dummy' - domain_context = sphinx_domains(settings.env) + domain_context = sphinx_domains(domains=env.domains, temp_data=env.temp_data) domain_context.enable() yield settings domain_context.disable()