mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Create a new type for the current document's environment state (#13151)
This commit is contained in:
parent
c7eaf175e6
commit
e65bbb96ae
@ -47,6 +47,52 @@ Build environment API
|
||||
|
||||
.. autoattribute:: parser
|
||||
|
||||
**Per-document attributes**
|
||||
|
||||
.. attribute:: current_document
|
||||
|
||||
Temporary data storage while reading a document.
|
||||
|
||||
Extensions may use the mapping interface provided by
|
||||
``env.current_document`` to store data relating to the current document,
|
||||
but should use a unique prefix to avoid name clashes.
|
||||
|
||||
.. important::
|
||||
Only the following attributes constitute the public API.
|
||||
The type itself and any methods or other attributes remain private,
|
||||
experimental, and will be changed or removed without notice.
|
||||
|
||||
.. attribute:: current_document.docname
|
||||
:type: str
|
||||
|
||||
The document name ('docname') for the current document.
|
||||
|
||||
.. attribute:: current_document.default_role
|
||||
:type: str
|
||||
|
||||
The default role for the current document.
|
||||
Set by the :dudir:`default-role` directive.
|
||||
|
||||
.. attribute:: current_document.default_domain
|
||||
:type: Domain | None
|
||||
|
||||
The default domain for the current document.
|
||||
Set by the :rst:dir:`default-domain` directive.
|
||||
|
||||
.. attribute:: current_document.highlight_language
|
||||
:type: str
|
||||
|
||||
The default language for syntax highlighting.
|
||||
Set by the :rst:dir:`highlight` directive to override
|
||||
the :confval:`highlight_language` config value.
|
||||
|
||||
.. attribute:: current_document._parser
|
||||
:type: Parser | None
|
||||
|
||||
*This attribute is experimental and may be changed without notice.*
|
||||
|
||||
The parser being used to parse the current document.
|
||||
|
||||
**Utility methods**
|
||||
|
||||
.. automethod:: doc2path
|
||||
|
@ -13,7 +13,12 @@ from typing import TYPE_CHECKING, Any, Literal, final
|
||||
from docutils import nodes
|
||||
from docutils.utils import DependencyList
|
||||
|
||||
from sphinx.environment import CONFIG_CHANGED_REASON, CONFIG_OK, BuildEnvironment
|
||||
from sphinx.environment import (
|
||||
CONFIG_CHANGED_REASON,
|
||||
CONFIG_OK,
|
||||
BuildEnvironment,
|
||||
_CurrentDocument,
|
||||
)
|
||||
from sphinx.environment.adapters.asset import ImageAdapter
|
||||
from sphinx.errors import SphinxError
|
||||
from sphinx.locale import __
|
||||
@ -620,7 +625,7 @@ class Builder:
|
||||
filename = str(self.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
|
||||
self.env.current_document._parser = publisher.parser
|
||||
# record_dependencies is mutable even though it is in settings,
|
||||
# explicitly re-initialise for each document
|
||||
publisher.settings.record_dependencies = DependencyList()
|
||||
@ -640,7 +645,7 @@ class Builder:
|
||||
self.env.all_docs[docname] = time.time_ns() // 1_000
|
||||
|
||||
# cleanup
|
||||
self.env.temp_data.clear()
|
||||
self.env.current_document = _CurrentDocument()
|
||||
self.env.ref_context.clear()
|
||||
|
||||
self.write_doctree(docname, doctree, _cache=_cache)
|
||||
|
@ -284,9 +284,9 @@ class ObjectDescription(SphinxDirective, Generic[ObjDescT]):
|
||||
# needed for association of version{added,changed} directives
|
||||
object_name: ObjDescT = self.names[0]
|
||||
if isinstance(object_name, tuple):
|
||||
self.env.temp_data['object'] = str(object_name[0])
|
||||
self.env.current_document.obj_desc_name = str(object_name[0])
|
||||
else:
|
||||
self.env.temp_data['object'] = str(object_name)
|
||||
self.env.current_document.obj_desc_name = str(object_name)
|
||||
self.before_content()
|
||||
content_children = self.parse_content_to_nodes(allow_section_headings=True)
|
||||
content_node = addnodes.desc_content('', *content_children)
|
||||
@ -296,7 +296,7 @@ class ObjectDescription(SphinxDirective, Generic[ObjDescT]):
|
||||
'object-description-transform', self.domain, self.objtype, content_node
|
||||
)
|
||||
DocFieldTransformer(self).transform_all(content_node)
|
||||
self.env.temp_data['object'] = ''
|
||||
self.env.current_document.obj_desc_name = ''
|
||||
self.after_content()
|
||||
|
||||
if node['no-typesetting']:
|
||||
@ -335,7 +335,7 @@ class DefaultRole(SphinxDirective):
|
||||
)
|
||||
if role:
|
||||
docutils.register_role('', role) # type: ignore[arg-type]
|
||||
self.env.temp_data['default_role'] = role_name
|
||||
self.env.current_document.default_role = role_name
|
||||
else:
|
||||
literal_block = nodes.literal_block(self.block_text, self.block_text)
|
||||
reporter = self.state.reporter
|
||||
@ -362,13 +362,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.current_document.default_domain = default_domain
|
||||
return []
|
||||
|
||||
|
||||
|
@ -48,7 +48,7 @@ class Highlight(SphinxDirective):
|
||||
linenothreshold = self.options.get('linenothreshold', sys.maxsize)
|
||||
force = 'force' in self.options
|
||||
|
||||
self.env.temp_data['highlight_language'] = language
|
||||
self.env.current_document.highlight_language = language
|
||||
return [
|
||||
addnodes.highlightlang(
|
||||
lang=language, force=force, linenothreshold=linenothreshold
|
||||
@ -159,8 +159,9 @@ class CodeBlock(SphinxDirective):
|
||||
# no highlight language specified. Then this directive refers the current
|
||||
# highlight setting via ``highlight`` directive or ``highlight_language``
|
||||
# configuration.
|
||||
literal['language'] = self.env.temp_data.get(
|
||||
'highlight_language', self.config.highlight_language
|
||||
literal['language'] = (
|
||||
self.env.current_document.highlight_language
|
||||
or self.config.highlight_language
|
||||
)
|
||||
extra_args = literal['highlight_args'] = {}
|
||||
if hl_lines is not None:
|
||||
|
@ -115,8 +115,9 @@ class Code(SphinxDirective):
|
||||
# no highlight language specified. Then this directive refers the current
|
||||
# highlight setting via ``highlight`` directive or ``highlight_language``
|
||||
# configuration.
|
||||
node['language'] = self.env.temp_data.get(
|
||||
'highlight_language', self.config.highlight_language
|
||||
node['language'] = (
|
||||
self.env.current_document.highlight_language
|
||||
or self.config.highlight_language
|
||||
)
|
||||
|
||||
if 'number-lines' in self.options:
|
||||
|
@ -220,19 +220,19 @@ class CObject(ObjectDescription[ASTDeclaration]):
|
||||
|
||||
def run(self) -> list[Node]:
|
||||
env = self.state.document.settings.env # from ObjectDescription.run
|
||||
if 'c:parent_symbol' not in env.temp_data:
|
||||
if env.current_document.c_parent_symbol is None:
|
||||
root = env.domaindata['c']['root_symbol']
|
||||
env.temp_data['c:parent_symbol'] = root
|
||||
env.current_document.c_parent_symbol = root
|
||||
env.ref_context['c:parent_key'] = root.get_lookup_key()
|
||||
|
||||
# When multiple declarations are made in the same directive
|
||||
# they need to know about each other to provide symbol lookup for function parameters.
|
||||
# We use last_symbol to store the latest added declaration in a directive.
|
||||
env.temp_data['c:last_symbol'] = None
|
||||
env.current_document.c_last_symbol = None
|
||||
return super().run()
|
||||
|
||||
def handle_signature(self, sig: str, signode: TextElement) -> ASTDeclaration:
|
||||
parent_symbol: Symbol = self.env.temp_data['c:parent_symbol']
|
||||
parent_symbol: Symbol = self.env.current_document.c_parent_symbol
|
||||
|
||||
max_len = (
|
||||
self.env.config.c_maximum_signature_line_length
|
||||
@ -254,7 +254,7 @@ class CObject(ObjectDescription[ASTDeclaration]):
|
||||
# the possibly inner declarations.
|
||||
name = _make_phony_error_name()
|
||||
symbol = parent_symbol.add_name(name)
|
||||
self.env.temp_data['c:last_symbol'] = symbol
|
||||
self.env.current_document.c_last_symbol = symbol
|
||||
raise ValueError from e
|
||||
|
||||
try:
|
||||
@ -264,15 +264,15 @@ class CObject(ObjectDescription[ASTDeclaration]):
|
||||
# append the new declaration to the sibling list
|
||||
assert symbol.siblingAbove is None
|
||||
assert symbol.siblingBelow is None
|
||||
symbol.siblingAbove = self.env.temp_data['c:last_symbol']
|
||||
symbol.siblingAbove = self.env.current_document.c_last_symbol
|
||||
if symbol.siblingAbove is not None:
|
||||
assert symbol.siblingAbove.siblingBelow is None
|
||||
symbol.siblingAbove.siblingBelow = symbol
|
||||
self.env.temp_data['c:last_symbol'] = symbol
|
||||
self.env.current_document.c_last_symbol = symbol
|
||||
except _DuplicateSymbolError as e:
|
||||
# Assume we are actually in the old symbol,
|
||||
# instead of the newly created duplicate.
|
||||
self.env.temp_data['c:last_symbol'] = e.symbol
|
||||
self.env.current_document.c_last_symbol = e.symbol
|
||||
msg = __(
|
||||
'Duplicate C declaration, also defined at %s:%s.\n'
|
||||
"Declaration is '.. c:%s:: %s'."
|
||||
@ -298,15 +298,15 @@ class CObject(ObjectDescription[ASTDeclaration]):
|
||||
return ast
|
||||
|
||||
def before_content(self) -> None:
|
||||
last_symbol: Symbol = self.env.temp_data['c:last_symbol']
|
||||
last_symbol: Symbol = self.env.current_document.c_last_symbol
|
||||
assert last_symbol
|
||||
self.oldParentSymbol = self.env.temp_data['c:parent_symbol']
|
||||
self.oldParentSymbol = self.env.current_document.c_parent_symbol
|
||||
self.oldParentKey: LookupKey = self.env.ref_context['c:parent_key']
|
||||
self.env.temp_data['c:parent_symbol'] = last_symbol
|
||||
self.env.current_document.c_parent_symbol = last_symbol
|
||||
self.env.ref_context['c:parent_key'] = last_symbol.get_lookup_key()
|
||||
|
||||
def after_content(self) -> None:
|
||||
self.env.temp_data['c:parent_symbol'] = self.oldParentSymbol
|
||||
self.env.current_document.c_parent_symbol = self.oldParentSymbol
|
||||
self.env.ref_context['c:parent_key'] = self.oldParentKey
|
||||
|
||||
|
||||
@ -410,8 +410,8 @@ class CNamespaceObject(SphinxDirective):
|
||||
name = _make_phony_error_name()
|
||||
symbol = root_symbol.add_name(name)
|
||||
stack = [symbol]
|
||||
self.env.temp_data['c:parent_symbol'] = symbol
|
||||
self.env.temp_data['c:namespace_stack'] = stack
|
||||
self.env.current_document.c_parent_symbol = symbol
|
||||
self.env.current_document.c_namespace_stack = stack
|
||||
self.env.ref_context['c:parent_key'] = symbol.get_lookup_key()
|
||||
return []
|
||||
|
||||
@ -435,14 +435,12 @@ class CNamespacePushObject(SphinxDirective):
|
||||
except DefinitionError as e:
|
||||
logger.warning(e, location=self.get_location())
|
||||
name = _make_phony_error_name()
|
||||
old_parent = self.env.temp_data.get('c:parent_symbol', None)
|
||||
old_parent = self.env.current_document.c_parent_symbol
|
||||
if not old_parent:
|
||||
old_parent = self.env.domaindata['c']['root_symbol']
|
||||
symbol = old_parent.add_name(name)
|
||||
stack = self.env.temp_data.get('c:namespace_stack', [])
|
||||
stack.append(symbol)
|
||||
self.env.temp_data['c:parent_symbol'] = symbol
|
||||
self.env.temp_data['c:namespace_stack'] = stack
|
||||
self.env.current_document.c_namespace_stack.append(symbol)
|
||||
self.env.current_document.c_parent_symbol = symbol
|
||||
self.env.ref_context['c:parent_key'] = symbol.get_lookup_key()
|
||||
return []
|
||||
|
||||
@ -455,21 +453,19 @@ class CNamespacePopObject(SphinxDirective):
|
||||
option_spec: ClassVar[OptionSpec] = {}
|
||||
|
||||
def run(self) -> list[Node]:
|
||||
stack = self.env.temp_data.get('c:namespace_stack', None)
|
||||
if not stack or len(stack) == 0:
|
||||
stack = self.env.current_document.c_namespace_stack
|
||||
if len(stack) == 0:
|
||||
logger.warning(
|
||||
'C namespace pop on empty stack. Defaulting to global scope.',
|
||||
location=self.get_location(),
|
||||
)
|
||||
stack = []
|
||||
else:
|
||||
stack.pop()
|
||||
if len(stack) > 0:
|
||||
symbol = stack[-1]
|
||||
else:
|
||||
symbol = self.env.domaindata['c']['root_symbol']
|
||||
self.env.temp_data['c:parent_symbol'] = symbol
|
||||
self.env.temp_data['c:namespace_stack'] = stack
|
||||
self.env.current_document.c_parent_symbol = symbol
|
||||
self.env.ref_context['c:parent_key'] = symbol.get_lookup_key()
|
||||
return []
|
||||
|
||||
@ -488,9 +484,9 @@ class AliasNode(nodes.Element):
|
||||
self.aliasOptions = aliasOptions
|
||||
self.document = document
|
||||
if env is not None:
|
||||
if 'c:parent_symbol' not in env.temp_data:
|
||||
if env.current_document.c_parent_symbol is None:
|
||||
root = env.domaindata['c']['root_symbol']
|
||||
env.temp_data['c:parent_symbol'] = root
|
||||
env.current_document.c_parent_symbol = root
|
||||
env.ref_context['c:parent_key'] = root.get_lookup_key()
|
||||
self.parentKey = env.ref_context['c:parent_key']
|
||||
else:
|
||||
@ -735,7 +731,7 @@ class CExprRole(SphinxRole):
|
||||
# see below
|
||||
node = addnodes.desc_inline('c', text, text, classes=[self.class_type])
|
||||
return [node], []
|
||||
parent_symbol = self.env.temp_data.get('c:parent_symbol', None)
|
||||
parent_symbol = self.env.current_document.c_parent_symbol
|
||||
if parent_symbol is None:
|
||||
parent_symbol = self.env.domaindata['c']['root_symbol']
|
||||
# ...most if not all of these classes should really apply to the individual references,
|
||||
|
@ -133,7 +133,7 @@ class ChangeSetDomain(Domain):
|
||||
def note_changeset(self, node: addnodes.versionmodified) -> None:
|
||||
version = node['version']
|
||||
module = self.env.ref_context.get('py:module')
|
||||
objname = self.env.temp_data.get('object', '')
|
||||
objname = self.env.current_document.obj_desc_name
|
||||
changeset = ChangeSet(
|
||||
node['type'],
|
||||
self.env.docname,
|
||||
|
@ -309,9 +309,9 @@ class CPPObject(ObjectDescription[ASTDeclaration]):
|
||||
|
||||
def run(self) -> list[Node]:
|
||||
env = self.state.document.settings.env # from ObjectDescription.run
|
||||
if 'cpp:parent_symbol' not in env.temp_data:
|
||||
if env.current_document.cpp_parent_symbol is None:
|
||||
root = env.domaindata['cpp']['root_symbol']
|
||||
env.temp_data['cpp:parent_symbol'] = root
|
||||
env.current_document.cpp_parent_symbol = root
|
||||
env.ref_context['cpp:parent_key'] = root.get_lookup_key()
|
||||
|
||||
# The lookup keys assume that no nested scopes exists inside overloaded functions.
|
||||
@ -325,7 +325,7 @@ class CPPObject(ObjectDescription[ASTDeclaration]):
|
||||
# :cpp:any:`boom`
|
||||
#
|
||||
# So we disallow any signatures inside functions.
|
||||
parent_symbol = env.temp_data['cpp:parent_symbol']
|
||||
parent_symbol = env.current_document.cpp_parent_symbol
|
||||
parent_decl = parent_symbol.declaration
|
||||
if parent_decl is not None and parent_decl.objectType == 'function':
|
||||
msg = (
|
||||
@ -336,16 +336,16 @@ class CPPObject(ObjectDescription[ASTDeclaration]):
|
||||
logger.warning(msg, location=self.get_location())
|
||||
name = _make_phony_error_name()
|
||||
symbol = parent_symbol.add_name(name)
|
||||
env.temp_data['cpp:last_symbol'] = symbol
|
||||
env.current_document.cpp_last_symbol = symbol
|
||||
return []
|
||||
# When multiple declarations are made in the same directive
|
||||
# they need to know about each other to provide symbol lookup for function parameters.
|
||||
# We use last_symbol to store the latest added declaration in a directive.
|
||||
env.temp_data['cpp:last_symbol'] = None
|
||||
env.current_document.cpp_last_symbol = None
|
||||
return super().run()
|
||||
|
||||
def handle_signature(self, sig: str, signode: desc_signature) -> ASTDeclaration:
|
||||
parent_symbol: Symbol = self.env.temp_data['cpp:parent_symbol']
|
||||
parent_symbol: Symbol = self.env.current_document.cpp_parent_symbol
|
||||
|
||||
max_len = (
|
||||
self.env.config.cpp_maximum_signature_line_length
|
||||
@ -367,7 +367,7 @@ class CPPObject(ObjectDescription[ASTDeclaration]):
|
||||
# the possibly inner declarations.
|
||||
name = _make_phony_error_name()
|
||||
symbol = parent_symbol.add_name(name)
|
||||
self.env.temp_data['cpp:last_symbol'] = symbol
|
||||
self.env.current_document.cpp_last_symbol = symbol
|
||||
raise ValueError from e
|
||||
|
||||
try:
|
||||
@ -377,15 +377,15 @@ class CPPObject(ObjectDescription[ASTDeclaration]):
|
||||
# append the new declaration to the sibling list
|
||||
assert symbol.siblingAbove is None
|
||||
assert symbol.siblingBelow is None
|
||||
symbol.siblingAbove = self.env.temp_data['cpp:last_symbol']
|
||||
symbol.siblingAbove = self.env.current_document.cpp_last_symbol
|
||||
if symbol.siblingAbove is not None:
|
||||
assert symbol.siblingAbove.siblingBelow is None
|
||||
symbol.siblingAbove.siblingBelow = symbol
|
||||
self.env.temp_data['cpp:last_symbol'] = symbol
|
||||
self.env.current_document.cpp_last_symbol = symbol
|
||||
except _DuplicateSymbolError as e:
|
||||
# Assume we are actually in the old symbol,
|
||||
# instead of the newly created duplicate.
|
||||
self.env.temp_data['cpp:last_symbol'] = e.symbol
|
||||
self.env.current_document.cpp_last_symbol = e.symbol
|
||||
msg = __(
|
||||
'Duplicate C++ declaration, also defined at %s:%s.\n'
|
||||
"Declaration is '.. cpp:%s:: %s'."
|
||||
@ -412,27 +412,28 @@ class CPPObject(ObjectDescription[ASTDeclaration]):
|
||||
return ast
|
||||
|
||||
def before_content(self) -> None:
|
||||
last_symbol: Symbol = self.env.temp_data['cpp:last_symbol']
|
||||
last_symbol: Symbol = self.env.current_document.cpp_last_symbol
|
||||
assert last_symbol
|
||||
self.oldParentSymbol = self.env.temp_data['cpp:parent_symbol']
|
||||
self.oldParentSymbol = self.env.current_document.cpp_parent_symbol
|
||||
self.oldParentKey: LookupKey = self.env.ref_context['cpp:parent_key']
|
||||
self.env.temp_data['cpp:parent_symbol'] = last_symbol
|
||||
self.env.current_document.cpp_parent_symbol = last_symbol
|
||||
self.env.ref_context['cpp:parent_key'] = last_symbol.get_lookup_key()
|
||||
self.env.temp_data['cpp:domain_name'] = (
|
||||
*self.env.temp_data.get('cpp:domain_name', ()),
|
||||
self.env.current_document.cpp_domain_name = (
|
||||
*self.env.current_document.cpp_domain_name,
|
||||
last_symbol.identOrOp._stringify(str),
|
||||
)
|
||||
|
||||
def after_content(self) -> None:
|
||||
temp_data = self.env.temp_data
|
||||
temp_data['cpp:parent_symbol'] = self.oldParentSymbol
|
||||
self.env.current_document.cpp_parent_symbol = self.oldParentSymbol
|
||||
self.env.ref_context['cpp:parent_key'] = self.oldParentKey
|
||||
temp_data['cpp:domain_name'] = temp_data['cpp:domain_name'][:-1]
|
||||
cpp_domain_name = self.env.current_document.cpp_domain_name
|
||||
self.env.current_document.cpp_domain_name = cpp_domain_name[:-1]
|
||||
|
||||
def _object_hierarchy_parts(self, sig_node: desc_signature) -> tuple[str, ...]:
|
||||
last_symbol: Symbol = self.env.current_document.cpp_last_symbol
|
||||
return tuple(
|
||||
s.identOrOp._stringify(str)
|
||||
for s in self.env.temp_data['cpp:last_symbol'].get_full_nested_name().names
|
||||
for s in last_symbol.get_full_nested_name().names
|
||||
)
|
||||
|
||||
def _toc_entry_name(self, sig_node: desc_signature) -> str:
|
||||
@ -448,7 +449,7 @@ class CPPObject(ObjectDescription[ASTDeclaration]):
|
||||
*parents, name = sig_node['_toc_parts']
|
||||
if config.toc_object_entries_show_parents == 'domain':
|
||||
return '::'.join((
|
||||
*self.env.temp_data.get('cpp:domain_name', ()),
|
||||
*self.env.current_document.cpp_domain_name,
|
||||
name + parens,
|
||||
))
|
||||
if config.toc_object_entries_show_parents == 'hide':
|
||||
@ -555,8 +556,8 @@ class CPPNamespaceObject(SphinxDirective):
|
||||
ast = ASTNamespace(name, None)
|
||||
symbol = root_symbol.add_name(ast.nestedName, ast.templatePrefix)
|
||||
stack = [symbol]
|
||||
self.env.temp_data['cpp:parent_symbol'] = symbol
|
||||
self.env.temp_data['cpp:namespace_stack'] = stack
|
||||
self.env.current_document.cpp_parent_symbol = symbol
|
||||
self.env.current_document.cpp_namespace_stack = stack
|
||||
self.env.ref_context['cpp:parent_key'] = symbol.get_lookup_key()
|
||||
return []
|
||||
|
||||
@ -581,14 +582,12 @@ class CPPNamespacePushObject(SphinxDirective):
|
||||
logger.warning(e, location=self.get_location())
|
||||
name = _make_phony_error_name()
|
||||
ast = ASTNamespace(name, None)
|
||||
old_parent = self.env.temp_data.get('cpp:parent_symbol', None)
|
||||
old_parent = self.env.current_document.cpp_parent_symbol
|
||||
if not old_parent:
|
||||
old_parent = self.env.domaindata['cpp']['root_symbol']
|
||||
symbol = old_parent.add_name(ast.nestedName, ast.templatePrefix)
|
||||
stack = self.env.temp_data.get('cpp:namespace_stack', [])
|
||||
stack.append(symbol)
|
||||
self.env.temp_data['cpp:parent_symbol'] = symbol
|
||||
self.env.temp_data['cpp:namespace_stack'] = stack
|
||||
self.env.current_document.cpp_namespace_stack.append(symbol)
|
||||
self.env.current_document.cpp_parent_symbol = symbol
|
||||
self.env.ref_context['cpp:parent_key'] = symbol.get_lookup_key()
|
||||
return []
|
||||
|
||||
@ -601,21 +600,19 @@ class CPPNamespacePopObject(SphinxDirective):
|
||||
option_spec: ClassVar[OptionSpec] = {}
|
||||
|
||||
def run(self) -> list[Node]:
|
||||
stack = self.env.temp_data.get('cpp:namespace_stack', None)
|
||||
if not stack or len(stack) == 0:
|
||||
stack = self.env.current_document.cpp_namespace_stack
|
||||
if len(stack) == 0:
|
||||
logger.warning(
|
||||
'C++ namespace pop on empty stack. Defaulting to global scope.',
|
||||
location=self.get_location(),
|
||||
)
|
||||
stack = []
|
||||
else:
|
||||
stack.pop()
|
||||
if len(stack) > 0:
|
||||
symbol = stack[-1]
|
||||
else:
|
||||
symbol = self.env.domaindata['cpp']['root_symbol']
|
||||
self.env.temp_data['cpp:parent_symbol'] = symbol
|
||||
self.env.temp_data['cpp:namespace_stack'] = stack
|
||||
self.env.current_document.cpp_parent_symbol = symbol
|
||||
self.env.ref_context['cpp:parent_key'] = symbol.get_lookup_key()
|
||||
return []
|
||||
|
||||
@ -632,9 +629,9 @@ class AliasNode(nodes.Element):
|
||||
self.sig = sig
|
||||
self.aliasOptions = aliasOptions
|
||||
if env is not None:
|
||||
if 'cpp:parent_symbol' not in env.temp_data:
|
||||
if env.current_document.cpp_parent_symbol is None:
|
||||
root = env.domaindata['cpp']['root_symbol']
|
||||
env.temp_data['cpp:parent_symbol'] = root
|
||||
env.current_document.cpp_parent_symbol = root
|
||||
env.ref_context['cpp:parent_key'] = root.get_lookup_key()
|
||||
self.parentKey = env.ref_context['cpp:parent_key']
|
||||
else:
|
||||
@ -844,7 +841,7 @@ class CPPAliasObject(ObjectDescription):
|
||||
self.before_content()
|
||||
content_node = addnodes.desc_content('', *self.parse_content_to_nodes())
|
||||
node.append(content_node)
|
||||
self.env.temp_data['object'] = None
|
||||
self.env.current_document.obj_desc_name = ''
|
||||
self.after_content()
|
||||
return [node]
|
||||
|
||||
@ -912,7 +909,7 @@ class CPPExprRole(SphinxRole):
|
||||
# see below
|
||||
node = addnodes.desc_inline('cpp', text, text, classes=[self.class_type])
|
||||
return [node], []
|
||||
parent_symbol = self.env.temp_data.get('cpp:parent_symbol', None)
|
||||
parent_symbol = self.env.current_document.cpp_parent_symbol
|
||||
if parent_symbol is None:
|
||||
parent_symbol = self.env.domaindata['cpp']['root_symbol']
|
||||
# ...most if not all of these classes should really apply to the individual references,
|
||||
|
@ -6,8 +6,8 @@ import functools
|
||||
import os
|
||||
import pickle
|
||||
from collections import defaultdict
|
||||
from copy import copy
|
||||
from typing import TYPE_CHECKING
|
||||
from copy import deepcopy
|
||||
from typing import TYPE_CHECKING, Final
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.domains._domains_container import _DomainsContainer
|
||||
@ -42,6 +42,8 @@ if TYPE_CHECKING:
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.config import Config
|
||||
from sphinx.domains import Domain
|
||||
from sphinx.domains.c._symbol import Symbol as CSymbol
|
||||
from sphinx.domains.cpp._symbol import Symbol as CPPSymbol
|
||||
from sphinx.events import EventManager
|
||||
from sphinx.project import Project
|
||||
from sphinx.util._pathlib import _StrPath
|
||||
@ -196,10 +198,10 @@ class BuildEnvironment:
|
||||
self.original_image_uri: dict[_StrPath, str] = {}
|
||||
|
||||
# temporary data storage while reading a document
|
||||
self.temp_data: dict[str, Any] = {}
|
||||
self.current_document: _CurrentDocument = _CurrentDocument()
|
||||
# context for cross-references (e.g. current module or class)
|
||||
# this is similar to temp_data, but will for example be copied to
|
||||
# attributes of "any" cross references
|
||||
# this is similar to ``self.current_document``,
|
||||
# but will for example be copied to attributes of "any" cross references
|
||||
self.ref_context: dict[str, Any] = {}
|
||||
|
||||
# search index data
|
||||
@ -426,7 +428,13 @@ class BuildEnvironment:
|
||||
if filename.startswith('/'):
|
||||
abs_fn = (self.srcdir / filename[1:]).resolve()
|
||||
else:
|
||||
doc_dir = self.doc2path(docname or self.docname, base=False).parent
|
||||
if not docname:
|
||||
if self.docname:
|
||||
docname = self.docname
|
||||
else:
|
||||
msg = 'docname'
|
||||
raise KeyError(msg)
|
||||
doc_dir = self.doc2path(docname, base=False).parent
|
||||
abs_fn = (self.srcdir / doc_dir / filename).resolve()
|
||||
|
||||
rel_fn = _relative_path(abs_fn, self.srcdir)
|
||||
@ -558,32 +566,42 @@ class BuildEnvironment:
|
||||
|
||||
def prepare_settings(self, docname: str) -> None:
|
||||
"""Prepare to set up environment for reading."""
|
||||
self.temp_data['docname'] = docname
|
||||
# defaults to the global default, but can be re-set in a document
|
||||
self.temp_data['default_role'] = self.config.default_role
|
||||
self.temp_data['default_domain'] = self.domains.get(self.config.primary_domain)
|
||||
self.current_document = _CurrentDocument(
|
||||
docname=docname,
|
||||
# defaults to the global default, but can be re-set in a document
|
||||
default_role=self.config.default_role,
|
||||
default_domain=self.domains.get(self.config.primary_domain),
|
||||
)
|
||||
|
||||
# utilities to use while reading a document
|
||||
|
||||
@property
|
||||
def temp_data(self) -> _CurrentDocument:
|
||||
"""Returns the temporary data storage for the current document.
|
||||
|
||||
Kept for backwards compatibility.
|
||||
"""
|
||||
return self.current_document
|
||||
|
||||
@property
|
||||
def docname(self) -> str:
|
||||
"""Returns the docname of the document currently being parsed."""
|
||||
return self.temp_data['docname']
|
||||
return self.current_document.docname
|
||||
|
||||
@property
|
||||
def parser(self) -> Parser:
|
||||
"""Returns the parser being used for to parse the current document."""
|
||||
return self.temp_data['_parser']
|
||||
if (parser := self.current_document._parser) is not None:
|
||||
return parser
|
||||
msg = 'parser'
|
||||
raise KeyError(msg)
|
||||
|
||||
def new_serialno(self, category: str = '') -> int:
|
||||
"""Return a serial number, e.g. for index entry targets.
|
||||
|
||||
The number is guaranteed to be unique in the current document.
|
||||
"""
|
||||
key = category + 'serialno'
|
||||
cur = self.temp_data.get(key, 0)
|
||||
self.temp_data[key] = cur + 1
|
||||
return cur
|
||||
return self.current_document.new_serial_number(category)
|
||||
|
||||
def note_dependency(
|
||||
self, filename: str | os.PathLike[str], *, docname: str | None = None
|
||||
@ -726,17 +744,19 @@ class BuildEnvironment:
|
||||
|
||||
def apply_post_transforms(self, doctree: nodes.document, docname: str) -> None:
|
||||
"""Apply all post-transforms."""
|
||||
backup = self.current_document
|
||||
new = deepcopy(backup)
|
||||
new.docname = docname
|
||||
try:
|
||||
# set env.docname during applying post-transforms
|
||||
backup = copy(self.temp_data)
|
||||
self.temp_data['docname'] = docname
|
||||
self.current_document = new
|
||||
|
||||
transformer = SphinxTransformer(doctree)
|
||||
transformer.set_environment(self)
|
||||
transformer.add_transforms(self.app.registry.get_post_transforms())
|
||||
transformer.apply_transforms()
|
||||
finally:
|
||||
self.temp_data = backup
|
||||
self.current_document = backup
|
||||
|
||||
# allow custom references to be resolved
|
||||
self.events.emit('doctree-resolved', doctree, docname)
|
||||
@ -846,3 +866,230 @@ def _check_toc_parents(toctree_includes: dict[str, list[str]]) -> None:
|
||||
type='toc',
|
||||
subtype='multiple_toc_parents',
|
||||
)
|
||||
|
||||
|
||||
class _CurrentDocument:
|
||||
"""Temporary data storage while reading a document.
|
||||
|
||||
This class is only for internal use. Please don't use this in your extensions.
|
||||
It will be removed or changed without notice.
|
||||
The only stable API is via ``env.current_document``.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
'_parser',
|
||||
'_serial_numbers',
|
||||
'_extension_data',
|
||||
'autodoc_annotations',
|
||||
'autodoc_class',
|
||||
'autodoc_module',
|
||||
'c_last_symbol',
|
||||
'c_namespace_stack',
|
||||
'c_parent_symbol',
|
||||
'cpp_domain_name',
|
||||
'cpp_last_symbol',
|
||||
'cpp_namespace_stack',
|
||||
'cpp_parent_symbol',
|
||||
'default_domain',
|
||||
'default_role',
|
||||
'docname',
|
||||
'highlight_language',
|
||||
'obj_desc_name',
|
||||
'reading_started_at',
|
||||
)
|
||||
|
||||
# Map of old-style temp_data keys to _CurrentDocument attributes
|
||||
__attr_map: Final = {
|
||||
'_parser': '_parser',
|
||||
'annotations': 'autodoc_annotations',
|
||||
'autodoc:class': 'autodoc_class',
|
||||
'autodoc:module': 'autodoc_module',
|
||||
'c:last_symbol': 'c_last_symbol',
|
||||
'c:namespace_stack': 'c_namespace_stack',
|
||||
'c:parent_symbol': 'c_parent_symbol',
|
||||
'cpp:domain_name': 'cpp_domain_name',
|
||||
'cpp:last_symbol': 'cpp_last_symbol',
|
||||
'cpp:namespace_stack': 'cpp_namespace_stack',
|
||||
'cpp:parent_symbol': 'cpp_parent_symbol',
|
||||
'default_domain': 'default_domain',
|
||||
'default_role': 'default_role',
|
||||
'docname': 'docname',
|
||||
'highlight_language': 'highlight_language',
|
||||
'object': 'obj_desc_name',
|
||||
'started_at': 'reading_started_at',
|
||||
}
|
||||
|
||||
# Attributes that should reset to None if popped.
|
||||
__attr_default_none: Final = frozenset({
|
||||
'_parser',
|
||||
'c:last_symbol',
|
||||
'c:parent_symbol',
|
||||
'cpp:last_symbol',
|
||||
'cpp:parent_symbol',
|
||||
'default_domain',
|
||||
})
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
docname: str = '',
|
||||
default_role: str = '',
|
||||
default_domain: Domain | None = None,
|
||||
) -> None:
|
||||
#: The docname of the document currently being parsed.
|
||||
self.docname: str = docname
|
||||
|
||||
#: The default role for the current document.
|
||||
#: Set by the ``.. default-role::`` directive.
|
||||
self.default_role: str = default_role
|
||||
|
||||
#: The default domain for the current document.
|
||||
#: Set by the ``.. default-domain::`` directive.
|
||||
self.default_domain: Domain | None = default_domain
|
||||
|
||||
#: The parser being used to parse the current document.
|
||||
self._parser: Parser | None = None
|
||||
|
||||
#: The default language for syntax highlighting.
|
||||
#: Set by the ``.. highlight::`` directive to override
|
||||
#: the ``highlight_language`` config value.
|
||||
self.highlight_language: str = ''
|
||||
|
||||
#: The current object's name.
|
||||
#: Used in the Changes builder.
|
||||
self.obj_desc_name: str = ''
|
||||
|
||||
#: Records type hints of Python objects in the current document.
|
||||
#: Used in ``sphinx.ext.autodoc.typehints``.
|
||||
#: Maps object names to maps of attribute names -> type hints.
|
||||
self.autodoc_annotations: dict[str, dict[str, str]] = {}
|
||||
|
||||
#: The current Python class name.
|
||||
#: Used in ``sphinx.ext.autodoc``.
|
||||
self.autodoc_class: str = ''
|
||||
|
||||
#: The current Python module name.
|
||||
#: Used in ``sphinx.ext.autodoc``.
|
||||
self.autodoc_module: str = ''
|
||||
|
||||
#: The most-recently added declaration in a directive.
|
||||
#: Used in the C Domain.
|
||||
self.c_last_symbol: CSymbol | None = None
|
||||
|
||||
#: The stack of namespace scopes, altered by the ``.. c:namespace::``
|
||||
#: and ``.. c:namespace-(push|pop)::``directives.
|
||||
#: Used in the C Domain.
|
||||
self.c_namespace_stack: list[CSymbol] = []
|
||||
|
||||
#: The parent declaration.
|
||||
#: Used in the C Domain.
|
||||
self.c_parent_symbol: CSymbol | None = None
|
||||
|
||||
#: A stack of the string representation of declarations,
|
||||
#: used to format the table of contents entry.
|
||||
#: Used in the C++ Domain.
|
||||
self.cpp_domain_name: tuple[str, ...] = ()
|
||||
|
||||
#: The most-recently added declaration in a directive.
|
||||
#: Used in the C++ Domain.
|
||||
self.cpp_last_symbol: CPPSymbol | None = None
|
||||
|
||||
#: The stack of namespace scopes, altered by the ``.. cpp:namespace::``
|
||||
#: and ``.. cpp:namespace-(push|pop)::``directives.
|
||||
#: Used in the C++ Domain.
|
||||
self.cpp_namespace_stack: list[CPPSymbol] = []
|
||||
|
||||
#: The parent declaration.
|
||||
#: Used in the C++ Domain.
|
||||
self.cpp_parent_symbol: CPPSymbol | None = None
|
||||
|
||||
#: Records the time when reading begain for the current document.
|
||||
#: Used in ``sphinx.ext.duration``.
|
||||
self.reading_started_at: float = 0.0
|
||||
|
||||
# Used for generating unique serial numbers.
|
||||
self._serial_numbers: dict[str, int] = {}
|
||||
|
||||
# Stores properties relating to the current document set by extensions.
|
||||
self._extension_data: dict[str, Any] = {}
|
||||
|
||||
def new_serial_number(self, category: str = '', /) -> int:
|
||||
"""Return a serial number, e.g. for index entry targets.
|
||||
|
||||
The number is guaranteed to be unique in the current document & category.
|
||||
"""
|
||||
current = self._serial_numbers.get(category, 0)
|
||||
self._serial_numbers[category] = current + 1
|
||||
return current
|
||||
|
||||
# Mapping interface:
|
||||
|
||||
def __getitem__(self, item: str) -> Any:
|
||||
if item in self.__attr_map:
|
||||
return getattr(self, self.__attr_map[item])
|
||||
return self._extension_data[item]
|
||||
|
||||
def __setitem__(self, key: str, value: Any) -> None:
|
||||
if key in self.__attr_map:
|
||||
setattr(self, self.__attr_map[key], value)
|
||||
else:
|
||||
self._extension_data[key] = value
|
||||
|
||||
def __delitem__(self, key: str) -> None:
|
||||
self.pop(key, default=None)
|
||||
|
||||
def __contains__(self, item: str) -> bool:
|
||||
if item in {'c:parent_symbol', 'cpp:parent_symbol'}:
|
||||
return getattr(self, item) is not None
|
||||
return item in self.__attr_map or item in self._extension_data
|
||||
|
||||
def __iter__(self) -> Iterator[str]:
|
||||
return iter(self.keys())
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(self.__attr_map) + len(self._extension_data)
|
||||
|
||||
def keys(self) -> Iterable[str]:
|
||||
return frozenset(self.__attr_map.keys() | self._extension_data.keys())
|
||||
|
||||
def items(self) -> Iterable[tuple[str, Any]]:
|
||||
for key in self.keys():
|
||||
yield key, self[key]
|
||||
|
||||
def values(self) -> Iterable[Any]:
|
||||
for key in self.keys():
|
||||
yield self[key]
|
||||
|
||||
def get(self, key: str, default: Any | None = None) -> Any | None:
|
||||
try:
|
||||
return self[key]
|
||||
except KeyError:
|
||||
return default
|
||||
|
||||
__sentinel = object()
|
||||
|
||||
def pop(self, key: str, default: Any | None = __sentinel) -> Any | None:
|
||||
if key in self.__attr_map:
|
||||
# the keys in __attr_map always exist, so ``default`` is ignored
|
||||
value = getattr(self, self.__attr_map[key])
|
||||
if key in self.__attr_default_none:
|
||||
default = None
|
||||
else:
|
||||
default = type(value)() # set key to type's default
|
||||
setattr(self, self.__attr_map[key], default)
|
||||
return value
|
||||
if default is self.__sentinel:
|
||||
return self._extension_data.pop(key)
|
||||
return self._extension_data.pop(key, default)
|
||||
|
||||
def setdefault(self, key: str, default: Any | None = None) -> Any | None:
|
||||
return self._extension_data.setdefault(key, default)
|
||||
|
||||
def clear(self) -> None:
|
||||
_CurrentDocument.__init__(self) # NoQA: PLC2801
|
||||
|
||||
def update(self, other: Iterable[tuple[str, Any]] = (), /, **kwargs: Any) -> None:
|
||||
other_dict = dict(other) if not isinstance(other, dict) else other
|
||||
for dct in other_dict, kwargs:
|
||||
for key, value in dct.items():
|
||||
self[key] = value
|
||||
|
@ -878,9 +878,9 @@ class Documenter:
|
||||
*self.options.members*.
|
||||
"""
|
||||
# set current namespace for finding members
|
||||
self.env.temp_data['autodoc:module'] = self.modname
|
||||
self.env.current_document.autodoc_module = self.modname
|
||||
if self.objpath:
|
||||
self.env.temp_data['autodoc:class'] = self.objpath[0]
|
||||
self.env.current_document.autodoc_class = self.objpath[0]
|
||||
|
||||
want_all = (
|
||||
all_members or self.options.inherited_members or self.options.members is ALL
|
||||
@ -918,8 +918,8 @@ class Documenter:
|
||||
)
|
||||
|
||||
# reset current objects
|
||||
self.env.temp_data['autodoc:module'] = None
|
||||
self.env.temp_data['autodoc:class'] = None
|
||||
self.env.current_document.autodoc_module = ''
|
||||
self.env.current_document.autodoc_class = ''
|
||||
|
||||
def sort_members(
|
||||
self, documenters: list[tuple[Documenter, bool]], order: str
|
||||
@ -1261,7 +1261,7 @@ class ModuleLevelDocumenter(Documenter):
|
||||
|
||||
# if documenting a toplevel object without explicit module,
|
||||
# it can be contained in another auto directive ...
|
||||
modname = self.env.temp_data.get('autodoc:module')
|
||||
modname = self.env.current_document.autodoc_module
|
||||
# ... or in the scope of a module directive
|
||||
if not modname:
|
||||
modname = self.env.ref_context.get('py:module')
|
||||
@ -1287,19 +1287,18 @@ class ClassLevelDocumenter(Documenter):
|
||||
# if documenting a class-level object without path,
|
||||
# there must be a current class, either from a parent
|
||||
# auto directive ...
|
||||
mod_cls_ = self.env.temp_data.get('autodoc:class')
|
||||
mod_cls = self.env.current_document.autodoc_class
|
||||
# ... or from a class directive
|
||||
if mod_cls_ is None:
|
||||
mod_cls_ = self.env.ref_context.get('py:class')
|
||||
# ... if still None, there's no way to know
|
||||
if mod_cls_ is None:
|
||||
if not mod_cls:
|
||||
mod_cls = self.env.ref_context.get('py:class', '')
|
||||
# ... if still falsy, there's no way to know
|
||||
if not mod_cls:
|
||||
return None, []
|
||||
mod_cls = mod_cls_
|
||||
modname, sep, cls = mod_cls.rpartition('.')
|
||||
parents = [cls]
|
||||
# if the module name is still missing, get it like above
|
||||
if not modname:
|
||||
modname = self.env.temp_data.get('autodoc:module')
|
||||
modname = self.env.current_document.autodoc_module
|
||||
if not modname:
|
||||
modname = self.env.ref_context.get('py:module')
|
||||
# ... else, it stays None, which means invalid
|
||||
|
@ -38,8 +38,8 @@ def record_typehints(
|
||||
|
||||
try:
|
||||
if callable(obj):
|
||||
annotations = app.env.temp_data.setdefault('annotations', {})
|
||||
annotation = annotations.setdefault(name, {})
|
||||
current_document = app.env.current_document
|
||||
annotation = current_document.autodoc_annotations.setdefault(name, {})
|
||||
sig = inspect.signature(obj, type_aliases=app.config.autodoc_type_aliases)
|
||||
for param in sig.parameters.values():
|
||||
if param.annotation is not param.empty:
|
||||
@ -71,7 +71,7 @@ def merge_typehints(
|
||||
# signature node does not have valid context info for the target object
|
||||
return
|
||||
|
||||
annotations = app.env.temp_data.get('annotations', {})
|
||||
annotations = app.env.current_document.autodoc_annotations
|
||||
if annotations.get(fullname, {}):
|
||||
field_lists = [n for n in contentnode if isinstance(n, nodes.field_list)]
|
||||
if field_lists == []:
|
||||
|
@ -66,13 +66,12 @@ def on_builder_inited(app: Sphinx) -> None:
|
||||
|
||||
def on_source_read(app: Sphinx, docname: str, content: list[str]) -> None:
|
||||
"""Start to measure reading duration."""
|
||||
app.env.temp_data['started_at'] = time.monotonic()
|
||||
app.env.current_document.reading_started_at = time.monotonic()
|
||||
|
||||
|
||||
def on_doctree_read(app: Sphinx, doctree: nodes.document) -> None:
|
||||
"""Record a reading duration."""
|
||||
started_at = app.env.temp_data['started_at']
|
||||
duration = time.monotonic() - started_at
|
||||
duration = time.monotonic() - app.env.current_document.reading_started_at
|
||||
domain = app.env.domains['duration']
|
||||
domain.note_reading_duration(duration)
|
||||
|
||||
|
@ -398,7 +398,7 @@ class IntersphinxRole(SphinxRole):
|
||||
# the user did not specify a domain,
|
||||
# so we check first the default (if available) then standard domains
|
||||
domains: list[Domain] = []
|
||||
if default_domain := self.env.temp_data.get('default_domain'):
|
||||
if default_domain := self.env.current_document.default_domain:
|
||||
domains.append(default_domain)
|
||||
if (
|
||||
std_domain := self.env.domains.standard_domain
|
||||
@ -505,7 +505,7 @@ class IntersphinxRole(SphinxRole):
|
||||
names = name.split(':')
|
||||
if len(names) == 1:
|
||||
# role
|
||||
default_domain = self.env.temp_data.get('default_domain')
|
||||
default_domain = self.env.current_document.default_domain
|
||||
domain = default_domain.name if default_domain else None
|
||||
role = names[0]
|
||||
elif len(names) == 2:
|
||||
|
@ -17,7 +17,7 @@ if TYPE_CHECKING:
|
||||
def parse(app: Sphinx, text: str, docname: str = 'index') -> nodes.document:
|
||||
"""Parse a string as reStructuredText with Sphinx application."""
|
||||
try:
|
||||
app.env.temp_data['docname'] = docname
|
||||
app.env.current_document.docname = docname
|
||||
reader = SphinxStandaloneReader()
|
||||
reader.setup(app)
|
||||
parser = RSTParser()
|
||||
@ -37,4 +37,4 @@ def parse(app: Sphinx, text: str, docname: str = 'index') -> nodes.document:
|
||||
},
|
||||
)
|
||||
finally:
|
||||
app.env.temp_data.pop('docname', None)
|
||||
app.env.current_document.docname = ''
|
||||
|
@ -285,7 +285,7 @@ class sphinx_domains(CustomReSTDispatcher):
|
||||
)
|
||||
# else look in the default domain
|
||||
else:
|
||||
def_domain = self.env.temp_data.get('default_domain')
|
||||
def_domain = self.env.current_document.default_domain
|
||||
if def_domain is not None:
|
||||
element = getattr(def_domain, type)(name)
|
||||
if element is not None:
|
||||
@ -587,7 +587,7 @@ class SphinxRole:
|
||||
if name:
|
||||
self.name = name.lower()
|
||||
else:
|
||||
self.name = self.env.temp_data.get('default_role', '')
|
||||
self.name = self.env.current_document.default_role
|
||||
if not self.name:
|
||||
self.name = self.env.config.default_role
|
||||
if not self.name:
|
||||
|
@ -185,13 +185,13 @@ def test_env_relfn2path(app):
|
||||
assert absfn == str(app.srcdir / 'logo.jpg')
|
||||
|
||||
# omit docname (w/ current docname)
|
||||
app.env.temp_data['docname'] = 'subdir/document'
|
||||
app.env.current_document.docname = 'subdir/document'
|
||||
relfn, absfn = app.env.relfn2path('images/logo.jpg')
|
||||
assert Path(relfn) == Path('subdir/images/logo.jpg')
|
||||
assert absfn == str(app.srcdir / 'subdir' / 'images' / 'logo.jpg')
|
||||
|
||||
# omit docname (w/o current docname)
|
||||
app.env.temp_data.clear()
|
||||
app.env.current_document.clear()
|
||||
with pytest.raises(KeyError, match=r"^'docname'$"):
|
||||
app.env.relfn2path('images/logo.jpg')
|
||||
|
||||
|
@ -22,7 +22,8 @@ def do_autodoc(
|
||||
options: dict[str, Any] | None = None,
|
||||
) -> StringList:
|
||||
options = {} if options is None else options.copy()
|
||||
app.env.temp_data.setdefault('docname', 'index') # set dummy docname
|
||||
if not app.env.current_document.docname:
|
||||
app.env.current_document.docname = 'index' # set dummy docname
|
||||
doccls = app.registry.documenters[objtype]
|
||||
docoptions = process_documenter_options(doccls, app.config, options)
|
||||
state = Mock()
|
||||
|
@ -95,9 +95,10 @@ def test_parse_name(app):
|
||||
'test_ext_autodoc.raises(exc) -> None',
|
||||
('test_ext_autodoc', ['raises'], 'exc', 'None'),
|
||||
)
|
||||
directive.env.temp_data['autodoc:module'] = 'test_ext_autodoc'
|
||||
directive.env.current_document.autodoc_module = 'test_ext_autodoc'
|
||||
verify('function', 'raises', ('test_ext_autodoc', ['raises'], None, None))
|
||||
del directive.env.temp_data['autodoc:module']
|
||||
directive.env.current_document.autodoc_module = ''
|
||||
|
||||
directive.env.ref_context['py:module'] = 'test_ext_autodoc'
|
||||
verify('function', 'raises', ('test_ext_autodoc', ['raises'], None, None))
|
||||
verify('class', 'Base', ('test_ext_autodoc', ['Base'], None, None))
|
||||
@ -111,7 +112,7 @@ def test_parse_name(app):
|
||||
)
|
||||
directive.env.ref_context['py:module'] = 'sphinx.testing.util'
|
||||
directive.env.ref_context['py:class'] = 'Foo'
|
||||
directive.env.temp_data['autodoc:class'] = 'SphinxTestApp'
|
||||
directive.env.current_document.autodoc_class = 'SphinxTestApp'
|
||||
verify(
|
||||
'method',
|
||||
'cleanup',
|
||||
@ -526,7 +527,7 @@ def test_autodoc_exception(app):
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autodoc_warnings(app):
|
||||
app.env.temp_data['docname'] = 'dummy'
|
||||
app.env.current_document.docname = 'dummy'
|
||||
|
||||
# can't import module
|
||||
do_autodoc(app, 'module', 'unknown')
|
||||
@ -1299,7 +1300,7 @@ def test_autodoc_module_member_order(app):
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autodoc_module_scope(app):
|
||||
app.env.temp_data['autodoc:module'] = 'target'
|
||||
app.env.current_document.autodoc_module = 'target'
|
||||
actual = do_autodoc(app, 'attribute', 'Class.mdocattr')
|
||||
assert list(actual) == [
|
||||
'',
|
||||
@ -1314,8 +1315,8 @@ def test_autodoc_module_scope(app):
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autodoc_class_scope(app):
|
||||
app.env.temp_data['autodoc:module'] = 'target'
|
||||
app.env.temp_data['autodoc:class'] = 'Class'
|
||||
app.env.current_document.autodoc_module = 'target'
|
||||
app.env.current_document.autodoc_class = 'Class'
|
||||
actual = do_autodoc(app, 'attribute', 'mdocattr')
|
||||
assert list(actual) == [
|
||||
'',
|
||||
|
@ -38,7 +38,7 @@ def settings(app):
|
||||
settings = optparser.get_default_values()
|
||||
settings.smart_quotes = True
|
||||
settings.env = app.builder.env
|
||||
settings.env.temp_data['docname'] = 'dummy'
|
||||
settings.env.current_document.docname = 'dummy'
|
||||
settings.contentsname = 'dummy'
|
||||
domain_context = sphinx_domains(settings.env)
|
||||
domain_context.enable()
|
||||
|
@ -116,7 +116,7 @@ def test_format_date_timezone():
|
||||
@pytest.mark.sphinx('html', testroot='root')
|
||||
def test_get_filename_for_language(app):
|
||||
get_filename = i18n.get_image_filename_for_language
|
||||
app.env.temp_data['docname'] = 'index'
|
||||
app.env.current_document.docname = 'index'
|
||||
|
||||
# language is en
|
||||
app.env.config.language = 'en'
|
||||
@ -155,7 +155,7 @@ def test_get_filename_for_language(app):
|
||||
assert get_filename('foo.png', app.env) == '/en/foo.png'
|
||||
|
||||
# docpath (for a document in the sub directory)
|
||||
app.env.temp_data['docname'] = 'subdir/index'
|
||||
app.env.current_document.docname = 'subdir/index'
|
||||
assert get_filename('foo.png', app.env) == '/subdir/en/foo.png'
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user