Merge pull request #6459 from tk0miya/refactor_type_annotation_directives

Migrate to py3 style type annotation: sphinx.directives
This commit is contained in:
Takeshi KOMIYA 2019-06-09 01:28:03 +09:00 committed by GitHub
commit c80e8cfdd9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 119 deletions

View File

@ -9,23 +9,24 @@
"""
import re
from typing import List, cast
from typing import Any, Dict, List, Tuple
from typing import cast
from docutils import nodes
from docutils.nodes import Node
from docutils.parsers.rst import directives, roles
from sphinx import addnodes
from sphinx.addnodes import desc_signature
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
from sphinx.util import docutils
from sphinx.util.docfields import DocFieldTransformer, TypedField
from sphinx.util.docfields import DocFieldTransformer, Field, TypedField
from sphinx.util.docutils import SphinxDirective
from sphinx.util.typing import DirectiveOption
if False:
# For type annotation
from typing import Any, Dict, Tuple # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.util.docfields import Field # NOQA
from sphinx.util.typing import DirectiveOption # NOQA
from sphinx.application import Sphinx
# RE to strip backslash escapes
@ -70,8 +71,7 @@ class ObjectDescription(SphinxDirective):
# Warning: this might be removed in future version. Don't touch this from extensions.
_doc_field_type_map = {} # type: Dict[str, Tuple[Field, bool]]
def get_field_type_map(self):
# type: () -> Dict[str, Tuple[Field, bool]]
def get_field_type_map(self) -> Dict[str, Tuple[Field, bool]]:
if self._doc_field_type_map == {}:
for field in self.doc_field_types:
for name in field.names:
@ -84,8 +84,7 @@ class ObjectDescription(SphinxDirective):
return self._doc_field_type_map
def get_signatures(self):
# type: () -> List[str]
def get_signatures(self) -> List[str]:
"""
Retrieve the signatures to document from the directive arguments. By
default, signatures are given as arguments, one per line.
@ -96,8 +95,7 @@ class ObjectDescription(SphinxDirective):
# remove backslashes to support (dummy) escapes; helps Vim highlighting
return [strip_backslash_re.sub(r'\1', line.strip()) for line in lines]
def handle_signature(self, sig, signode):
# type: (str, addnodes.desc_signature) -> Any
def handle_signature(self, sig: str, signode: desc_signature) -> Any:
"""
Parse the signature *sig* into individual nodes and append them to
*signode*. If ValueError is raised, parsing is aborted and the whole
@ -109,8 +107,7 @@ class ObjectDescription(SphinxDirective):
"""
raise ValueError
def add_target_and_index(self, name, sig, signode):
# type: (Any, str, addnodes.desc_signature) -> None
def add_target_and_index(self, name: Any, sig: str, signode: desc_signature) -> None:
"""
Add cross-reference IDs and entries to self.indexnode, if applicable.
@ -118,24 +115,21 @@ class ObjectDescription(SphinxDirective):
"""
return # do nothing by default
def before_content(self):
# type: () -> None
def before_content(self) -> None:
"""
Called before parsing content. Used to set information about the current
directive context on the build environment.
"""
pass
def after_content(self):
# type: () -> None
def after_content(self) -> None:
"""
Called after parsing content. Used to reset information about the
current directive context on the build environment.
"""
pass
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
"""
Main directive entry function, called by docutils upon encountering the
directive.
@ -212,8 +206,7 @@ class DefaultRole(SphinxDirective):
optional_arguments = 1
final_argument_whitespace = False
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
if not self.arguments:
docutils.unregister_role('')
return []
@ -244,8 +237,7 @@ class DefaultDomain(SphinxDirective):
final_argument_whitespace = False
option_spec = {} # type: Dict
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
domain_name = self.arguments[0].lower()
# if domain_name not in env.domains:
# # try searching by label
@ -294,8 +286,7 @@ deprecated_alias('sphinx.directives',
DescDirective = ObjectDescription
def setup(app):
# type: (Sphinx) -> Dict[str, Any]
def setup(app: "Sphinx") -> Dict[str, Any]:
directives.register_directive('default-role', DefaultRole)
directives.register_directive('default-domain', DefaultDomain)
directives.register_directive('describe', ObjectDescription)

View File

@ -9,12 +9,15 @@
import sys
import warnings
from difflib import unified_diff
from typing import Any, Dict, List, Tuple
from docutils import nodes
from docutils.nodes import Element, Node
from docutils.parsers.rst import directives
from docutils.statemachine import StringList
from sphinx import addnodes
from sphinx.config import Config
from sphinx.deprecation import RemovedInSphinx40Warning
from sphinx.locale import __
from sphinx.util import logging
@ -23,9 +26,7 @@ from sphinx.util.docutils import SphinxDirective
if False:
# For type annotation
from typing import Any, Dict, List, Tuple # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.config import Config # NOQA
from sphinx.application import Sphinx
logger = logging.getLogger(__name__)
@ -45,8 +46,7 @@ class Highlight(SphinxDirective):
'linenothreshold': directives.positive_int,
}
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
language = self.arguments[0].strip()
linenothreshold = self.options.get('linenothreshold', sys.maxsize)
force = 'force' in self.options
@ -60,16 +60,14 @@ class Highlight(SphinxDirective):
class HighlightLang(Highlight):
"""highlightlang directive (deprecated)"""
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
warnings.warn('highlightlang directive is deprecated. '
'Please use highlight directive instead.',
RemovedInSphinx40Warning, stacklevel=2)
return super().run()
def dedent_lines(lines, dedent, location=None):
# type: (List[str], int, Tuple[str, int]) -> List[str]
def dedent_lines(lines: List[str], dedent: int, location: Tuple[str, int] = None) -> List[str]:
if not dedent:
return lines
@ -86,8 +84,7 @@ def dedent_lines(lines, dedent, location=None):
return new_lines
def container_wrapper(directive, literal_node, caption):
# type: (SphinxDirective, nodes.Node, str) -> nodes.container
def container_wrapper(directive: SphinxDirective, literal_node: Node, caption: str) -> nodes.container: # NOQA
container_node = nodes.container('', literal_block=True,
classes=['literal-block-wrapper'])
parsed = nodes.Element()
@ -129,8 +126,7 @@ class CodeBlock(SphinxDirective):
'name': directives.unchanged,
}
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
document = self.state.document
code = '\n'.join(self.content)
location = self.state_machine.get_source_and_line(self.lineno)
@ -157,7 +153,7 @@ class CodeBlock(SphinxDirective):
lines = dedent_lines(lines, self.options['dedent'], location=location)
code = '\n'.join(lines)
literal = nodes.literal_block(code, code) # type: nodes.Element
literal = nodes.literal_block(code, code) # type: Element
if 'linenos' in self.options or 'lineno-start' in self.options:
literal['linenos'] = True
literal['classes'] += self.options.get('class', [])
@ -209,8 +205,7 @@ class LiteralIncludeReader:
('diff', 'end-at'),
]
def __init__(self, filename, options, config):
# type: (str, Dict, Config) -> None
def __init__(self, filename: str, options: Dict, config: Config) -> None:
self.filename = filename
self.options = options
self.encoding = options.get('encoding', config.source_encoding)
@ -218,15 +213,13 @@ class LiteralIncludeReader:
self.parse_options()
def parse_options(self):
# type: () -> None
def parse_options(self) -> None:
for option1, option2 in self.INVALID_OPTIONS_PAIR:
if option1 in self.options and option2 in self.options:
raise ValueError(__('Cannot use both "%s" and "%s" options') %
(option1, option2))
def read_file(self, filename, location=None):
# type: (str, Tuple[str, int]) -> List[str]
def read_file(self, filename: str, location: Tuple[str, int] = None) -> List[str]:
try:
with open(filename, encoding=self.encoding, errors='strict') as f:
text = f.read()
@ -241,8 +234,7 @@ class LiteralIncludeReader:
'be wrong, try giving an :encoding: option') %
(self.encoding, filename))
def read(self, location=None):
# type: (Tuple[str, int]) -> Tuple[str, int]
def read(self, location: Tuple[str, int] = None) -> Tuple[str, int]:
if 'diff' in self.options:
lines = self.show_diff()
else:
@ -259,16 +251,14 @@ class LiteralIncludeReader:
return ''.join(lines), len(lines)
def show_diff(self, location=None):
# type: (Tuple[str, int]) -> List[str]
def show_diff(self, location: Tuple[str, int] = None) -> List[str]:
new_lines = self.read_file(self.filename)
old_filename = self.options.get('diff')
old_lines = self.read_file(old_filename)
diff = unified_diff(old_lines, new_lines, old_filename, self.filename)
return list(diff)
def pyobject_filter(self, lines, location=None):
# type: (List[str], Tuple[str, int]) -> List[str]
def pyobject_filter(self, lines: List[str], location: Tuple[str, int] = None) -> List[str]:
pyobject = self.options.get('pyobject')
if pyobject:
from sphinx.pycode import ModuleAnalyzer
@ -286,8 +276,7 @@ class LiteralIncludeReader:
return lines
def lines_filter(self, lines, location=None):
# type: (List[str], Tuple[str, int]) -> List[str]
def lines_filter(self, lines: List[str], location: Tuple[str, int] = None) -> List[str]:
linespec = self.options.get('lines')
if linespec:
linelist = parselinenos(linespec, len(lines))
@ -311,8 +300,7 @@ class LiteralIncludeReader:
return lines
def start_filter(self, lines, location=None):
# type: (List[str], Tuple[str, int]) -> List[str]
def start_filter(self, lines: List[str], location: Tuple[str, int] = None) -> List[str]:
if 'start-at' in self.options:
start = self.options.get('start-at')
inclusive = False
@ -343,8 +331,7 @@ class LiteralIncludeReader:
return lines
def end_filter(self, lines, location=None):
# type: (List[str], Tuple[str, int]) -> List[str]
def end_filter(self, lines: List[str], location: Tuple[str, int] = None) -> List[str]:
if 'end-at' in self.options:
end = self.options.get('end-at')
inclusive = True
@ -371,24 +358,21 @@ class LiteralIncludeReader:
return lines
def prepend_filter(self, lines, location=None):
# type: (List[str], Tuple[str, int]) -> List[str]
def prepend_filter(self, lines: List[str], location: Tuple[str, int] = None) -> List[str]:
prepend = self.options.get('prepend')
if prepend:
lines.insert(0, prepend + '\n')
return lines
def append_filter(self, lines, location=None):
# type: (List[str], Tuple[str, int]) -> List[str]
def append_filter(self, lines: List[str], location: Tuple[str, int] = None) -> List[str]:
append = self.options.get('append')
if append:
lines.append(append + '\n')
return lines
def dedent_filter(self, lines, location=None):
# type: (List[str], Tuple[str, int]) -> List[str]
def dedent_filter(self, lines: List[str], location: Tuple[str, int] = None) -> List[str]:
if 'dedent' in self.options:
return dedent_lines(lines, self.options.get('dedent'), location=location)
else:
@ -430,8 +414,7 @@ class LiteralInclude(SphinxDirective):
'diff': directives.unchanged_required,
}
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
document = self.state.document
if not document.settings.file_insertion_enabled:
return [document.reporter.warning('File insertion disabled',
@ -449,7 +432,7 @@ class LiteralInclude(SphinxDirective):
reader = LiteralIncludeReader(filename, self.options, self.config)
text, lines = reader.read(location=location)
retnode = nodes.literal_block(text, text, source=filename) # type: nodes.Element
retnode = nodes.literal_block(text, text, source=filename) # type: Element
retnode['force'] = 'force' in self.options
self.set_source_info(retnode)
if self.options.get('diff'): # if diff is set, set udiff
@ -483,8 +466,7 @@ class LiteralInclude(SphinxDirective):
return [document.reporter.warning(exc, line=self.lineno)]
def setup(app):
# type: (Sphinx) -> Dict[str, Any]
def setup(app: "Sphinx") -> Dict[str, Any]:
directives.register_directive('highlight', Highlight)
directives.register_directive('highlightlang', HighlightLang)
directives.register_directive('code-block', CodeBlock)

View File

@ -7,9 +7,11 @@
"""
import re
from typing import Any, Dict, List
from typing import cast
from docutils import nodes
from docutils.nodes import Element, Node
from docutils.parsers.rst import directives
from docutils.parsers.rst.directives.admonitions import BaseAdmonition
from docutils.parsers.rst.directives.misc import Class
@ -25,15 +27,13 @@ from sphinx.util.nodes import explicit_title_re, process_index_entry
if False:
# For type annotation
from typing import Any, Dict, List # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.application import Sphinx
glob_re = re.compile(r'.*[*?\[].*')
def int_or_nothing(argument):
# type: (str) -> int
def int_or_nothing(argument: str) -> int:
if not argument:
return 999
return int(argument)
@ -60,8 +60,7 @@ class TocTree(SphinxDirective):
'reversed': directives.flag,
}
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
subnode = addnodes.toctree()
subnode['parent'] = self.env.docname
@ -160,11 +159,10 @@ class Author(SphinxDirective):
final_argument_whitespace = True
option_spec = {} # type: Dict
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
if not self.config.show_authors:
return []
para = nodes.paragraph(translatable=False) # type: nodes.Element
para = nodes.paragraph(translatable=False) # type: Element
emph = nodes.emphasis()
para += emph
if self.name == 'sectionauthor':
@ -179,7 +177,7 @@ class Author(SphinxDirective):
inodes, messages = self.state.inline_text(self.arguments[0], self.lineno)
emph.extend(inodes)
ret = [para] # type: List[nodes.Node]
ret = [para] # type: List[Node]
ret += messages
return ret
@ -194,8 +192,7 @@ class Index(SphinxDirective):
final_argument_whitespace = True
option_spec = {} # type: Dict
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
arguments = self.arguments[0].split('\n')
targetid = 'index-%s' % self.env.new_serialno('index')
targetnode = nodes.target('', '', ids=[targetid])
@ -226,8 +223,7 @@ class TabularColumns(SphinxDirective):
final_argument_whitespace = True
option_spec = {} # type: Dict
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
node = addnodes.tabular_col_spec()
node['spec'] = self.arguments[0]
self.set_source_info(node)
@ -244,15 +240,14 @@ class Centered(SphinxDirective):
final_argument_whitespace = True
option_spec = {} # type: Dict
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
if not self.arguments:
return []
subnode = addnodes.centered() # type: nodes.Element
subnode = addnodes.centered() # type: Element
inodes, messages = self.state.inline_text(self.arguments[0], self.lineno)
subnode.extend(inodes)
ret = [subnode] # type: List[nodes.Node]
ret = [subnode] # type: List[Node]
ret += messages
return ret
@ -267,8 +262,7 @@ class Acks(SphinxDirective):
final_argument_whitespace = False
option_spec = {} # type: Dict
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
node = addnodes.acks()
node.document = self.state.document
self.state.nested_parse(self.content, self.content_offset, node)
@ -291,8 +285,7 @@ class HList(SphinxDirective):
'columns': int,
}
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
ncolumns = self.options.get('columns', 2)
node = nodes.paragraph()
node.document = self.state.document
@ -325,8 +318,7 @@ class Only(SphinxDirective):
final_argument_whitespace = True
option_spec = {} # type: Dict
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
node = addnodes.only()
node.document = self.state.document
self.set_source_info(node)
@ -380,8 +372,7 @@ class Include(BaseInclude, SphinxDirective):
"correctly", i.e. relative to source directory.
"""
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
if self.arguments[0].startswith('<') and \
self.arguments[0].endswith('>'):
# docutils "standard" includes, do not do path processing
@ -392,8 +383,7 @@ class Include(BaseInclude, SphinxDirective):
return super().run()
def setup(app):
# type: (Sphinx) -> Dict[str, Any]
def setup(app: "Sphinx") -> Dict[str, Any]:
directives.register_directive('toctree', TocTree)
directives.register_directive('sectionauthor', Author)
directives.register_directive('moduleauthor', Author)

View File

@ -6,10 +6,11 @@
:license: BSD, see LICENSE for details.
"""
from typing import Any, Dict, List, Tuple
from typing import cast
from docutils import nodes
from docutils.nodes import make_id
from docutils.nodes import Node, make_id, system_message
from docutils.parsers.rst import directives
from docutils.parsers.rst.directives import images, html, tables
@ -20,8 +21,7 @@ from sphinx.util.nodes import set_source_info
if False:
# For type annotation
from typing import Dict, List, Tuple # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.application import Sphinx
class Figure(images.Figure):
@ -29,8 +29,7 @@ class Figure(images.Figure):
instead of the image node.
"""
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
name = self.options.pop('name', None)
result = super().run()
if len(result) == 2 or isinstance(result[0], nodes.system_message):
@ -52,8 +51,7 @@ class Figure(images.Figure):
class Meta(html.Meta, SphinxDirective):
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
result = super().run()
for node in result:
if (isinstance(node, nodes.pending) and
@ -74,8 +72,7 @@ class RSTTable(tables.RSTTable):
Only for docutils-0.13 or older version."""
def make_title(self):
# type: () -> Tuple[nodes.title, List[nodes.system_message]]
def make_title(self) -> Tuple[nodes.title, List[system_message]]:
title, message = super().make_title()
if title:
set_source_info(self, title)
@ -88,8 +85,7 @@ class CSVTable(tables.CSVTable):
Only for docutils-0.13 or older version."""
def make_title(self):
# type: () -> Tuple[nodes.title, List[nodes.system_message]]
def make_title(self) -> Tuple[nodes.title, List[system_message]]:
title, message = super().make_title()
if title:
set_source_info(self, title)
@ -102,8 +98,7 @@ class ListTable(tables.ListTable):
Only for docutils-0.13 or older version."""
def make_title(self):
# type: () -> Tuple[nodes.title, List[nodes.system_message]]
def make_title(self) -> Tuple[nodes.title, List[system_message]]:
title, message = super().make_title()
if title:
set_source_info(self, title)
@ -125,8 +120,7 @@ class Code(SphinxDirective):
}
has_content = True
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
self.assert_has_content()
code = '\n'.join(self.content)
@ -169,8 +163,7 @@ class MathDirective(SphinxDirective):
'nowrap': directives.flag,
}
def run(self):
# type: () -> List[nodes.Node]
def run(self) -> List[Node]:
latex = '\n'.join(self.content)
if self.arguments and self.arguments[0]:
latex = self.arguments[0] + '\n\n' + latex
@ -184,12 +177,11 @@ class MathDirective(SphinxDirective):
self.add_name(node)
self.set_source_info(node)
ret = [node] # type: List[nodes.Node]
ret = [node] # type: List[Node]
self.add_target(ret)
return ret
def add_target(self, ret):
# type: (List[nodes.Node]) -> None
def add_target(self, ret: List[Node]) -> None:
node = cast(nodes.math_block, ret[0])
# assign label automatically if math_number_all enabled
@ -216,8 +208,7 @@ class MathDirective(SphinxDirective):
self.state_machine.reporter.warning(exc, line=self.lineno)
def setup(app):
# type: (Sphinx) -> Dict
def setup(app: "Sphinx") -> Dict[str, Any]:
directives.register_directive('figure', Figure)
directives.register_directive('meta', Meta)
directives.register_directive('table', RSTTable)