Merge branch '2.0'

This commit is contained in:
Takeshi KOMIYA 2019-06-30 01:08:48 +09:00
commit c18dcf08f9
11 changed files with 361 additions and 507 deletions

View File

@ -243,21 +243,23 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
These work exactly like :rst:dir:`autoclass` etc.,
but do not offer the options used for automatic member documentation.
:rst:dir:`autodata` and :rst:dir:`autoattribute` support
the ``annotation`` option.
Without this option, the representation of the object
will be shown in the documentation.
When the option is given without arguments,
only the name of the object will be printed::
:rst:dir:`autodata` and :rst:dir:`autoattribute` support the ``annotation``
option. The option controls how the value of variable is shown. If specified
without arguments, only the name of the variable will be printed, and its value
is not shown::
.. autodata:: CD_DRIVE
:annotation:
You can tell sphinx what should be printed after the name::
If the option specified with arguments, it is printed after the name as a value
of the variable::
.. autodata:: CD_DRIVE
:annotation: = your CD device name
By default, without ``annotation`` option, Sphinx tries to obtain the value of
the variable and print it after the name.
For module data members and class attributes, documentation can either be put
into a comment with special formatting (using a ``#:`` to start the comment
instead of just ``#``), or in a docstring *after* the definition. Comments

View File

@ -10,21 +10,22 @@
"""
import copy
from typing import NamedTuple
from typing import Any, Callable, Dict, Iterable, List, NamedTuple, Tuple, Type, Union
from docutils import nodes
from docutils.nodes import Element, Node, system_message
from docutils.parsers.rst.states import Inliner
from sphinx.addnodes import pending_xref
from sphinx.errors import SphinxError
from sphinx.locale import _
from sphinx.roles import XRefRole
from sphinx.util.typing import RoleFunction
if False:
# For type annotation
from typing import Any, Callable, Dict, Iterable, List, Tuple, Type, Union # NOQA
from docutils import nodes # NOQA
from docutils.parsers.rst.states import Inliner # NOQA
from sphinx import addnodes # NOQA
from sphinx.builders import Builder # NOQA
from sphinx.environment import BuildEnvironment # NOQA
from sphinx.roles import XRefRole # NOQA
from sphinx.util.typing import RoleFunction # NOQA
from sphinx.builders import Builder
from sphinx.environment import BuildEnvironment
class ObjType:
@ -46,8 +47,7 @@ class ObjType:
'searchprio': 1,
}
def __init__(self, lname, *roles, **attrs):
# type: (str, Any, Any) -> None
def __init__(self, lname: str, *roles, **attrs) -> None:
self.lname = lname
self.roles = roles # type: Tuple
self.attrs = self.known_attrs.copy() # type: Dict
@ -82,15 +82,14 @@ class Index:
localname = None # type: str
shortname = None # type: str
def __init__(self, domain):
# type: (Domain) -> None
def __init__(self, domain: "Domain") -> None:
if self.name is None or self.localname is None:
raise SphinxError('Index subclass %s has no valid name or localname'
% self.__class__.__name__)
self.domain = domain
def generate(self, docnames=None):
# type: (Iterable[str]) -> Tuple[List[Tuple[str, List[IndexEntry]]], bool]
def generate(self, docnames: Iterable[str] = None
) -> Tuple[List[Tuple[str, List[IndexEntry]]], bool]:
"""Get entries for the index.
If ``docnames`` is given, restrict to entries referring to these
@ -181,7 +180,7 @@ class Domain:
#: role name -> a warning message if reference is missing
dangling_warnings = {} # type: Dict[str, str]
#: node_class -> (enum_node_type, title_getter)
enumerable_nodes = {} # type: Dict[Type[nodes.Node], Tuple[str, Callable]]
enumerable_nodes = {} # type: Dict[Type[Node], Tuple[str, Callable]]
#: data value for a fresh environment
initial_data = {} # type: Dict
@ -190,8 +189,7 @@ class Domain:
#: data version, bump this when the format of `self.data` changes
data_version = 0
def __init__(self, env):
# type: (BuildEnvironment) -> None
def __init__(self, env: "BuildEnvironment") -> None:
self.env = env # type: BuildEnvironment
self._role_cache = {} # type: Dict[str, Callable]
self._directive_cache = {} # type: Dict[str, Callable]
@ -220,8 +218,7 @@ class Domain:
self.objtypes_for_role = self._role2type.get # type: Callable[[str], List[str]]
self.role_for_objtype = self._type2role.get # type: Callable[[str], str]
def add_object_type(self, name, objtype):
# type: (str, ObjType) -> None
def add_object_type(self, name: str, objtype: ObjType) -> None:
"""Add an object type."""
self.object_types[name] = objtype
if objtype.roles:
@ -232,8 +229,7 @@ class Domain:
for role in objtype.roles:
self._role2type.setdefault(role, []).append(name)
def role(self, name):
# type: (str) -> RoleFunction
def role(self, name: str) -> RoleFunction:
"""Return a role adapter function that always gives the registered
role its full name ('domain:name') as the first argument.
"""
@ -243,15 +239,15 @@ class Domain:
return None
fullname = '%s:%s' % (self.name, name)
def role_adapter(typ, rawtext, text, lineno, inliner, options={}, content=[]):
# type: (str, str, str, int, Inliner, Dict, List[str]) -> Tuple[List[nodes.Node], List[nodes.system_message]] # NOQA
def role_adapter(typ: str, rawtext: str, text: str, lineno: int,
inliner: Inliner, options: Dict = {}, content: List[str] = []
) -> Tuple[List[Node], List[system_message]]:
return self.roles[name](fullname, rawtext, text, lineno,
inliner, options, content)
self._role_cache[name] = role_adapter
return role_adapter
def directive(self, name):
# type: (str) -> Callable
def directive(self, name: str) -> Callable:
"""Return a directive adapter class that always gives the registered
directive its full name ('domain:name') as ``self.name``.
"""
@ -263,8 +259,7 @@ class Domain:
BaseDirective = self.directives[name]
class DirectiveAdapter(BaseDirective): # type: ignore
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
self.name = fullname
return super().run()
self._directive_cache[name] = DirectiveAdapter
@ -272,13 +267,11 @@ class Domain:
# methods that should be overwritten
def clear_doc(self, docname):
# type: (str) -> None
def clear_doc(self, docname: str) -> None:
"""Remove traces of a document in the domain-specific inventories."""
pass
def merge_domaindata(self, docnames, otherdata):
# type: (List[str], Dict) -> None
def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
"""Merge in data regarding *docnames* from a different domaindata
inventory (coming from a subprocess in parallel builds).
"""
@ -286,26 +279,24 @@ class Domain:
'to be able to do parallel builds!' %
self.__class__)
def process_doc(self, env, docname, document):
# type: (BuildEnvironment, str, nodes.document) -> None
def process_doc(self, env: "BuildEnvironment", docname: str,
document: nodes.document) -> None:
"""Process a document after it is read by the environment."""
pass
def check_consistency(self):
# type: () -> None
def check_consistency(self) -> None:
"""Do consistency checks (**experimental**)."""
pass
def process_field_xref(self, pnode):
# type: (addnodes.pending_xref) -> None
def process_field_xref(self, pnode: pending_xref) -> None:
"""Process a pending xref created in a doc field.
For example, attach information about the current scope.
"""
pass
def resolve_xref(self, env, fromdocname, builder,
typ, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
def resolve_xref(self, env: "BuildEnvironment", fromdocname: str, builder: "Builder",
typ: str, target: str, node: pending_xref, contnode: Element
) -> Element:
"""Resolve the pending_xref *node* with the given *typ* and *target*.
This method should return a new node, to replace the xref node,
@ -321,8 +312,9 @@ class Domain:
"""
pass
def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, addnodes.pending_xref, nodes.Element) -> List[Tuple[str, nodes.Element]] # NOQA
def resolve_any_xref(self, env: "BuildEnvironment", fromdocname: str, builder: "Builder",
target: str, node: pending_xref, contnode: Element
) -> List[Tuple[str, Element]]:
"""Resolve the pending_xref *node* with the given *target*.
The reference comes from an "any" or similar role, which means that we
@ -338,8 +330,7 @@ class Domain:
"""
raise NotImplementedError
def get_objects(self):
# type: () -> Iterable[Tuple[str, str, str, str, str, int]]
def get_objects(self) -> Iterable[Tuple[str, str, str, str, str, int]]:
"""Return an iterable of "object descriptions".
Object descriptions are tuples with six items:
@ -374,20 +365,17 @@ class Domain:
"""
return []
def get_type_name(self, type, primary=False):
# type: (ObjType, bool) -> str
def get_type_name(self, type: ObjType, primary: bool = False) -> str:
"""Return full name for given ObjType."""
if primary:
return type.lname
return _('%s %s') % (self.label, type.lname)
def get_enumerable_node_type(self, node):
# type: (nodes.Node) -> str
def get_enumerable_node_type(self, node: Node) -> str:
"""Get type of enumerable nodes (experimental)."""
enum_node_type, _ = self.enumerable_nodes.get(node.__class__, (None, None))
return enum_node_type
def get_full_qualified_name(self, node):
# type: (nodes.Element) -> str
def get_full_qualified_name(self, node: Element) -> str:
"""Return full qualified name for given node."""
return None

View File

