mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Replace napoleon.iterators
by simpler stack implementation (#9856)
This commit is contained in:
parent
d730c55f13
commit
03c1e1b15c
1
CHANGES
1
CHANGES
@ -12,6 +12,7 @@ Deprecated
|
|||||||
|
|
||||||
* #10467: Deprecated ``sphinx.util.stemmer`` in favour of ``snowballstemmer``.
|
* #10467: Deprecated ``sphinx.util.stemmer`` in favour of ``snowballstemmer``.
|
||||||
Patch by Adam Turner.
|
Patch by Adam Turner.
|
||||||
|
* #9856: Deprecated ``sphinx.ext.napoleon.iterators``.
|
||||||
|
|
||||||
Features added
|
Features added
|
||||||
--------------
|
--------------
|
||||||
|
@ -22,6 +22,11 @@ The following is a list of deprecated interfaces.
|
|||||||
- (will be) Removed
|
- (will be) Removed
|
||||||
- Alternatives
|
- Alternatives
|
||||||
|
|
||||||
|
* - ``sphinx.ext.napoleon.iterators``
|
||||||
|
- 5.1
|
||||||
|
- 7.0
|
||||||
|
- ``pockets.iterators``
|
||||||
|
|
||||||
* - ``sphinx.util.stemmer``
|
* - ``sphinx.util.stemmer``
|
||||||
- 5.1
|
- 5.1
|
||||||
- 7.0
|
- 7.0
|
||||||
|
@ -10,7 +10,6 @@ from typing import Any, Callable, Dict, List, Tuple, Type, Union
|
|||||||
from sphinx.application import Sphinx
|
from sphinx.application import Sphinx
|
||||||
from sphinx.config import Config as SphinxConfig
|
from sphinx.config import Config as SphinxConfig
|
||||||
from sphinx.deprecation import RemovedInSphinx60Warning
|
from sphinx.deprecation import RemovedInSphinx60Warning
|
||||||
from sphinx.ext.napoleon.iterators import modify_iter
|
|
||||||
from sphinx.locale import _, __
|
from sphinx.locale import _, __
|
||||||
from sphinx.util import logging
|
from sphinx.util import logging
|
||||||
from sphinx.util.inspect import stringify_annotation
|
from sphinx.util.inspect import stringify_annotation
|
||||||
@ -46,6 +45,19 @@ _default_regex = re.compile(
|
|||||||
_SINGLETONS = ("None", "True", "False", "Ellipsis")
|
_SINGLETONS = ("None", "True", "False", "Ellipsis")
|
||||||
|
|
||||||
|
|
||||||
|
class Deque(collections.deque):
|
||||||
|
"""A subclass of deque with an additional `.Deque.get` method."""
|
||||||
|
|
||||||
|
sentinel = object()
|
||||||
|
|
||||||
|
def get(self, n: int) -> Any:
|
||||||
|
"""
|
||||||
|
Return the nth element of the stack, or ``self.sentinel`` if n is
|
||||||
|
greater than the stack size.
|
||||||
|
"""
|
||||||
|
return self[n] if n < len(self) else self.sentinel
|
||||||
|
|
||||||
|
|
||||||
def _convert_type_spec(_type: str, translations: Dict[str, str] = {}) -> str:
|
def _convert_type_spec(_type: str, translations: Dict[str, str] = {}) -> str:
|
||||||
"""Convert type specification to reference in reST."""
|
"""Convert type specification to reference in reST."""
|
||||||
if _type in translations:
|
if _type in translations:
|
||||||
@ -153,7 +165,7 @@ class GoogleDocstring:
|
|||||||
lines = docstring.splitlines()
|
lines = docstring.splitlines()
|
||||||
else:
|
else:
|
||||||
lines = docstring
|
lines = docstring
|
||||||
self._line_iter = modify_iter(lines, modifier=lambda s: s.rstrip())
|
self._lines = Deque(map(str.rstrip, lines))
|
||||||
self._parsed_lines: List[str] = []
|
self._parsed_lines: List[str] = []
|
||||||
self._is_in_section = False
|
self._is_in_section = False
|
||||||
self._section_indent = 0
|
self._section_indent = 0
|
||||||
@ -225,32 +237,32 @@ class GoogleDocstring:
|
|||||||
|
|
||||||
def _consume_indented_block(self, indent: int = 1) -> List[str]:
|
def _consume_indented_block(self, indent: int = 1) -> List[str]:
|
||||||
lines = []
|
lines = []
|
||||||
line = self._line_iter.peek()
|
line = self._lines.get(0)
|
||||||
while(not self._is_section_break() and
|
while(not self._is_section_break() and
|
||||||
(not line or self._is_indented(line, indent))):
|
(not line or self._is_indented(line, indent))):
|
||||||
lines.append(next(self._line_iter))
|
lines.append(self._lines.popleft())
|
||||||
line = self._line_iter.peek()
|
line = self._lines.get(0)
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
def _consume_contiguous(self) -> List[str]:
|
def _consume_contiguous(self) -> List[str]:
|
||||||
lines = []
|
lines = []
|
||||||
while (self._line_iter.has_next() and
|
while (self._lines and
|
||||||
self._line_iter.peek() and
|
self._lines.get(0) and
|
||||||
not self._is_section_header()):
|
not self._is_section_header()):
|
||||||
lines.append(next(self._line_iter))
|
lines.append(self._lines.popleft())
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
def _consume_empty(self) -> List[str]:
|
def _consume_empty(self) -> List[str]:
|
||||||
lines = []
|
lines = []
|
||||||
line = self._line_iter.peek()
|
line = self._lines.get(0)
|
||||||
while self._line_iter.has_next() and not line:
|
while self._lines and not line:
|
||||||
lines.append(next(self._line_iter))
|
lines.append(self._lines.popleft())
|
||||||
line = self._line_iter.peek()
|
line = self._lines.get(0)
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
def _consume_field(self, parse_type: bool = True, prefer_type: bool = False
|
def _consume_field(self, parse_type: bool = True, prefer_type: bool = False
|
||||||
) -> Tuple[str, str, List[str]]:
|
) -> Tuple[str, str, List[str]]:
|
||||||
line = next(self._line_iter)
|
line = self._lines.popleft()
|
||||||
|
|
||||||
before, colon, after = self._partition_field_on_colon(line)
|
before, colon, after = self._partition_field_on_colon(line)
|
||||||
_name, _type, _desc = before, '', after
|
_name, _type, _desc = before, '', after
|
||||||
@ -288,7 +300,7 @@ class GoogleDocstring:
|
|||||||
return fields
|
return fields
|
||||||
|
|
||||||
def _consume_inline_attribute(self) -> Tuple[str, List[str]]:
|
def _consume_inline_attribute(self) -> Tuple[str, List[str]]:
|
||||||
line = next(self._line_iter)
|
line = self._lines.popleft()
|
||||||
_type, colon, _desc = self._partition_field_on_colon(line)
|
_type, colon, _desc = self._partition_field_on_colon(line)
|
||||||
if not colon or not _desc:
|
if not colon or not _desc:
|
||||||
_type, _desc = _desc, _type
|
_type, _desc = _desc, _type
|
||||||
@ -326,7 +338,7 @@ class GoogleDocstring:
|
|||||||
return lines
|
return lines
|
||||||
|
|
||||||
def _consume_section_header(self) -> str:
|
def _consume_section_header(self) -> str:
|
||||||
section = next(self._line_iter)
|
section = self._lines.popleft()
|
||||||
stripped_section = section.strip(':')
|
stripped_section = section.strip(':')
|
||||||
if stripped_section.lower() in self._sections:
|
if stripped_section.lower() in self._sections:
|
||||||
section = stripped_section
|
section = stripped_section
|
||||||
@ -334,15 +346,15 @@ class GoogleDocstring:
|
|||||||
|
|
||||||
def _consume_to_end(self) -> List[str]:
|
def _consume_to_end(self) -> List[str]:
|
||||||
lines = []
|
lines = []
|
||||||
while self._line_iter.has_next():
|
while self._lines:
|
||||||
lines.append(next(self._line_iter))
|
lines.append(self._lines.popleft())
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
def _consume_to_next_section(self) -> List[str]:
|
def _consume_to_next_section(self) -> List[str]:
|
||||||
self._consume_empty()
|
self._consume_empty()
|
||||||
lines = []
|
lines = []
|
||||||
while not self._is_section_break():
|
while not self._is_section_break():
|
||||||
lines.append(next(self._line_iter))
|
lines.append(self._lines.popleft())
|
||||||
return lines + self._consume_empty()
|
return lines + self._consume_empty()
|
||||||
|
|
||||||
def _dedent(self, lines: List[str], full: bool = False) -> List[str]:
|
def _dedent(self, lines: List[str], full: bool = False) -> List[str]:
|
||||||
@ -468,12 +480,12 @@ class GoogleDocstring:
|
|||||||
return lines
|
return lines
|
||||||
|
|
||||||
def _get_current_indent(self, peek_ahead: int = 0) -> int:
|
def _get_current_indent(self, peek_ahead: int = 0) -> int:
|
||||||
line = self._line_iter.peek(peek_ahead + 1)[peek_ahead]
|
line = self._lines.get(peek_ahead)
|
||||||
while line != self._line_iter.sentinel:
|
while line is not self._lines.sentinel:
|
||||||
if line:
|
if line:
|
||||||
return self._get_indent(line)
|
return self._get_indent(line)
|
||||||
peek_ahead += 1
|
peek_ahead += 1
|
||||||
line = self._line_iter.peek(peek_ahead + 1)[peek_ahead]
|
line = self._lines.get(peek_ahead)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def _get_indent(self, line: str) -> int:
|
def _get_indent(self, line: str) -> int:
|
||||||
@ -528,7 +540,7 @@ class GoogleDocstring:
|
|||||||
return next_indent > indent
|
return next_indent > indent
|
||||||
|
|
||||||
def _is_section_header(self) -> bool:
|
def _is_section_header(self) -> bool:
|
||||||
section = self._line_iter.peek().lower()
|
section = self._lines.get(0).lower()
|
||||||
match = _google_section_regex.match(section)
|
match = _google_section_regex.match(section)
|
||||||
if match and section.strip(':') in self._sections:
|
if match and section.strip(':') in self._sections:
|
||||||
header_indent = self._get_indent(section)
|
header_indent = self._get_indent(section)
|
||||||
@ -542,8 +554,8 @@ class GoogleDocstring:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def _is_section_break(self) -> bool:
|
def _is_section_break(self) -> bool:
|
||||||
line = self._line_iter.peek()
|
line = self._lines.get(0)
|
||||||
return (not self._line_iter.has_next() or
|
return (not self._lines or
|
||||||
self._is_section_header() or
|
self._is_section_header() or
|
||||||
(self._is_in_section and
|
(self._is_in_section and
|
||||||
line and
|
line and
|
||||||
@ -585,7 +597,7 @@ class GoogleDocstring:
|
|||||||
self._parsed_lines.extend(res)
|
self._parsed_lines.extend(res)
|
||||||
return
|
return
|
||||||
|
|
||||||
while self._line_iter.has_next():
|
while self._lines:
|
||||||
if self._is_section_header():
|
if self._is_section_header():
|
||||||
try:
|
try:
|
||||||
section = self._consume_section_header()
|
section = self._consume_section_header()
|
||||||
@ -1158,7 +1170,7 @@ class NumpyDocstring(GoogleDocstring):
|
|||||||
|
|
||||||
def _consume_field(self, parse_type: bool = True, prefer_type: bool = False
|
def _consume_field(self, parse_type: bool = True, prefer_type: bool = False
|
||||||
) -> Tuple[str, str, List[str]]:
|
) -> Tuple[str, str, List[str]]:
|
||||||
line = next(self._line_iter)
|
line = self._lines.popleft()
|
||||||
if parse_type:
|
if parse_type:
|
||||||
_name, _, _type = self._partition_field_on_colon(line)
|
_name, _, _type = self._partition_field_on_colon(line)
|
||||||
else:
|
else:
|
||||||
@ -1189,15 +1201,15 @@ class NumpyDocstring(GoogleDocstring):
|
|||||||
return self._consume_fields(prefer_type=True)
|
return self._consume_fields(prefer_type=True)
|
||||||
|
|
||||||
def _consume_section_header(self) -> str:
|
def _consume_section_header(self) -> str:
|
||||||
section = next(self._line_iter)
|
section = self._lines.popleft()
|
||||||
if not _directive_regex.match(section):
|
if not _directive_regex.match(section):
|
||||||
# Consume the header underline
|
# Consume the header underline
|
||||||
next(self._line_iter)
|
self._lines.popleft()
|
||||||
return section
|
return section
|
||||||
|
|
||||||
def _is_section_break(self) -> bool:
|
def _is_section_break(self) -> bool:
|
||||||
line1, line2 = self._line_iter.peek(2)
|
line1, line2 = self._lines.get(0), self._lines.get(1)
|
||||||
return (not self._line_iter.has_next() or
|
return (not self._lines or
|
||||||
self._is_section_header() or
|
self._is_section_header() or
|
||||||
['', ''] == [line1, line2] or
|
['', ''] == [line1, line2] or
|
||||||
(self._is_in_section and
|
(self._is_in_section and
|
||||||
@ -1205,7 +1217,7 @@ class NumpyDocstring(GoogleDocstring):
|
|||||||
not self._is_indented(line1, self._section_indent)))
|
not self._is_indented(line1, self._section_indent)))
|
||||||
|
|
||||||
def _is_section_header(self) -> bool:
|
def _is_section_header(self) -> bool:
|
||||||
section, underline = self._line_iter.peek(2)
|
section, underline = self._lines.get(0), self._lines.get(1)
|
||||||
section = section.lower()
|
section = section.lower()
|
||||||
if section in self._sections and isinstance(underline, str):
|
if section in self._sections and isinstance(underline, str):
|
||||||
return bool(_numpy_section_regex.match(underline))
|
return bool(_numpy_section_regex.match(underline))
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
"""A collection of helpful iterators."""
|
"""A collection of helpful iterators."""
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
import warnings
|
||||||
from typing import Any, Iterable, Optional
|
from typing import Any, Iterable, Optional
|
||||||
|
|
||||||
|
from sphinx.deprecation import RemovedInSphinx70Warning
|
||||||
|
|
||||||
|
warnings.warn('sphinx.ext.napoleon.iterators is deprecated.',
|
||||||
|
RemovedInSphinx70Warning)
|
||||||
|
|
||||||
|
|
||||||
class peek_iter:
|
class peek_iter:
|
||||||
"""An iterator object that supports peeking ahead.
|
"""An iterator object that supports peeking ahead.
|
||||||
|
@ -1,10 +1,19 @@
|
|||||||
"""Tests for :mod:`sphinx.ext.napoleon.iterators` module."""
|
"""Tests for :mod:`sphinx.ext.napoleon.iterators` module."""
|
||||||
|
|
||||||
|
import sys
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
|
from sphinx.deprecation import RemovedInSphinx70Warning
|
||||||
from sphinx.ext.napoleon.iterators import modify_iter, peek_iter
|
from sphinx.ext.napoleon.iterators import modify_iter, peek_iter
|
||||||
|
|
||||||
|
|
||||||
|
class ModuleIsDeprecatedTest(TestCase):
|
||||||
|
def test_module_is_deprecated(self):
|
||||||
|
sys.modules.pop("sphinx.ext.napoleon.iterators")
|
||||||
|
with self.assertWarns(RemovedInSphinx70Warning):
|
||||||
|
import sphinx.ext.napoleon.iterators # noqa
|
||||||
|
|
||||||
|
|
||||||
class BaseIteratorsTest(TestCase):
|
class BaseIteratorsTest(TestCase):
|
||||||
def assertEqualTwice(self, expected, func, *args):
|
def assertEqualTwice(self, expected, func, *args):
|
||||||
self.assertEqual(expected, func(*args))
|
self.assertEqual(expected, func(*args))
|
||||||
|
Loading…
Reference in New Issue
Block a user