From e11bf76919f4c2ccf6420fd7b4d2ab42901badf8 Mon Sep 17 00:00:00 2001 From: picnixz <10796600+picnixz@users.noreply.github.com> Date: Mon, 24 Jul 2023 12:35:12 +0200 Subject: [PATCH] Fix ``MemoryError`` in ``sphinx.ext.intersphinx`` when using ``None`` or ``typing.*`` as inline type references (#11338) Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com> --- CHANGES | 2 ++ sphinx/ext/intersphinx.py | 29 ++++++++++++++++++----------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/CHANGES b/CHANGES index 294e80e52..a527a7baf 100644 --- a/CHANGES +++ b/CHANGES @@ -58,6 +58,8 @@ Bugs fixed ... Patch by Bénédikt Tran. +* #11337: Fix a ``MemoryError`` in ``sphinx.ext.intersphinx`` when using ``None`` + or ``typing.*`` as inline type references. Patch by Bénédikt Tran (picnixz) Testing -------- diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index 3079849cf..a3d048e43 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -25,7 +25,7 @@ import re import sys import time from os import path -from typing import IO, TYPE_CHECKING, Any, cast +from typing import IO, TYPE_CHECKING, Any, Iterable, cast from urllib.parse import urlsplit, urlunsplit from docutils import nodes @@ -324,7 +324,7 @@ def _create_element_from_result(domain: Domain, inv_name: str | None, def _resolve_reference_in_domain_by_target( inv_name: str | None, inventory: Inventory, - domain: Domain, objtypes: list[str], + domain: Domain, objtypes: Iterable[str], target: str, node: pending_xref, contnode: TextElement) -> nodes.reference | None: for objtype in objtypes: @@ -357,24 +357,31 @@ def _resolve_reference_in_domain_by_target( def _resolve_reference_in_domain(env: BuildEnvironment, inv_name: str | None, inventory: Inventory, honor_disabled_refs: bool, - domain: Domain, objtypes: list[str], + domain: Domain, objtypes: Iterable[str], node: pending_xref, contnode: TextElement, ) -> nodes.reference | None: + obj_types: dict[str, None] = {}.fromkeys(objtypes) + # we adjust the object types for backwards compatibility - if domain.name == 'std' and 'cmdoption' in objtypes: + if domain.name == 'std' and 'cmdoption' in obj_types: # cmdoptions were stored as std:option until Sphinx 1.6 - objtypes.append('option') - if domain.name == 'py' and 'attribute' in objtypes: + obj_types['option'] = None + if domain.name == 'py' and 'attribute' in obj_types: # properties are stored as py:method since Sphinx 2.1 - objtypes.append('method') + obj_types['method'] = None # the inventory contains domain:type as objtype - objtypes = [f"{domain.name}:{t}" for t in objtypes] + domain_name = domain.name + obj_types = {f"{domain_name}:{obj_type}": None for obj_type in obj_types} # now that the objtypes list is complete we can remove the disabled ones if honor_disabled_refs: - disabled = env.config.intersphinx_disabled_reftypes - objtypes = [o for o in objtypes if o not in disabled] + disabled = set(env.config.intersphinx_disabled_reftypes) + obj_types = {obj_type: None + for obj_type in obj_types + if obj_type not in disabled} + + objtypes = [*obj_types.keys()] # without qualification res = _resolve_reference_in_domain_by_target(inv_name, inventory, domain, objtypes, @@ -405,7 +412,7 @@ def _resolve_reference(env: BuildEnvironment, inv_name: str | None, inventory: I if (honor_disabled_refs and (domain_name + ":*") in env.config.intersphinx_disabled_reftypes): continue - objtypes = list(domain.object_types) + objtypes: Iterable[str] = domain.object_types.keys() res = _resolve_reference_in_domain(env, inv_name, inventory, honor_disabled_refs, domain, objtypes,