@ -10,24 +10,23 @@
import re
import string
from typing import Any, Dict, Iterator, List, Tuple
from docutils import nodes
from docutils.nodes import Element
from sphinx import addnodes
from sphinx.addnodes import pending_xref, desc_signature
from sphinx.application import Sphinx
from sphinx.builders import Builder
from sphinx.directives import ObjectDescription
from sphinx.domains import Domain, ObjType
from sphinx.environment import BuildEnvironment
from sphinx.locale import _
from sphinx.roles import XRefRole
from sphinx.util.docfields import Field, TypedField
from sphinx.util.nodes import make_refnode
if False:
# For type annotation
from typing import Any, Dict, Iterator, List, Tuple # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.builders import Builder # NOQA
from sphinx.environment import BuildEnvironment # NOQA
# RE to split at word boundaries
wsplit_re = re.compile(r'(\W+)')
@ -79,23 +78,20 @@ class CObject(ObjectDescription):
'struct', '_Bool',
}
def _parse_type(self, node, ctype):
# type: (nodes.Element, str) -> None
def _parse_type(self, node: Element, ctype: str) -> None:
# add cross-ref nodes for all words
for part in [_f for _f in wsplit_re.split(ctype) if _f]:
tnode = nodes.Text(part, part)
if part[0] in string.ascii_letters + '_' and \
part not in self.stopwords:
pnode = addnodes.pending_xref(
'', refdomain='c', reftype='type', reftarget=part,
modname=None, classname=None)
pnode = pending_xref('', refdomain='c', reftype='type', reftarget=part,
modname=None, classname=None)
pnode += tnode
node += pnode
else:
node += tnode
def _parse_arglist(self, arglist):
# type: (str) -> Iterator[str]
def _parse_arglist(self, arglist: str) -> Iterator[str]:
while True:
m = c_funcptr_arg_sig_re.match(arglist)
if m:
@ -113,8 +109,7 @@ class CObject(ObjectDescription):
yield arglist
break
def handle_signature(self, sig, signode):
# type: (str, addnodes.desc_signature) -> str
def handle_signature(self, sig: str, signode: desc_signature) -> str:
"""Transform a C signature into RST nodes."""
# first try the function pointer signature regex, it's more specific
m = c_funcptr_sig_re.match(sig)
@ -183,8 +178,7 @@ class CObject(ObjectDescription):
signode += addnodes.desc_addname(const, const)
return fullname
def get_index_text(self, name):
# type: (str) -> str
def get_index_text(self, name: str) -> str:
if self.objtype == 'function':
return _('%s (C function)') % name
elif self.objtype == 'member':
@ -198,8 +192,7 @@ class CObject(ObjectDescription):
else:
return ''
def add_target_and_index(self, name, sig, signode):
# type: (str, str, addnodes.desc_signature) -> None
def add_target_and_index(self, name: str, sig: str, signode: desc_signature) -> None:
# for C API items we add a prefix since names are usually not qualified
# by a module name and so easily clash with e.g. section titles
targetname = 'c.' + name
@ -221,23 +214,21 @@ class CObject(ObjectDescription):
self.indexnode['entries'].append(('single', indextext,
targetname, '', None))
def before_content(self):
# type: () -> None
def before_content(self) -> None:
self.typename_set = False
if self.name == 'c:type':
if self.names:
self.env.ref_context['c:type'] = self.names[0]
self.typename_set = True
def after_content(self):
# type: () -> None
def after_content(self) -> None:
if self.typename_set:
self.env.ref_context.pop('c:type', None)
class CXRefRole(XRefRole):
def process_link(self, env, refnode, has_explicit_title, title, target):
# type: (BuildEnvironment, nodes.Element, bool, str, str) -> Tuple[str, str]
def process_link(self, env: BuildEnvironment, refnode: Element,
has_explicit_title: bool, title: str, target: str) -> Tuple[str, str]:
if not has_explicit_title:
target = target.lstrip('~') # only has a meaning for the title
# if the first character is a tilde, don't display the module/class
@ -280,22 +271,20 @@ class CDomain(Domain):
'objects': {}, # fullname -> docname, objtype
} # type: Dict[str, Dict[str, Tuple[str, Any]]]
def clear_doc(self, docname):
# type: (str) -> None
def clear_doc(self, docname: str) -> None:
for fullname, (fn, _l) in list(self.data['objects'].items()):
if fn == docname:
del self.data['objects'][fullname]
def merge_domaindata(self, docnames, otherdata):
# type: (List[str], Dict) -> None
def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
# XXX check duplicates
for fullname, (fn, objtype) in otherdata['objects'].items():
if fn in docnames:
self.data['objects'][fullname] = (fn, objtype)
def resolve_xref(self, env, fromdocname, builder,
typ, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
typ: str, target: str, node: pending_xref, contnode: Element
) -> Element:
# strip pointer asterisk
target = target.rstrip(' *')
# becase TypedField can generate xrefs
@ -307,9 +296,9 @@ class CDomain(Domain):
return make_refnode(builder, fromdocname, obj[0], 'c.' + target,
contnode, target)
def resolve_any_xref(self, env, fromdocname, builder, target,
node, contnode):
# type: (BuildEnvironment, str, Builder, str, addnodes.pending_xref, nodes.Element) -> List[Tuple[str, nodes.Element]] # NOQA
def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
target: str, node: pending_xref, contnode: Element
) -> List[Tuple[str, Element]]:
# strip pointer asterisk
target = target.rstrip(' *')
if target not in self.data['objects']:
@ -319,14 +308,12 @@ class CDomain(Domain):
make_refnode(builder, fromdocname, obj[0], 'c.' + target,
contnode, target))]
def get_objects(self):
# type: () -> Iterator[Tuple[str, str, str, str, str, int]]
def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]:
for refname, (docname, type) in list(self.data['objects'].items()):
yield (refname, refname, type, docname, 'c.' + refname, 1)
def setup(app):
# type: (Sphinx) -> Dict[str, Any]
def setup(app: Sphinx) -> Dict[str, Any]:
app.add_domain(CDomain)
return {

View File

@ -9,9 +9,11 @@
"""
from collections import namedtuple
from typing import Any, Dict, List
from typing import cast
from docutils import nodes
from docutils.nodes import Node
from sphinx import addnodes
from sphinx.domains import Domain
@ -21,9 +23,8 @@ from sphinx.util.docutils import SphinxDirective
if False:
# For type annotation
from typing import Any, Dict, List # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.environment import BuildEnvironment # NOQA
from sphinx.application import Sphinx
from sphinx.environment import BuildEnvironment
versionlabels = {
@ -54,8 +55,7 @@ class VersionChange(SphinxDirective):
final_argument_whitespace = True
option_spec = {} # type: Dict
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
node = addnodes.versionmodified()
node.document = self.state.document
self.set_source_info(node)
@ -93,7 +93,7 @@ class VersionChange(SphinxDirective):
domain = cast(ChangeSetDomain, self.env.get_domain('changeset'))
domain.note_changeset(node)
ret = [node] # type: List[nodes.Node]
ret = [node] # type: List[Node]
ret += messages
return ret
@ -108,15 +108,13 @@ class ChangeSetDomain(Domain):
'changes': {}, # version -> list of ChangeSet
} # type: Dict
def clear_doc(self, docname):
# type: (str) -> None
def clear_doc(self, docname: str) -> None:
for version, changes in self.data['changes'].items():
for changeset in changes[:]:
if changeset.docname == docname:
changes.remove(changeset)
def merge_domaindata(self, docnames, otherdata):
# type: (List[str], Dict) -> None
def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
# XXX duplicates?
for version, otherchanges in otherdata['changes'].items():
changes = self.data['changes'].setdefault(version, [])
@ -124,12 +122,10 @@ class ChangeSetDomain(Domain):
if changeset.docname in docnames:
changes.append(changeset)
def process_doc(self, env, docname, document):
# type: (BuildEnvironment, str, nodes.document) -> None
def process_doc(self, env: "BuildEnvironment", docname: str, document: nodes.document) -> None: # NOQA
pass # nothing to do here. All changesets are registered on calling directive.
def note_changeset(self, node):
# type: (addnodes.versionmodified) -> None
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')
@ -137,13 +133,11 @@ class ChangeSetDomain(Domain):
module, objname, node.astext())
self.data['changes'].setdefault(version, []).append(changeset)
def get_changesets_for(self, version):
# type: (str) -> List[ChangeSet]
def get_changesets_for(self, version: str) -> List[ChangeSet]:
return self.data['changes'].get(version, [])
def setup(app):
# type: (Sphinx) -> Dict[str, Any]
def setup(app: "Sphinx") -> Dict[str, Any]:
app.add_domain(ChangeSetDomain)
app.add_directive('deprecated', VersionChange)
app.add_directive('versionadded', VersionChange)

View File

@ -8,11 +8,13 @@
:license: BSD, see LICENSE for details.
"""
from typing import Any, Dict, List, Set, Tuple
from typing import cast
from docutils import nodes
from docutils.nodes import Element
from sphinx import addnodes
from sphinx.addnodes import pending_xref
from sphinx.domains import Domain
from sphinx.locale import __
from sphinx.transforms import SphinxTransform
@ -21,10 +23,10 @@ from sphinx.util.nodes import copy_source_info, make_refnode
if False:
# For type annotation
from typing import Any, Dict, List, Set, Tuple, Union # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.builders import Builder # NOQA
from sphinx.environment import BuildEnvironment # NOQA
from sphinx.application import Sphinx
from sphinx.builders import Builder
from sphinx.environment import BuildEnvironment
logger = logging.getLogger(__name__)
@ -40,17 +42,14 @@ class CitationDomain(Domain):
}
@property
def citations(self):
# type: () -> Dict[str, Tuple[str, str, int]]
def citations(self) -> Dict[str, Tuple[str, str, int]]:
return self.data.setdefault('citations', {})
@property
def citation_refs(self):
# type: () -> Dict[str, Set[str]]
def citation_refs(self) -> Dict[str, Set[str]]:
return self.data.setdefault('citation_refs', {})
def clear_doc(self, docname):
# type: (str) -> None
def clear_doc(self, docname: str) -> None:
for key, (fn, _l, lineno) in list(self.citations.items()):
if fn == docname:
del self.citations[key]
@ -60,8 +59,7 @@ class CitationDomain(Domain):
elif docname in docnames:
docnames.remove(docname)
def merge_domaindata(self, docnames, otherdata):
# type: (List[str], Dict) -> None
def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
# XXX duplicates?
for key, data in otherdata['citations'].items():
if data[0] in docnames:
@ -72,8 +70,7 @@ class CitationDomain(Domain):
if docname in docnames:
citation_refs.add(docname)
def note_citation(self, node):
# type: (nodes.citation) -> None
def note_citation(self, node: nodes.citation) -> None:
label = node[0].astext()
if label in self.citations:
path = self.env.doc2path(self.citations[label][0])
@ -81,20 +78,19 @@ class CitationDomain(Domain):
location=node, type='ref', subtype='citation')
self.citations[label] = (node['docname'], node['ids'][0], node.line)
def note_citation_reference(self, node):
# type: (addnodes.pending_xref) -> None
def note_citation_reference(self, node: pending_xref) -> None:
docnames = self.citation_refs.setdefault(node['reftarget'], set())
docnames.add(self.env.docname)
def check_consistency(self):
# type: () -> None
def check_consistency(self) -> None:
for name, (docname, labelid, lineno) in self.citations.items():
if name not in self.citation_refs:
logger.warning(__('Citation [%s] is not referenced.'), name,
type='ref', subtype='citation', location=(docname, lineno))
def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
def resolve_xref(self, env: "BuildEnvironment", fromdocname: str, builder: "Builder",
typ: str, target: str, node: pending_xref, contnode: Element
) -> Element:
docname, labelid, lineno = self.citations.get(target, ('', '', 0))
if not docname:
return None
@ -102,8 +98,9 @@ class CitationDomain(Domain):
return make_refnode(builder, fromdocname, docname,
labelid, contnode)
def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, addnodes.pending_xref, nodes.Element) -> List[Tuple[str, nodes.Element]] # NOQA
def resolve_any_xref(self, env: "BuildEnvironment", fromdocname: str, builder: "Builder",
target: str, node: pending_xref, contnode: Element
) -> List[Tuple[str, Element]]:
refnode = self.resolve_xref(env, fromdocname, builder, 'ref', target, node, contnode)
if refnode is None:
return []
@ -115,8 +112,7 @@ class CitationDefinitionTransform(SphinxTransform):
"""Mark citation definition labels as not smartquoted."""
default_priority = 619
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
domain = cast(CitationDomain, self.env.get_domain('citation'))
for node in self.document.traverse(nodes.citation):
# register citation node to domain
@ -135,16 +131,15 @@ class CitationReferenceTransform(SphinxTransform):
"""
default_priority = 619
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
domain = cast(CitationDomain, self.env.get_domain('citation'))
for node in self.document.traverse(nodes.citation_reference):
target = node.astext()
ref = addnodes.pending_xref(target, refdomain='citation', reftype='ref',
reftarget=target, refwarn=True,
support_smartquotes=False,
ids=node["ids"],
classes=node.get('classes', []))
ref = pending_xref(target, refdomain='citation', reftype='ref',
reftarget=target, refwarn=True,
support_smartquotes=False,
ids=node["ids"],
classes=node.get('classes', []))
ref += nodes.inline(target, '[%s]' % target)
copy_source_info(node, ref)
node.replace_self(ref)
@ -153,8 +148,7 @@ class CitationReferenceTransform(SphinxTransform):
domain.note_citation_reference(ref)
def setup(app):
# type: (Sphinx) -> Dict[str, Any]
def setup(app: "Sphinx") -> Dict[str, Any]:
app.add_domain(CitationDomain)
app.add_transform(CitationDefinitionTransform)
app.add_transform(CitationReferenceTransform)

View File

@ -8,26 +8,26 @@
:license: BSD, see LICENSE for details.
"""
from typing import Any, Dict, Iterator, List, Tuple
from docutils import nodes
from docutils.nodes import Element, Node
from docutils.parsers.rst import directives
from sphinx import addnodes
from sphinx.addnodes import desc_signature, pending_xref
from sphinx.application import Sphinx
from sphinx.builders import Builder
from sphinx.directives import ObjectDescription
from sphinx.domains import Domain, ObjType
from sphinx.domains.python import _pseudo_parse_arglist
from sphinx.environment import BuildEnvironment
from sphinx.locale import _
from sphinx.roles import XRefRole
from sphinx.util.docfields import Field, GroupedField, TypedField
from sphinx.util.docutils import SphinxDirective
from sphinx.util.nodes import make_refnode
if False:
# For type annotation
from typing import Any, Dict, Iterator, List, Tuple # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.builders import Builder # NOQA
from sphinx.environment import BuildEnvironment # NOQA
class JSObject(ObjectDescription):
"""
@ -44,8 +44,7 @@ class JSObject(ObjectDescription):
#: based on directive nesting
allow_nesting = False
def handle_signature(self, sig, signode):
# type: (str, addnodes.desc_signature) -> Tuple[str, str]
def handle_signature(self, sig: str, signode: desc_signature) -> Tuple[str, str]:
"""Breaks down construct signatures
Parses out prefix and argument list from construct definition. The
@ -98,8 +97,8 @@ class JSObject(ObjectDescription):
_pseudo_parse_arglist(signode, arglist)
return fullname, prefix
def add_target_and_index(self, name_obj, sig, signode):
# type: (Tuple[str, str], str, addnodes.desc_signature) -> None
def add_target_and_index(self, name_obj: Tuple[str, str], sig: str,
signode: desc_signature) -> None:
mod_name = self.env.ref_context.get('js:module')
fullname = (mod_name and mod_name + '.' or '') + name_obj[0]
if fullname not in self.state.document.ids:
@ -122,8 +121,7 @@ class JSObject(ObjectDescription):
fullname.replace('$', '_S_'),
'', None))
def get_index_text(self, objectname, name_obj):
# type: (str, Tuple[str, str]) -> str
def get_index_text(self, objectname: str, name_obj: Tuple[str, str]) -> str:
name, obj = name_obj
if self.objtype == 'function':
if not obj:
@ -137,8 +135,7 @@ class JSObject(ObjectDescription):
return _('%s (%s attribute)') % (name, obj)
return ''
def before_content(self):
# type: () -> None
def before_content(self) -> None:
"""Handle object nesting before content
:py:class:`JSObject` represents JavaScript language constructs. For
@ -174,8 +171,7 @@ class JSObject(ObjectDescription):
objects = self.env.ref_context.setdefault('js:objects', [])
objects.append(prefix)
def after_content(self):
# type: () -> None
def after_content(self) -> None:
"""Handle object de-nesting after content
If this class is a nestable object, removing the last nested class prefix
@ -246,12 +242,11 @@ class JSModule(SphinxDirective):
'noindex': directives.flag
}
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
mod_name = self.arguments[0].strip()
self.env.ref_context['js:module'] = mod_name
noindex = 'noindex' in self.options
ret = [] # type: List[nodes.Node]
ret = [] # type: List[Node]
if not noindex:
self.env.domaindata['js']['modules'][mod_name] = self.env.docname
# Make a duplicate entry in 'objects' to facilitate searching for
@ -269,8 +264,8 @@ class JSModule(SphinxDirective):
class JSXRefRole(XRefRole):
def process_link(self, env, refnode, has_explicit_title, title, target):
# type: (BuildEnvironment, nodes.Element, bool, str, str) -> Tuple[str, str]
def process_link(self, env: BuildEnvironment, refnode: Element,
has_explicit_title: bool, title: str, target: str) -> Tuple[str, str]:
# basically what sphinx.domains.python.PyXRefRole does
refnode['js:object'] = env.ref_context.get('js:object')
refnode['js:module'] = env.ref_context.get('js:module')
@ -322,8 +317,7 @@ class JavaScriptDomain(Domain):
'modules': {}, # mod_name -> docname
} # type: Dict[str, Dict[str, Tuple[str, str]]]
def clear_doc(self, docname):
# type: (str) -> None
def clear_doc(self, docname: str) -> None:
for fullname, (pkg_docname, _l) in list(self.data['objects'].items()):
if pkg_docname == docname:
del self.data['objects'][fullname]
@ -331,8 +325,7 @@ class JavaScriptDomain(Domain):
if pkg_docname == docname:
del self.data['modules'][mod_name]
def merge_domaindata(self, docnames, otherdata):
# type: (List[str], Dict) -> None
def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
# XXX check duplicates
for fullname, (fn, objtype) in otherdata['objects'].items():
if fn in docnames:
@ -341,8 +334,8 @@ class JavaScriptDomain(Domain):
if pkg_docname in docnames:
self.data['modules'][mod_name] = pkg_docname
def find_obj(self, env, mod_name, prefix, name, typ, searchorder=0):
# type: (BuildEnvironment, str, str, str, str, int) -> Tuple[str, Tuple[str, str]]
def find_obj(self, env: BuildEnvironment, mod_name: str, prefix: str, name: str,
typ: str, searchorder: int = 0) -> Tuple[str, Tuple[str, str]]:
if name[-2:] == '()':
name = name[:-2]
objects = self.data['objects']
@ -366,9 +359,9 @@ class JavaScriptDomain(Domain):
return newname, objects.get(newname)
def resolve_xref(self, env, fromdocname, builder, typ, target, node,
contnode):
# type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
typ: str, target: str, node: pending_xref, contnode: Element
) -> Element:
mod_name = node.get('js:module')
prefix = node.get('js:object')
searchorder = node.hasattr('refspecific') and 1 or 0
@ -378,9 +371,9 @@ class JavaScriptDomain(Domain):
return make_refnode(builder, fromdocname, obj[0],
name.replace('$', '_S_'), contnode, name)
def resolve_any_xref(self, env, fromdocname, builder, target, node,
contnode):
# type: (BuildEnvironment, str, Builder, str, addnodes.pending_xref, nodes.Element) -> List[Tuple[str, nodes.Element]] # NOQA
def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
target: str, node: pending_xref, contnode: Element
) -> List[Tuple[str, Element]]:
mod_name = node.get('js:module')
prefix = node.get('js:object')
name, obj = self.find_obj(env, mod_name, prefix, target, None, 1)
@ -390,14 +383,12 @@ class JavaScriptDomain(Domain):
make_refnode(builder, fromdocname, obj[0],
name.replace('$', '_S_'), contnode, name))]
def get_objects(self):
# type: () -> Iterator[Tuple[str, str, str, str, str, int]]
def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]:
for refname, (docname, type) in list(self.data['objects'].items()):
yield refname, refname, type, docname, \
refname.replace('$', '_S_'), 1
def get_full_qualified_name(self, node):
# type: (nodes.Element) -> str
def get_full_qualified_name(self, node: Element) -> str:
modname = node.get('js:module')
prefix = node.get('js:object')
target = node.get('reftarget')
@ -407,8 +398,7 @@ class JavaScriptDomain(Domain):
return '.'.join(filter(None, [modname, prefix, target]))
def setup(app):
# type: (Sphinx) -> Dict[str, Any]
def setup(app: Sphinx) -> Dict[str, Any]:
app.add_domain(JavaScriptDomain)
return {

View File

@ -9,12 +9,16 @@
"""
import warnings
from typing import Any, Dict, Iterable, List, Tuple
from docutils import nodes
from docutils.nodes import Element, Node, system_message
from docutils.nodes import make_id
from sphinx.addnodes import pending_xref
from sphinx.deprecation import RemovedInSphinx40Warning
from sphinx.domains import Domain
from sphinx.environment import BuildEnvironment
from sphinx.locale import __
from sphinx.roles import XRefRole
from sphinx.util import logging
@ -22,18 +26,16 @@ from sphinx.util.nodes import make_refnode
if False:
# For type annotation
from typing import Any, Dict, Iterable, List, Tuple # NOQA
from sphinx import addnodes # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.builders import Builder # NOQA
from sphinx.environment import BuildEnvironment # NOQA
from sphinx.application import Sphinx
from sphinx.builders import Builder
logger = logging.getLogger(__name__)
class MathReferenceRole(XRefRole):
def result_nodes(self, document, env, node, is_ref):
# type: (nodes.document, BuildEnvironment, nodes.Element, bool) -> Tuple[List[nodes.Node], List[nodes.system_message]] # NOQA
def result_nodes(self, document: nodes.document, env: BuildEnvironment, node: Element,
is_ref: bool) -> Tuple[List[Node], List[system_message]]:
node['refdomain'] = 'math'
return [node], []
@ -58,12 +60,10 @@ class MathDomain(Domain):
}
@property
def equations(self):
# type: () -> Dict[str, Tuple[str, int]]
def equations(self) -> Dict[str, Tuple[str, int]]:
return self.data.setdefault('objects', {}) # labelid -> (docname, eqno)
def note_equation(self, docname, labelid, location=None):
# type: (str, str, Any) -> None
def note_equation(self, docname: str, labelid: str, location: Any = None) -> None:
if labelid in self.equations:
other = self.equations[labelid][0]
logger.warning(__('duplicate label of equation %s, other instance in %s') %
@ -71,31 +71,27 @@ class MathDomain(Domain):
self.equations[labelid] = (docname, self.env.new_serialno('eqno') + 1)
def get_equation_number_for(self, labelid):
# type: (str) -> int
def get_equation_number_for(self, labelid: str) -> int:
if labelid in self.equations:
return self.equations[labelid][1]
else:
return None
def process_doc(self, env, docname, document):
# type: (BuildEnvironment, str, nodes.document) -> None
def math_node(node):
# type: (nodes.Node) -> bool
def process_doc(self, env: BuildEnvironment, docname: str,
document: nodes.document) -> None:
def math_node(node: Node) -> bool:
return isinstance(node, (nodes.math, nodes.math_block))
self.data['has_equations'][docname] = any(document.traverse(math_node))
def clear_doc(self, docname):
# type: (str) -> None
def clear_doc(self, docname: str) -> None:
for equation_id, (doc, eqno) in list(self.equations.items()):
if doc == docname:
del self.equations[equation_id]
self.data['has_equations'].pop(docname, None)
def merge_domaindata(self, docnames, otherdata):
# type: (Iterable[str], Dict) -> None
def merge_domaindata(self, docnames: Iterable[str], otherdata: Dict) -> None:
for labelid, (doc, eqno) in otherdata['objects'].items():
if doc in docnames:
self.equations[labelid] = (doc, eqno)
@ -103,8 +99,9 @@ class MathDomain(Domain):
for docname in docnames:
self.data['has_equations'][docname] = otherdata['has_equations'][docname]
def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: "Builder",
typ: str, target: str, node: pending_xref, contnode: Element
) -> Element:
assert typ in ('eq', 'numref')
docname, number = self.equations.get(target, (None, None))
if docname:
@ -131,20 +128,19 @@ class MathDomain(Domain):
else:
return None
def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, addnodes.pending_xref, nodes.Element) -> List[Tuple[str, nodes.Element]] # NOQA
def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: "Builder",
target: str, node: pending_xref, contnode: Element
) -> List[Tuple[str, Element]]:
refnode = self.resolve_xref(env, fromdocname, builder, 'eq', target, node, contnode)
if refnode is None:
return []
else:
return [('eq', refnode)]
def get_objects(self):
# type: () -> List
def get_objects(self) -> List:
return []
def add_equation(self, env, docname, labelid):
# type: (BuildEnvironment, str, str) -> int
def add_equation(self, env: BuildEnvironment, docname: str, labelid: str) -> int:
warnings.warn('MathDomain.add_equation() is deprecated.',
RemovedInSphinx40Warning)
if labelid in self.equations:
@ -156,20 +152,17 @@ class MathDomain(Domain):
self.equations[labelid] = (docname, eqno)
return eqno
def get_next_equation_number(self, docname):
# type: (str) -> int
def get_next_equation_number(self, docname: str) -> int:
warnings.warn('MathDomain.get_next_equation_number() is deprecated.',
RemovedInSphinx40Warning)
targets = [eq for eq in self.equations.values() if eq[0] == docname]
return len(targets) + 1
def has_equations(self):
# type: () -> bool
def has_equations(self) -> bool:
return any(self.data['has_equations'].values())
def setup(app):
# type: (Sphinx) -> Dict[str, Any]
def setup(app: "Sphinx") -> Dict[str, Any]:
app.add_domain(MathDomain)
app.add_role('eq', MathReferenceRole(warn_dangling=True))

View File

@ -10,29 +10,29 @@
import re
import warnings
from typing import Any, Dict, Iterable, Iterator, List, Tuple, Type
from typing import cast
from docutils import nodes
from docutils.nodes import Element, Node
from docutils.parsers.rst import directives
from sphinx import addnodes
from sphinx.addnodes import pending_xref, desc_signature
from sphinx.application import Sphinx
from sphinx.builders import Builder
from sphinx.deprecation import RemovedInSphinx40Warning
from sphinx.directives import ObjectDescription
from sphinx.domains import Domain, ObjType, Index, IndexEntry
from sphinx.environment import BuildEnvironment
from sphinx.locale import _, __
from sphinx.roles import XRefRole
from sphinx.util import logging
from sphinx.util.docfields import Field, GroupedField, TypedField
from sphinx.util.docutils import SphinxDirective
from sphinx.util.nodes import make_refnode
from sphinx.util.typing import TextlikeNode
if False:
# For type annotation
from typing import Any, Dict, Iterable, Iterator, List, Tuple, Type # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.builders import Builder # NOQA
from sphinx.environment import BuildEnvironment # NOQA
from sphinx.util.typing import TextlikeNode # NOQA
logger = logging.getLogger(__name__)
@ -58,8 +58,7 @@ pairindextypes = {
}
def _pseudo_parse_arglist(signode, arglist):
# type: (addnodes.desc_signature, str) -> None
def _pseudo_parse_arglist(signode: desc_signature, arglist: str) -> None:
""""Parse" a list of arguments separated by commas.
Arguments can have "optional" annotations given by enclosing them in
@ -67,7 +66,7 @@ def _pseudo_parse_arglist(signode, arglist):
string literal (e.g. default argument value).
"""
paramlist = addnodes.desc_parameterlist()
stack = [paramlist] # type: List[nodes.Element]
stack = [paramlist] # type: List[Element]
try:
for argument in arglist.split(','):
argument = argument.strip()
@ -110,15 +109,9 @@ def _pseudo_parse_arglist(signode, arglist):
# This override allows our inline type specifiers to behave like :class: link
# when it comes to handling "." and "~" prefixes.
class PyXrefMixin:
def make_xref(self,
rolename, # type: str
domain, # type: str
target, # type: str
innernode=nodes.emphasis, # type: Type[TextlikeNode]
contnode=None, # type: nodes.Node
env=None, # type: BuildEnvironment
):
# type: (...) -> nodes.Node
def make_xref(self, rolename: str, domain: str, target: str,
innernode: Type[TextlikeNode] = nodes.emphasis,
contnode: Node = None, env: BuildEnvironment = None) -> Node:
result = super().make_xref(rolename, domain, target, # type: ignore
innernode, contnode, env)
result['refspecific'] = True
@ -133,15 +126,9 @@ class PyXrefMixin:
break
return result
def make_xrefs(self,
rolename, # type: str
domain, # type: str
target, # type: str
innernode=nodes.emphasis, # type: Type[TextlikeNode]
contnode=None, # type: nodes.Node
env=None, # type: BuildEnvironment
):
# type: (...) -> List[nodes.Node]
def make_xrefs(self, rolename: str, domain: str, target: str,
innernode: Type[TextlikeNode] = nodes.emphasis,
contnode: Node = None, env: BuildEnvironment = None) -> List[Node]:
delims = r'(\s*[\[\]\(\),](?:\s*or\s)?\s*|\s+or\s+)'
delims_re = re.compile(delims)
sub_targets = re.split(delims, target)
@ -163,9 +150,9 @@ class PyXrefMixin:
class PyField(PyXrefMixin, Field):
def make_xref(self, rolename, domain, target,
innernode=nodes.emphasis, contnode=None, env=None):
# type: (str, str, str, Type[TextlikeNode], nodes.Node, BuildEnvironment) -> nodes.Node # NOQA
def make_xref(self, rolename: str, domain: str, target: str,
innernode: Type[TextlikeNode] = nodes.emphasis,
contnode: Node = None, env: BuildEnvironment = None) -> Node:
if rolename == 'class' and target == 'None':
# None is not a type, so use obj role instead.
rolename = 'obj'
@ -178,9 +165,9 @@ class PyGroupedField(PyXrefMixin, GroupedField):
class PyTypedField(PyXrefMixin, TypedField):
def make_xref(self, rolename, domain, target,
innernode=nodes.emphasis, contnode=None, env=None):
# type: (str, str, str, Type[TextlikeNode], nodes.Node, BuildEnvironment) -> nodes.Node # NOQA
def make_xref(self, rolename: str, domain: str, target: str,
innernode: Type[TextlikeNode] = nodes.emphasis,
contnode: Node = None, env: BuildEnvironment = None) -> Node:
if rolename == 'class' and target == 'None':
# None is not a type, so use obj role instead.
rolename = 'obj'
@ -222,22 +209,19 @@ class PyObject(ObjectDescription):
allow_nesting = False
def get_signature_prefix(self, sig):
# type: (str) -> str
def get_signature_prefix(self, sig: str) -> str:
"""May return a prefix to put before the object name in the
signature.
"""
return ''
def needs_arglist(self):
# type: () -> bool
def needs_arglist(self) -> bool:
"""May return true if an empty argument list is to be generated even if
the document contains none.
"""
return False
def handle_signature(self, sig, signode):
# type: (str, addnodes.desc_signature) -> Tuple[str, str]
def handle_signature(self, sig: str, signode: desc_signature) -> Tuple[str, str]:
"""Transform a Python signature into RST nodes.
Return (fully qualified name of the thing, classname if any).
@ -311,13 +295,12 @@ class PyObject(ObjectDescription):
return fullname, prefix
def get_index_text(self, modname, name):
# type: (str, Tuple[str, str]) -> str
def get_index_text(self, modname: str, name: Tuple[str, str]) -> str:
"""Return the text for the index entry of the object."""
raise NotImplementedError('must be implemented in subclasses')
def add_target_and_index(self, name_cls, sig, signode):
# type: (Tuple[str, str], str, addnodes.desc_signature) -> None
def add_target_and_index(self, name_cls: Tuple[str, str], sig: str,
signode: desc_signature) -> None:
modname = self.options.get('module', self.env.ref_context.get('py:module'))
fullname = (modname and modname + '.' or '') + name_cls[0]
# note target
@ -336,8 +319,7 @@ class PyObject(ObjectDescription):
self.indexnode['entries'].append(('single', indextext,
fullname, '', None))
def before_content(self):
# type: () -> None
def before_content(self) -> None:
"""Handle object nesting before content
:py:class:`PyObject` represents Python language constructs. For
@ -370,8 +352,7 @@ class PyObject(ObjectDescription):
modules.append(self.env.ref_context.get('py:module'))
self.env.ref_context['py:module'] = self.options['module']
def after_content(self):
# type: () -> None
def after_content(self) -> None:
"""Handle object de-nesting after content
If this class is a nestable object, removing the last nested class prefix
@ -402,19 +383,16 @@ class PyModulelevel(PyObject):
Description of an object on module level (functions, data).
"""
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
warnings.warn('PyClassmember is deprecated.',
RemovedInSphinx40Warning)
return super().run()
def needs_arglist(self):
# type: () -> bool
def needs_arglist(self) -> bool:
return self.objtype == 'function'
def get_index_text(self, modname, name_cls):
# type: (str, Tuple[str, str]) -> str
def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str:
if self.objtype == 'function':
if not modname:
return _('%s() (built-in function)') % name_cls[0]
@ -435,19 +413,16 @@ class PyFunction(PyObject):
'async': directives.flag,
})
def get_signature_prefix(self, sig):
# type: (str) -> str
def get_signature_prefix(self, sig: str) -> str:
if 'async' in self.options:
return 'async '
else:
return ''
def needs_arglist(self):
# type: () -> bool
def needs_arglist(self) -> bool:
return True
def get_index_text(self, modname, name_cls):
# type: (str, Tuple[str, str]) -> str
def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str:
name, cls = name_cls
if modname:
return _('%s() (in module %s)') % (name, modname)
@ -458,8 +433,7 @@ class PyFunction(PyObject):
class PyVariable(PyObject):
"""Description of a variable."""
def get_index_text(self, modname, name_cls):
# type: (str, Tuple[str, str]) -> str
def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str:
name, cls = name_cls
if modname:
return _('%s (in module %s)') % (name, modname)
@ -474,12 +448,10 @@ class PyClasslike(PyObject):
allow_nesting = True
def get_signature_prefix(self, sig):
# type: (str) -> str
def get_signature_prefix(self, sig: str) -> str:
return self.objtype + ' '
def get_index_text(self, modname, name_cls):
# type: (str, Tuple[str, str]) -> str
def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str:
if self.objtype == 'class':
if not modname:
return _('%s (built-in class)') % name_cls[0]
@ -495,27 +467,23 @@ class PyClassmember(PyObject):
Description of a class member (methods, attributes).
"""
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
warnings.warn('PyClassmember is deprecated.',
RemovedInSphinx40Warning)
return super().run()
def needs_arglist(self):
# type: () -> bool
def needs_arglist(self) -> bool:
return self.objtype.endswith('method')
def get_signature_prefix(self, sig):
# type: (str) -> str
def get_signature_prefix(self, sig: str) -> str:
if self.objtype == 'staticmethod':
return 'static '
elif self.objtype == 'classmethod':
return 'classmethod '
return ''
def get_index_text(self, modname, name_cls):
# type: (str, Tuple[str, str]) -> str
def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str:
name, cls = name_cls
add_modules = self.env.config.add_module_names
if self.objtype == 'method':
@ -584,15 +552,13 @@ class PyMethod(PyObject):
'staticmethod': directives.flag,
})
def needs_arglist(self):
# type: () -> bool
def needs_arglist(self) -> bool:
if 'property' in self.options:
return False
else:
return True
def get_signature_prefix(self, sig):
# type: (str) -> str
def get_signature_prefix(self, sig: str) -> str:
prefix = []
if 'abstractmethod' in self.options:
prefix.append('abstract')
@ -610,8 +576,7 @@ class PyMethod(PyObject):
else:
return ''
def get_index_text(self, modname, name_cls):
# type: (str, Tuple[str, str]) -> str
def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str:
name, cls = name_cls
try:
clsname, methname = name.rsplit('.', 1)
@ -638,8 +603,7 @@ class PyClassMethod(PyMethod):
option_spec = PyObject.option_spec.copy()
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
self.name = 'py:method'
self.options['classmethod'] = True
@ -651,8 +615,7 @@ class PyStaticMethod(PyMethod):
option_spec = PyObject.option_spec.copy()
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
self.name = 'py:method'
self.options['staticmethod'] = True
@ -662,8 +625,7 @@ class PyStaticMethod(PyMethod):
class PyAttribute(PyObject):
"""Description of an attribute."""
def get_index_text(self, modname, name_cls):
# type: (str, Tuple[str, str]) -> str
def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str:
name, cls = name_cls
try:
clsname, attrname = name.rsplit('.', 1)
@ -682,14 +644,12 @@ class PyDecoratorMixin:
"""
Mixin for decorator directives.
"""
def handle_signature(self, sig, signode):
# type: (str, addnodes.desc_signature) -> Tuple[str, str]
def handle_signature(self, sig: str, signode: desc_signature) -> Tuple[str, str]:
ret = super().handle_signature(sig, signode) # type: ignore
signode.insert(0, addnodes.desc_addname('@', '@'))
return ret
def needs_arglist(self):
# type: () -> bool
def needs_arglist(self) -> bool:
return False
@ -697,8 +657,7 @@ class PyDecoratorFunction(PyDecoratorMixin, PyModulelevel):
"""
Directive to mark functions meant to be used as decorators.
"""
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
# a decorator function is a function after all
self.name = 'py:function'
return super().run()
@ -708,8 +667,7 @@ class PyDecoratorMethod(PyDecoratorMixin, PyClassmember):
"""
Directive to mark methods meant to be used as decorators.
"""
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
self.name = 'py:method'
return super().run()
@ -730,14 +688,13 @@ class PyModule(SphinxDirective):
'deprecated': directives.flag,
}
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
domain = cast(PythonDomain, self.env.get_domain('py'))
modname = self.arguments[0].strip()
noindex = 'noindex' in self.options
self.env.ref_context['py:module'] = modname
ret = [] # type: List[nodes.Node]
ret = [] # type: List[Node]
if not noindex:
# note module to the domain
domain.note_module(modname,
@ -771,8 +728,7 @@ class PyCurrentModule(SphinxDirective):
final_argument_whitespace = False
option_spec = {} # type: Dict
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
modname = self.arguments[0].strip()
if modname == 'None':
self.env.ref_context.pop('py:module', None)
@ -782,8 +738,8 @@ class PyCurrentModule(SphinxDirective):
class PyXRefRole(XRefRole):
def process_link(self, env, refnode, has_explicit_title, title, target):
# type: (BuildEnvironment, nodes.Element, bool, str, str) -> Tuple[str, str]
def process_link(self, env: BuildEnvironment, refnode: Element,
has_explicit_title: bool, title: str, target: str) -> Tuple[str, str]:
refnode['py:module'] = env.ref_context.get('py:module')
refnode['py:class'] = env.ref_context.get('py:class')
if not has_explicit_title:
@ -813,8 +769,8 @@ class PythonModuleIndex(Index):
localname = _('Python Module Index')
shortname = _('modules')
def generate(self, docnames=None):
# type: (Iterable[str]) -> Tuple[List[Tuple[str, List[IndexEntry]]], bool]
def generate(self, docnames: Iterable[str] = None
) -> Tuple[List[Tuple[str, List[IndexEntry]]], bool]:
content = {} # type: Dict[str, List[IndexEntry]]
# list of prefixes to ignore
ignores = None # type: List[str]
@ -928,12 +884,10 @@ class PythonDomain(Domain):
]
@property
def objects(self):
# type: () -> Dict[str, Tuple[str, str]]
def objects(self) -> Dict[str, Tuple[str, str]]:
return self.data.setdefault('objects', {}) # fullname -> docname, objtype
def note_object(self, name, objtype, location=None):
# type: (str, str, Any) -> None
def note_object(self, name: str, objtype: str, location: Any = None) -> None:
"""Note a python object for cross reference.
.. versionadded:: 2.1
@ -946,20 +900,17 @@ class PythonDomain(Domain):
self.objects[name] = (self.env.docname, objtype)
@property
def modules(self):
# type: () -> Dict[str, Tuple[str, str, str, bool]]
def modules(self) -> Dict[str, Tuple[str, str, str, bool]]:
return self.data.setdefault('modules', {}) # modname -> docname, synopsis, platform, deprecated # NOQA
def note_module(self, name, synopsis, platform, deprecated):
# type: (str, str, str, bool) -> None
def note_module(self, name: str, synopsis: str, platform: str, deprecated: bool) -> None:
"""Note a python module for cross reference.
.. versionadded:: 2.1
"""
self.modules[name] = (self.env.docname, synopsis, platform, deprecated)
def clear_doc(self, docname):
# type: (str) -> None
def clear_doc(self, docname: str) -> None:
for fullname, (fn, _l) in list(self.objects.items()):
if fn == docname:
del self.objects[fullname]
@ -967,8 +918,7 @@ class PythonDomain(Domain):
if fn == docname:
del self.modules[modname]
def merge_domaindata(self, docnames, otherdata):
# type: (List[str], Dict) -> None
def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
# XXX check duplicates?
for fullname, (fn, objtype) in otherdata['objects'].items():
if fn in docnames:
@ -977,8 +927,8 @@ class PythonDomain(Domain):
if data[0] in docnames:
self.modules[modname] = data
def find_obj(self, env, modname, classname, name, type, searchmode=0):
# type: (BuildEnvironment, str, str, str, str, int) -> List[Tuple[str, Any]]
def find_obj(self, env: BuildEnvironment, modname: str, classname: str,
name: str, type: str, searchmode: int = 0) -> List[Tuple[str, Any]]:
"""Find a Python object for "name", perhaps using the given module
and/or classname. Returns a list of (name, object entry) tuples.
"""
@ -1040,9 +990,9 @@ class PythonDomain(Domain):
matches.append((newname, self.objects[newname]))
return matches
def resolve_xref(self, env, fromdocname, builder,
type, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
type: str, target: str, node: pending_xref, contnode: Element
) -> Element:
modname = node.get('py:module')
clsname = node.get('py:class')
searchmode = node.hasattr('refspecific') and 1 or 0
@ -1061,12 +1011,12 @@ class PythonDomain(Domain):
else:
return make_refnode(builder, fromdocname, obj[0], name, contnode, name)
def resolve_any_xref(self, env, fromdocname, builder, target,
node, contnode):
# type: (BuildEnvironment, str, Builder, str, addnodes.pending_xref, nodes.Element) -> List[Tuple[str, nodes.Element]] # NOQA
def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
target: str, node: pending_xref, contnode: Element
) -> List[Tuple[str, Element]]:
modname = node.get('py:module')
clsname = node.get('py:class')
results = [] # type: List[Tuple[str, nodes.Element]]
results = [] # type: List[Tuple[str, Element]]
# always search in "refspecific" mode with the :any: role
matches = self.find_obj(env, modname, clsname, target, None, 1)
@ -1081,8 +1031,8 @@ class PythonDomain(Domain):
contnode, name)))
return results
def _make_module_refnode(self, builder, fromdocname, name, contnode):
# type: (Builder, str, str, nodes.Node) -> nodes.Element
def _make_module_refnode(self, builder: Builder, fromdocname: str, name: str,
contnode: Node) -> Element:
# get additional info for modules
docname, synopsis, platform, deprecated = self.modules[name]
title = name
@ -1095,16 +1045,14 @@ class PythonDomain(Domain):
return make_refnode(builder, fromdocname, docname,
'module-' + name, contnode, title)
def get_objects(self):
# type: () -> Iterator[Tuple[str, str, str, str, str, int]]
def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]:
for modname, info in self.modules.items():
yield (modname, modname, 'module', info[0], 'module-' + modname, 0)
for refname, (docname, type) in self.objects.items():
if type != 'module': # modules are already handled
yield (refname, refname, type, docname, refname, 1)
def get_full_qualified_name(self, node):
# type: (nodes.Element) -> str
def get_full_qualified_name(self, node: Element) -> str:
modname = node.get('py:module')
clsname = node.get('py:class')
target = node.get('reftarget')
@ -1114,8 +1062,7 @@ class PythonDomain(Domain):
return '.'.join(filter(None, [modname, clsname, target]))
def setup(app):
# type: (Sphinx) -> Dict[str, Any]
def setup(app: Sphinx) -> Dict[str, Any]:
app.add_domain(PythonDomain)
return {

View File

@ -9,26 +9,24 @@
"""
import re
from typing import Any, Dict, Iterator, List, Tuple
from typing import cast
from docutils.nodes import Element
from docutils.parsers.rst import directives
from sphinx import addnodes
from sphinx.addnodes import desc_signature, pending_xref
from sphinx.application import Sphinx
from sphinx.builders import Builder
from sphinx.directives import ObjectDescription
from sphinx.domains import Domain, ObjType
from sphinx.environment import BuildEnvironment
from sphinx.locale import _, __
from sphinx.roles import XRefRole
from sphinx.util import logging
from sphinx.util.nodes import make_refnode
if False:
# For type annotation
from typing import Any, Dict, Iterator, List, Tuple # NOQA
from docutils import nodes # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.builders import Builder # NOQA
from sphinx.environment import BuildEnvironment # NOQA
logger = logging.getLogger(__name__)
@ -40,8 +38,7 @@ class ReSTMarkup(ObjectDescription):
Description of generic reST markup.
"""
def add_target_and_index(self, name, sig, signode):
# type: (str, str, addnodes.desc_signature) -> None
def add_target_and_index(self, name: str, sig: str, signode: desc_signature) -> None:
targetname = self.objtype + '-' + name
if targetname not in self.state.document.ids:
signode['names'].append(targetname)
@ -57,13 +54,11 @@ class ReSTMarkup(ObjectDescription):
self.indexnode['entries'].append(('single', indextext,
targetname, '', None))
def get_index_text(self, objectname, name):
# type: (str, str) -> str
def get_index_text(self, objectname: str, name: str) -> str:
return ''
def parse_directive(d):
# type: (str) -> Tuple[str, str]
def parse_directive(d: str) -> Tuple[str, str]:
"""Parse a directive signature.
Returns (directive, arguments) string tuple. If no arguments are given,
@ -87,8 +82,7 @@ class ReSTDirective(ReSTMarkup):
"""
Description of a reST directive.
"""
def handle_signature(self, sig, signode):
# type: (str, addnodes.desc_signature) -> str
def handle_signature(self, sig: str, signode: desc_signature) -> str:
name, args = parse_directive(sig)
desc_name = '.. %s::' % name
signode += addnodes.desc_name(desc_name, desc_name)
@ -96,18 +90,15 @@ class ReSTDirective(ReSTMarkup):
signode += addnodes.desc_addname(args, args)
return name
def get_index_text(self, objectname, name):
# type: (str, str) -> str
def get_index_text(self, objectname: str, name: str) -> str:
return _('%s (directive)') % name
def before_content(self):
# type: () -> None
def before_content(self) -> None:
if self.names:
directives = self.env.ref_context.setdefault('rst:directives', [])
directives.append(self.names[0])
def after_content(self):
# type: () -> None
def after_content(self) -> None:
directives = self.env.ref_context.setdefault('rst:directives', [])
if directives:
directives.pop()
@ -122,8 +113,7 @@ class ReSTDirectiveOption(ReSTMarkup):
'type': directives.unchanged,
})
def handle_signature(self, sig, signode):
# type: (str, addnodes.desc_signature) -> str
def handle_signature(self, sig: str, signode: desc_signature) -> str:
try:
name, argument = re.split(r'\s*:\s+', sig.strip(), 1)
except ValueError:
@ -137,8 +127,7 @@ class ReSTDirectiveOption(ReSTMarkup):
signode += addnodes.desc_annotation(text, text)
return name
def add_target_and_index(self, name, sig, signode):
# type: (str, str, addnodes.desc_signature) -> None
def add_target_and_index(self, name: str, sig: str, signode: desc_signature) -> None:
directive_name = self.current_directive
targetname = '-'.join([self.objtype, self.current_directive, name])
if targetname not in self.state.document.ids:
@ -162,8 +151,7 @@ class ReSTDirectiveOption(ReSTMarkup):
self.indexnode['entries'].append(('single', text, targetname, '', key))
@property
def current_directive(self):
# type: () -> str
def current_directive(self) -> str:
directives = self.env.ref_context.get('rst:directives')
if directives:
return directives[-1]
@ -175,13 +163,11 @@ class ReSTRole(ReSTMarkup):
"""
Description of a reST role.
"""
def handle_signature(self, sig, signode):
# type: (str, addnodes.desc_signature) -> str
def handle_signature(self, sig: str, signode: desc_signature) -> str:
signode += addnodes.desc_name(':%s:' % sig, ':%s:' % sig)
return sig
def get_index_text(self, objectname, name):
# type: (str, str) -> str
def get_index_text(self, objectname: str, name: str) -> str:
return _('%s (role)') % name
@ -209,12 +195,10 @@ class ReSTDomain(Domain):
} # type: Dict[str, Dict[Tuple[str, str], str]]
@property
def objects(self):
# type: () -> Dict[Tuple[str, str], str]
def objects(self) -> Dict[Tuple[str, str], str]:
return self.data.setdefault('objects', {}) # (objtype, fullname) -> docname
def note_object(self, objtype, name, location=None):
# type: (str, str, Any) -> None
def note_object(self, objtype: str, name: str, location: Any = None) -> None:
if (objtype, name) in self.objects:
docname = self.objects[objtype, name]
logger.warning(__('duplicate description of %s %s, other instance in %s') %
@ -222,21 +206,20 @@ class ReSTDomain(Domain):
self.objects[objtype, name] = self.env.docname
def clear_doc(self, docname):
# type: (str) -> None
def clear_doc(self, docname: str) -> None:
for (typ, name), doc in list(self.objects.items()):
if doc == docname:
del self.objects[typ, name]
def merge_domaindata(self, docnames, otherdata):
# type: (List[str], Dict) -> None
def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
# XXX check duplicates
for (typ, name), doc in otherdata['objects'].items():
if doc in docnames:
self.objects[typ, name] = doc
def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
typ: str, target: str, node: pending_xref, contnode: Element
) -> Element:
objtypes = self.objtypes_for_role(typ)
for objtype in objtypes:
todocname = self.objects.get((objtype, target))
@ -246,9 +229,10 @@ class ReSTDomain(Domain):
contnode, target + ' ' + objtype)
return None
def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, addnodes.pending_xref, nodes.Element) -> List[Tuple[str, nodes.Element]] # NOQA
results = [] # type: List[Tuple[str, nodes.Element]]
def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
target: str, node: pending_xref, contnode: Element
) -> List[Tuple[str, Element]]:
results = [] # type: List[Tuple[str, Element]]
for objtype in self.object_types:
todocname = self.objects.get((objtype, target))
if todocname:
@ -258,14 +242,12 @@ class ReSTDomain(Domain):
contnode, target + ' ' + objtype)))
return results
def get_objects(self):
# type: () -> Iterator[Tuple[str, str, str, str, str, int]]
def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]:
for (typ, name), docname in self.data['objects'].items():
yield name, name, typ, docname, typ + '-' + name, 1
def setup(app):
# type: (Sphinx) -> Dict[str, Any]
def setup(app: Sphinx) -> Dict[str, Any]:
app.add_domain(ReSTDomain)
return {

View File

@ -12,13 +12,16 @@ import re
import unicodedata
import warnings
from copy import copy
from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Tuple, Type, Union
from typing import cast
from docutils import nodes
from docutils.parsers.rst import directives
from docutils.nodes import Element, Node, system_message
from docutils.parsers.rst import Directive, directives
from docutils.statemachine import StringList
from sphinx import addnodes
from sphinx.addnodes import desc_signature, pending_xref
from sphinx.deprecation import RemovedInSphinx40Warning
from sphinx.directives import ObjectDescription
from sphinx.domains import Domain, ObjType
@ -27,15 +30,13 @@ from sphinx.roles import XRefRole
from sphinx.util import ws_re, logging, docname_join
from sphinx.util.docutils import SphinxDirective
from sphinx.util.nodes import clean_astext, make_refnode
from sphinx.util.typing import RoleFunction
if False:
# For type annotation
from typing import Any, Callable, Dict, Iterable, Iterator, List, Tuple, Type, Union # NOQA
from docutils.parsers.rst import Directive # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.builders import Builder # NOQA
from sphinx.environment import BuildEnvironment # NOQA
from sphinx.util.typing import RoleFunction # NOQA
from sphinx.application import Sphinx
from sphinx.builders import Builder
from sphinx.environment import BuildEnvironment
logger = logging.getLogger(__name__)
@ -51,10 +52,9 @@ class GenericObject(ObjectDescription):
A generic x-ref directive registered with Sphinx.add_object_type().
"""
indextemplate = ''
parse_node = None # type: Callable[[GenericObject, BuildEnvironment, str, addnodes.desc_signature], str] # NOQA
parse_node = None # type: Callable[[GenericObject, BuildEnvironment, str, desc_signature], str] # NOQA
def handle_signature(self, sig, signode):
# type: (str, addnodes.desc_signature) -> str
def handle_signature(self, sig: str, signode: desc_signature) -> str:
if self.parse_node:
name = self.parse_node(self.env, sig, signode)
else:
@ -64,8 +64,7 @@ class GenericObject(ObjectDescription):
name = ws_re.sub('', sig)
return name
def add_target_and_index(self, name, sig, signode):
# type: (str, str, addnodes.desc_signature) -> None
def add_target_and_index(self, name: str, sig: str, signode: desc_signature) -> None:
targetname = '%s-%s' % (self.objtype, name)
signode['ids'].append(targetname)
self.state.document.note_explicit_target(signode)
@ -93,8 +92,8 @@ class EnvVarXRefRole(XRefRole):
Cross-referencing role for environment variables (adds an index entry).
"""
def result_nodes(self, document, env, node, is_ref):
# type: (nodes.document, BuildEnvironment, nodes.Element, bool) -> Tuple[List[nodes.Node], List[nodes.system_message]] # NOQA
def result_nodes(self, document: nodes.document, env: "BuildEnvironment", node: Element,
is_ref: bool) -> Tuple[List[Node], List[system_message]]:
if not is_ref:
return [node], []
varname = node['reftarget']
@ -121,8 +120,7 @@ class Target(SphinxDirective):
final_argument_whitespace = True
option_spec = {} # type: Dict
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
# normalize whitespace in fullname like XRefRole does
fullname = ws_re.sub(' ', self.arguments[0].strip())
targetname = '%s-%s' % (self.name, fullname)
@ -154,8 +152,7 @@ class Cmdoption(ObjectDescription):
Description of a command-line option (.. option).
"""
def handle_signature(self, sig, signode):
# type: (str, addnodes.desc_signature) -> str
def handle_signature(self, sig: str, signode: desc_signature) -> str:
"""Transform an option description into RST nodes."""
count = 0
firstname = ''
@ -183,8 +180,7 @@ class Cmdoption(ObjectDescription):
raise ValueError
return firstname
def add_target_and_index(self, firstname, sig, signode):
# type: (str, str, addnodes.desc_signature) -> None
def add_target_and_index(self, firstname: str, sig: str, signode: desc_signature) -> None:
currprogram = self.env.ref_context.get('std:program')
for optname in signode.get('allnames', []):
targetname = optname.replace('/', '-')
@ -220,8 +216,7 @@ class Program(SphinxDirective):
final_argument_whitespace = True
option_spec = {} # type: Dict
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
program = ws_re.sub('-', self.arguments[0].strip())
if program == 'None':
self.env.ref_context.pop('std:program', None)
@ -231,21 +226,20 @@ class Program(SphinxDirective):
class OptionXRefRole(XRefRole):
def process_link(self, env, refnode, has_explicit_title, title, target):
# type: (BuildEnvironment, nodes.Element, bool, str, str) -> Tuple[str, str]
def process_link(self, env: "BuildEnvironment", refnode: Element, has_explicit_title: bool,
title: str, target: str) -> Tuple[str, str]:
refnode['std:program'] = env.ref_context.get('std:program')
return title, target
def split_term_classifiers(line):
# type: (str) -> List[Union[str, None]]
def split_term_classifiers(line: str) -> List[Optional[str]]:
# split line into a term and classifiers. if no classifier, None is used..
parts = re.split(' +: +', line) + [None]
return parts
def make_glossary_term(env, textnodes, index_key, source, lineno, new_id=None):
# type: (BuildEnvironment, Iterable[nodes.Node], str, str, int, str) -> nodes.term
def make_glossary_term(env: "BuildEnvironment", textnodes: Iterable[Node], index_key: str,
source: str, lineno: int, new_id: str = None) -> nodes.term:
# get a text-only representation of the term and register it
# as a cross-reference target
term = nodes.term('', '', *textnodes)
@ -291,8 +285,7 @@ class Glossary(SphinxDirective):
'sorted': directives.flag,
}
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
node = addnodes.glossary()
node.document = self.state.document
@ -398,16 +391,15 @@ class Glossary(SphinxDirective):
return messages + [node]
def token_xrefs(text):
# type: (str) -> List[nodes.Node]
def token_xrefs(text: str) -> List[Node]:
retnodes = [] # type: List[nodes.Node]
pos = 0
for m in token_re.finditer(text):
if m.start() > pos:
txt = text[pos:m.start()]
retnodes.append(nodes.Text(txt, txt))
refnode = addnodes.pending_xref(
m.group(1), reftype='token', refdomain='std', reftarget=m.group(1))
refnode = pending_xref(m.group(1), reftype='token', refdomain='std',
reftarget=m.group(1))
refnode += nodes.literal(m.group(1), m.group(1), classes=['xref'])
retnodes.append(refnode)
pos = m.end()
@ -427,8 +419,7 @@ class ProductionList(SphinxDirective):
final_argument_whitespace = True
option_spec = {} # type: Dict
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
domain = cast(StandardDomain, self.env.get_domain('std'))
node = addnodes.productionlist() # type: nodes.Element
i = 0
@ -533,8 +524,7 @@ class StandardDomain(Domain):
nodes.container: ('code-block', None),
} # type: Dict[Type[nodes.Node], Tuple[str, Callable]]
def __init__(self, env):
# type: (BuildEnvironment) -> None
def __init__(self, env: "BuildEnvironment") -> None:
super().__init__(env)
# set up enumerable nodes
@ -543,27 +533,22 @@ class StandardDomain(Domain):
self.enumerable_nodes[node] = settings
@property
def objects(self):
# type: () -> Dict[Tuple[str, str], Tuple[str, str]]
def objects(self) -> Dict[Tuple[str, str], Tuple[str, str]]:
return self.data.setdefault('objects', {}) # (objtype, name) -> docname, labelid
@property
def progoptions(self):
# type: () -> Dict[Tuple[str, str], Tuple[str, str]]
def progoptions(self) -> Dict[Tuple[str, str], Tuple[str, str]]:
return self.data.setdefault('progoptions', {}) # (program, name) -> docname, labelid
@property
def labels(self):
# type: () -> Dict[str, Tuple[str, str, str]]
def labels(self) -> Dict[str, Tuple[str, str, str]]:
return self.data.setdefault('labels', {}) # labelname -> docname, labelid, sectionname
@property
def anonlabels(self):
# type: () -> Dict[str, Tuple[str, str]]
def anonlabels(self) -> Dict[str, Tuple[str, str]]:
return self.data.setdefault('anonlabels', {}) # labelname -> docname, labelid
def clear_doc(self, docname):
# type: (str) -> None
def clear_doc(self, docname: str) -> None:
key = None # type: Any
for key, (fn, _l) in list(self.progoptions.items()):
if fn == docname:
@ -578,8 +563,7 @@ class StandardDomain(Domain):
if fn == docname:
del self.anonlabels[key]
def merge_domaindata(self, docnames, otherdata):
# type: (List[str], Dict) -> None
def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
# XXX duplicates?
for key, data in otherdata['progoptions'].items():
if data[0] in docnames:
@ -594,8 +578,7 @@ class StandardDomain(Domain):
if data[0] in docnames:
self.anonlabels[key] = data
def process_doc(self, env, docname, document):
# type: (BuildEnvironment, str, nodes.document) -> None
def process_doc(self, env: "BuildEnvironment", docname: str, document: nodes.document) -> None: # NOQA
for name, explicit in document.nametypes.items():
if not explicit:
continue
@ -636,17 +619,15 @@ class StandardDomain(Domain):
continue
self.labels[name] = docname, labelid, sectname
def add_object(self, objtype, name, docname, labelid):
# type: (str, str, str, str) -> None
def add_object(self, objtype: str, name: str, docname: str, labelid: str) -> None:
self.objects[objtype, name] = (docname, labelid)
def add_program_option(self, program, name, docname, labelid):
# type: (str, str, str, str) -> None
def add_program_option(self, program: str, name: str, docname: str, labelid: str) -> None:
self.progoptions[program, name] = (docname, labelid)
def build_reference_node(self, fromdocname, builder, docname, labelid,
sectname, rolename, **options):
# type: (str, Builder, str, str, str, str, Any) -> nodes.Element
def build_reference_node(self, fromdocname: str, builder: "Builder", docname: str,
labelid: str, sectname: str, rolename: str, **options
) -> Element:
nodeclass = options.pop('nodeclass', nodes.reference)
newnode = nodeclass('', '', internal=True, **options)
innernode = nodes.inline(sectname, sectname)
@ -659,7 +640,7 @@ class StandardDomain(Domain):
# set more info in contnode; in case the
# get_relative_uri call raises NoUri,
# the builder will then have to resolve these
contnode = addnodes.pending_xref('')
contnode = pending_xref('')
contnode['refdocname'] = docname
contnode['refsectname'] = sectname
newnode['refuri'] = builder.get_relative_uri(
@ -669,8 +650,8 @@ class StandardDomain(Domain):
newnode.append(innernode)
return newnode
def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
def resolve_xref(self, env: "BuildEnvironment", fromdocname: str, builder: "Builder",
typ: str, target: str, node: pending_xref, contnode: Element) -> Element:
if typ == 'ref':
resolver = self._resolve_ref_xref
elif typ == 'numref':
@ -691,8 +672,9 @@ class StandardDomain(Domain):
return resolver(env, fromdocname, builder, typ, target, node, contnode)
def _resolve_ref_xref(self, env, fromdocname, builder, typ, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
def _resolve_ref_xref(self, env: "BuildEnvironment", fromdocname: str,
builder: "Builder", typ: str, target: str, node: pending_xref,
contnode: Element) -> Element:
if node['refexplicit']:
# reference to anonymous label; the reference uses
# the supplied link caption
@ -708,8 +690,9 @@ class StandardDomain(Domain):
return self.build_reference_node(fromdocname, builder,
docname, labelid, sectname, 'ref')
def _resolve_numref_xref(self, env, fromdocname, builder, typ, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
def _resolve_numref_xref(self, env: "BuildEnvironment", fromdocname: str,
builder: "Builder", typ: str, target: str,
node: pending_xref, contnode: Element) -> Element:
if target in self.labels:
docname, labelid, figname = self.labels.get(target, ('', '', ''))
else:
@ -769,8 +752,9 @@ class StandardDomain(Domain):
nodeclass=addnodes.number_reference,
title=title)
def _resolve_keyword_xref(self, env, fromdocname, builder, typ, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
def _resolve_keyword_xref(self, env: "BuildEnvironment", fromdocname: str,
builder: "Builder", typ: str, target: str,
node: pending_xref, contnode: Element) -> Element:
# keywords are oddballs: they are referenced by named labels
docname, labelid, _ = self.labels.get(target, ('', '', ''))
if not docname:
@ -778,8 +762,9 @@ class StandardDomain(Domain):
return make_refnode(builder, fromdocname, docname,
labelid, contnode)
def _resolve_doc_xref(self, env, fromdocname, builder, typ, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
def _resolve_doc_xref(self, env: "BuildEnvironment", fromdocname: str,
builder: "Builder", typ: str, target: str,
node: pending_xref, contnode: Element) -> Element:
# directly reference to document by source name; can be absolute or relative
refdoc = node.get('refdoc', fromdocname)
docname = docname_join(refdoc, node['reftarget'])
@ -794,8 +779,9 @@ class StandardDomain(Domain):
innernode = nodes.inline(caption, caption, classes=['doc'])
return make_refnode(builder, fromdocname, docname, None, innernode)
def _resolve_option_xref(self, env, fromdocname, builder, typ, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
def _resolve_option_xref(self, env: "BuildEnvironment", fromdocname: str,
builder: "Builder", typ: str, target: str,
node: pending_xref, contnode: Element) -> Element:
progname = node.get('std:program')
target = target.strip()
docname, labelid = self.progoptions.get((progname, target), ('', ''))
@ -815,8 +801,9 @@ class StandardDomain(Domain):
return make_refnode(builder, fromdocname, docname,
labelid, contnode)
def _resolve_obj_xref(self, env, fromdocname, builder, typ, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
def _resolve_obj_xref(self, env: "BuildEnvironment", fromdocname: str,
builder: "Builder", typ: str, target: str,
node: pending_xref, contnode: Element) -> Element:
objtypes = self.objtypes_for_role(typ) or []
for objtype in objtypes:
if (objtype, target) in self.objects:
@ -829,8 +816,9 @@ class StandardDomain(Domain):
return make_refnode(builder, fromdocname, docname,
labelid, contnode)
def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, addnodes.pending_xref, nodes.Element) -> List[Tuple[str, nodes.Element]] # NOQA
def resolve_any_xref(self, env: "BuildEnvironment", fromdocname: str,
builder: "Builder", target: str, node: pending_xref,
contnode: Element) -> List[Tuple[str, Element]]:
results = [] # type: List[Tuple[str, nodes.Element]]
ltarget = target.lower() # :ref: lowercases its target automatically
for role in ('ref', 'option'): # do not try "keyword"
@ -851,8 +839,7 @@ class StandardDomain(Domain):
labelid, contnode)))
return results
def get_objects(self):
# type: () -> Iterator[Tuple[str, str, str, str, str, int]]
def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]:
# handle the special 'doc' reference here
for doc in self.env.all_docs:
yield (doc, clean_astext(self.env.titles[doc]), 'doc', doc, '', -1)
@ -873,17 +860,14 @@ class StandardDomain(Domain):
if name not in non_anon_labels:
yield (name, name, 'label', docname, labelid, -1)
def get_type_name(self, type, primary=False):
# type: (ObjType, bool) -> str
def get_type_name(self, type: ObjType, primary: bool = False) -> str:
# never prepend "Default"
return type.lname
def is_enumerable_node(self, node):
# type: (nodes.Node) -> bool
def is_enumerable_node(self, node: Node) -> bool:
return node.__class__ in self.enumerable_nodes
def get_numfig_title(self, node):
# type: (nodes.Node) -> str
def get_numfig_title(self, node: Node) -> str:
"""Get the title of enumerable nodes to refer them using its title"""
if self.is_enumerable_node(node):
elem = cast(nodes.Element, node)
@ -897,11 +881,9 @@ class StandardDomain(Domain):
return None
def get_enumerable_node_type(self, node):
# type: (nodes.Node) -> str
def get_enumerable_node_type(self, node: Node) -> str:
"""Get type of enumerable nodes."""
def has_child(node, cls):
# type: (nodes.Element, Type) -> bool
def has_child(node: Element, cls: Type) -> bool:
return any(isinstance(child, cls) for child in node)
if isinstance(node, nodes.section):
@ -915,8 +897,8 @@ class StandardDomain(Domain):
figtype, _ = self.enumerable_nodes.get(node.__class__, (None, None))
return figtype
def get_fignumber(self, env, builder, figtype, docname, target_node):
# type: (BuildEnvironment, Builder, str, str, nodes.Element) -> Tuple[int, ...]
def get_fignumber(self, env: "BuildEnvironment", builder: "Builder",
figtype: str, docname: str, target_node: Element) -> Tuple[int, ...]:
if figtype == 'section':
if builder.name == 'latex':
return tuple()
@ -938,8 +920,7 @@ class StandardDomain(Domain):
# Maybe it is defined in orphaned document.
raise ValueError
def get_full_qualified_name(self, node):
# type: (nodes.Element) -> str
def get_full_qualified_name(self, node: Element) -> str:
if node.get('reftype') == 'option':
progname = node.get('std:program')
command = ws_re.split(node.get('reftarget'))
@ -953,24 +934,20 @@ class StandardDomain(Domain):
else:
return None
def note_citations(self, env, docname, document):
# type: (BuildEnvironment, str, nodes.document) -> None
def note_citations(self, env: "BuildEnvironment", docname: str, document: nodes.document) -> None: # NOQA
warnings.warn('StandardDomain.note_citations() is deprecated.',
RemovedInSphinx40Warning)
def note_citation_refs(self, env, docname, document):
# type: (BuildEnvironment, str, nodes.document) -> None
def note_citation_refs(self, env: "BuildEnvironment", docname: str, document: nodes.document) -> None: # NOQA
warnings.warn('StandardDomain.note_citation_refs() is deprecated.',
RemovedInSphinx40Warning)
def note_labels(self, env, docname, document):
# type: (BuildEnvironment, str, nodes.document) -> None
def note_labels(self, env: "BuildEnvironment", docname: str, document: nodes.document) -> None: # NOQA
warnings.warn('StandardDomain.note_labels() is deprecated.',
RemovedInSphinx40Warning)
def setup(app):
# type: (Sphinx) -> Dict[str, Any]
def setup(app: "Sphinx") -> Dict[str, Any]:
app.add_domain(StandardDomain)
return {

View File

@ -270,7 +270,7 @@ def format_date(format: str, date: datetime = None, language: str = None) -> str
if source_date_epoch is not None:
date = datetime.utcfromtimestamp(float(source_date_epoch))
else:
date = datetime.now()
date = datetime.utcnow()
result = []
tokens = date_format_re.split(format)