diff --git a/CHANGES b/CHANGES index 049019b33e2..81d5adfd7da 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,7 @@ Incompatible changes description classes. * #11363: Remove the Setuptools integration (``build_sphinx`` hook in ``setup.py``). +* #11364: Remove deprecated ``sphinx.ext.napoleon.iterators`` module. Deprecated ---------- diff --git a/sphinx/ext/napoleon/iterators.py b/sphinx/ext/napoleon/iterators.py deleted file mode 100644 index 2861caa7d58..00000000000 --- a/sphinx/ext/napoleon/iterators.py +++ /dev/null @@ -1,235 +0,0 @@ -"""A collection of helpful iterators.""" - -from __future__ import annotations - -import collections -import warnings -from typing import Any, Iterable - -from sphinx.deprecation import RemovedInSphinx70Warning - -warnings.warn('sphinx.ext.napoleon.iterators is deprecated.', - RemovedInSphinx70Warning) - - -class peek_iter: - """An iterator object that supports peeking ahead. - - Parameters - ---------- - o : iterable or callable - `o` is interpreted very differently depending on the presence of - `sentinel`. - - If `sentinel` is not given, then `o` must be a collection object - which supports either the iteration protocol or the sequence protocol. - - If `sentinel` is given, then `o` must be a callable object. - - sentinel : any value, optional - If given, the iterator will call `o` with no arguments for each - call to its `next` method; if the value returned is equal to - `sentinel`, :exc:`StopIteration` will be raised, otherwise the - value will be returned. - - See Also - -------- - `peek_iter` can operate as a drop in replacement for the built-in - `iter `_ function. - - Attributes - ---------- - sentinel - The value used to indicate the iterator is exhausted. If `sentinel` - was not given when the `peek_iter` was instantiated, then it will - be set to a new object instance: ``object()``. - - """ - def __init__(self, *args: Any) -> None: - """__init__(o, sentinel=None)""" - self._iterable: Iterable = iter(*args) - self._cache: collections.deque = collections.deque() - if len(args) == 2: - self.sentinel = args[1] - else: - self.sentinel = object() - - def __iter__(self) -> peek_iter: - return self - - def __next__(self, n: int | None = None) -> Any: - return self.next(n) - - def _fillcache(self, n: int | None) -> None: - """Cache `n` items. If `n` is 0 or None, then 1 item is cached.""" - if not n: - n = 1 - try: - while len(self._cache) < n: - self._cache.append(next(self._iterable)) # type: ignore - except StopIteration: - while len(self._cache) < n: - self._cache.append(self.sentinel) - - def has_next(self) -> bool: - """Determine if iterator is exhausted. - - Returns - ------- - bool - True if iterator has more items, False otherwise. - - Note - ---- - Will never raise :exc:`StopIteration`. - - """ - return self.peek() != self.sentinel - - def next(self, n: int | None = None) -> Any: - """Get the next item or `n` items of the iterator. - - Parameters - ---------- - n : int or None - The number of items to retrieve. Defaults to None. - - Returns - ------- - item or list of items - The next item or `n` items of the iterator. If `n` is None, the - item itself is returned. If `n` is an int, the items will be - returned in a list. If `n` is 0, an empty list is returned. - - Raises - ------ - StopIteration - Raised if the iterator is exhausted, even if `n` is 0. - - """ - self._fillcache(n) - if not n: - if self._cache[0] == self.sentinel: - raise StopIteration - if n is None: - result = self._cache.popleft() - else: - result = [] - else: - if self._cache[n - 1] == self.sentinel: - raise StopIteration - result = [self._cache.popleft() for i in range(n)] - return result - - def peek(self, n: int | None = None) -> Any: - """Preview the next item or `n` items of the iterator. - - The iterator is not advanced when peek is called. - - Returns - ------- - item or list of items - The next item or `n` items of the iterator. If `n` is None, the - item itself is returned. If `n` is an int, the items will be - returned in a list. If `n` is 0, an empty list is returned. - - If the iterator is exhausted, `peek_iter.sentinel` is returned, - or placed as the last item in the returned list. - - Note - ---- - Will never raise :exc:`StopIteration`. - - """ - self._fillcache(n) - if n is None: - result = self._cache[0] - else: - result = [self._cache[i] for i in range(n)] - return result - - -class modify_iter(peek_iter): - """An iterator object that supports modifying items as they are returned. - - Parameters - ---------- - o : iterable or callable - `o` is interpreted very differently depending on the presence of - `sentinel`. - - If `sentinel` is not given, then `o` must be a collection object - which supports either the iteration protocol or the sequence protocol. - - If `sentinel` is given, then `o` must be a callable object. - - sentinel : any value, optional - If given, the iterator will call `o` with no arguments for each - call to its `next` method; if the value returned is equal to - `sentinel`, :exc:`StopIteration` will be raised, otherwise the - value will be returned. - - modifier : callable, optional - The function that will be used to modify each item returned by the - iterator. `modifier` should take a single argument and return a - single value. Defaults to ``lambda x: x``. - - If `sentinel` is not given, `modifier` must be passed as a keyword - argument. - - Attributes - ---------- - modifier : callable - `modifier` is called with each item in `o` as it is iterated. The - return value of `modifier` is returned in lieu of the item. - - Values returned by `peek` as well as `next` are affected by - `modifier`. However, `modify_iter.sentinel` is never passed through - `modifier`; it will always be returned from `peek` unmodified. - - Example - ------- - >>> a = [" A list ", - ... " of strings ", - ... " with ", - ... " extra ", - ... " whitespace. "] - >>> modifier = lambda s: s.strip().replace('with', 'without') - >>> for s in modify_iter(a, modifier=modifier): - ... print('"%s"' % s) - "A list" - "of strings" - "without" - "extra" - "whitespace." - - """ - def __init__(self, *args: Any, **kwargs: Any) -> None: - """__init__(o, sentinel=None, modifier=lambda x: x)""" - if 'modifier' in kwargs: - self.modifier = kwargs['modifier'] - elif len(args) > 2: - self.modifier = args[2] - args = args[:2] - else: - self.modifier = lambda x: x - if not callable(self.modifier): - raise TypeError('modify_iter(o, modifier): ' - 'modifier must be callable') - super().__init__(*args) - - def _fillcache(self, n: int | None) -> None: - """Cache `n` modified items. If `n` is 0 or None, 1 item is cached. - - Each item returned by the iterator is passed through the - `modify_iter.modified` function before being cached. - - """ - if not n: - n = 1 - try: - while len(self._cache) < n: - self._cache.append(self.modifier(next(self._iterable))) # type: ignore - except StopIteration: - while len(self._cache) < n: - self._cache.append(self.sentinel) diff --git a/tests/test_ext_napoleon_iterators.py b/tests/test_ext_napoleon_iterators.py deleted file mode 100644 index e7e976ee54a..00000000000 --- a/tests/test_ext_napoleon_iterators.py +++ /dev/null @@ -1,358 +0,0 @@ -"""Tests for :mod:`sphinx.ext.napoleon.iterators` module.""" - -import sys - -import pytest - -from sphinx.deprecation import RemovedInSphinx70Warning - -with pytest.warns(DeprecationWarning, - match="sphinx.ext.napoleon.iterators is deprecated."): - from sphinx.ext.napoleon.iterators import modify_iter, peek_iter - - -class TestModuleIsDeprecated: - def test_module_is_deprecated(self): - sys.modules.pop("sphinx.ext.napoleon.iterators") - with pytest.warns(RemovedInSphinx70Warning, - match="sphinx.ext.napoleon.iterators is deprecated."): - import sphinx.ext.napoleon.iterators # noqa: F401 - - -def _assert_equal_twice(expected, func, *args): - assert expected == func(*args) - assert expected == func(*args) - - -def _assert_false_twice(func, *args): - assert not func(*args) - assert not func(*args) - - -def _assert_next(it, expected, is_last): - _assert_true_twice(it.has_next) - _assert_equal_twice(expected, it.peek) - _assert_true_twice(it.has_next) - _assert_equal_twice(expected, it.peek) - _assert_true_twice(it.has_next) - assert expected == next(it) - if is_last: - _assert_false_twice(it.has_next) - _assert_raises_twice(StopIteration, it.next) - else: - _assert_true_twice(it.has_next) - - -def _assert_raises_twice(exc, func, *args): - with pytest.raises(exc): - func(*args) - with pytest.raises(exc): - func(*args) - - -def _assert_true_twice(func, *args): - assert func(*args) - assert func(*args) - - -class TestPeekIter: - def test_init_with_sentinel(self): - a = iter(['1', '2', 'DONE']) - sentinel = 'DONE' - with pytest.raises(TypeError): - peek_iter(a, sentinel) - - def get_next(): - return next(a) - it = peek_iter(get_next, sentinel) - assert it.sentinel == sentinel - _assert_next(it, '1', is_last=False) - _assert_next(it, '2', is_last=True) - - def test_iter(self): - a = ['1', '2', '3'] - it = peek_iter(a) - assert it is it.__iter__() - - a = [] - b = list(peek_iter(a)) - assert [] == b - - a = ['1'] - b = list(peek_iter(a)) - assert ["1"] == b - - a = ['1', '2'] - b = list(peek_iter(a)) - assert ["1", "2"] == b - - a = ['1', '2', '3'] - b = list(peek_iter(a)) - assert ["1", "2", "3"] == b - - def test_next_with_multi(self): - a = [] - it = peek_iter(a) - _assert_false_twice(it.has_next) - _assert_raises_twice(StopIteration, it.next, 2) - - a = ['1'] - it = peek_iter(a) - _assert_true_twice(it.has_next) - _assert_raises_twice(StopIteration, it.next, 2) - _assert_true_twice(it.has_next) - - a = ['1', '2'] - it = peek_iter(a) - _assert_true_twice(it.has_next) - assert ["1", "2"] == it.next(2) - _assert_false_twice(it.has_next) - - a = ['1', '2', '3'] - it = peek_iter(a) - _assert_true_twice(it.has_next) - assert ["1", "2"] == it.next(2) - _assert_true_twice(it.has_next) - _assert_raises_twice(StopIteration, it.next, 2) - _assert_true_twice(it.has_next) - - a = ['1', '2', '3', '4'] - it = peek_iter(a) - _assert_true_twice(it.has_next) - assert ["1", "2"] == it.next(2) - _assert_true_twice(it.has_next) - assert ["3", "4"] == it.next(2) - _assert_false_twice(it.has_next) - _assert_raises_twice(StopIteration, it.next, 2) - _assert_false_twice(it.has_next) - - def test_next_with_none(self): - a = [] - it = peek_iter(a) - _assert_false_twice(it.has_next) - _assert_raises_twice(StopIteration, it.next) - _assert_false_twice(it.has_next) - - a = ['1'] - it = peek_iter(a) - assert it.__next__() == "1" - - a = ['1'] - it = peek_iter(a) - _assert_next(it, '1', is_last=True) - - a = ['1', '2'] - it = peek_iter(a) - _assert_next(it, '1', is_last=False) - _assert_next(it, '2', is_last=True) - - a = ['1', '2', '3'] - it = peek_iter(a) - _assert_next(it, '1', is_last=False) - _assert_next(it, '2', is_last=False) - _assert_next(it, '3', is_last=True) - - def test_next_with_one(self): - a = [] - it = peek_iter(a) - _assert_false_twice(it.has_next) - _assert_raises_twice(StopIteration, it.next, 1) - - a = ['1'] - it = peek_iter(a) - _assert_true_twice(it.has_next) - assert ["1"] == it.next(1) - _assert_false_twice(it.has_next) - _assert_raises_twice(StopIteration, it.next, 1) - - a = ['1', '2'] - it = peek_iter(a) - _assert_true_twice(it.has_next) - assert ["1"] == it.next(1) - _assert_true_twice(it.has_next) - assert ["2"] == it.next(1) - _assert_false_twice(it.has_next) - _assert_raises_twice(StopIteration, it.next, 1) - - def test_next_with_zero(self): - a = [] - it = peek_iter(a) - _assert_false_twice(it.has_next) - _assert_raises_twice(StopIteration, it.next, 0) - - a = ['1'] - it = peek_iter(a) - _assert_true_twice(it.has_next) - _assert_equal_twice([], it.next, 0) - _assert_true_twice(it.has_next) - _assert_equal_twice([], it.next, 0) - - a = ['1', '2'] - it = peek_iter(a) - _assert_true_twice(it.has_next) - _assert_equal_twice([], it.next, 0) - _assert_true_twice(it.has_next) - _assert_equal_twice([], it.next, 0) - - def test_peek_with_multi(self): - a = [] - it = peek_iter(a) - _assert_false_twice(it.has_next) - _assert_equal_twice([it.sentinel, it.sentinel], it.peek, 2) - _assert_false_twice(it.has_next) - - a = ['1'] - it = peek_iter(a) - _assert_true_twice(it.has_next) - _assert_equal_twice(['1', it.sentinel], it.peek, 2) - _assert_true_twice(it.has_next) - _assert_equal_twice(['1', it.sentinel, it.sentinel], it.peek, 3) - _assert_true_twice(it.has_next) - - a = ['1', '2'] - it = peek_iter(a) - _assert_true_twice(it.has_next) - _assert_equal_twice(['1', '2'], it.peek, 2) - _assert_true_twice(it.has_next) - _assert_equal_twice(['1', '2', it.sentinel], it.peek, 3) - _assert_true_twice(it.has_next) - _assert_equal_twice(['1', '2', it.sentinel, it.sentinel], it.peek, 4) - _assert_true_twice(it.has_next) - - a = ['1', '2', '3'] - it = peek_iter(a) - _assert_true_twice(it.has_next) - _assert_equal_twice(['1', '2'], it.peek, 2) - _assert_true_twice(it.has_next) - _assert_equal_twice(['1', '2', '3'], it.peek, 3) - _assert_true_twice(it.has_next) - _assert_equal_twice(['1', '2', '3', it.sentinel], it.peek, 4) - _assert_true_twice(it.has_next) - assert next(it) == "1" - _assert_true_twice(it.has_next) - _assert_equal_twice(['2', '3'], it.peek, 2) - _assert_true_twice(it.has_next) - _assert_equal_twice(['2', '3', it.sentinel], it.peek, 3) - _assert_true_twice(it.has_next) - _assert_equal_twice(['2', '3', it.sentinel, it.sentinel], it.peek, 4) - _assert_true_twice(it.has_next) - - def test_peek_with_none(self): - a = [] - it = peek_iter(a) - _assert_false_twice(it.has_next) - _assert_equal_twice(it.sentinel, it.peek) - _assert_false_twice(it.has_next) - - a = ['1'] - it = peek_iter(a) - _assert_true_twice(it.has_next) - _assert_equal_twice('1', it.peek) - assert next(it) == "1" - _assert_false_twice(it.has_next) - _assert_equal_twice(it.sentinel, it.peek) - _assert_false_twice(it.has_next) - - a = ['1', '2'] - it = peek_iter(a) - _assert_true_twice(it.has_next) - _assert_equal_twice('1', it.peek) - assert next(it) == "1" - _assert_true_twice(it.has_next) - _assert_equal_twice('2', it.peek) - assert next(it) == "2" - _assert_false_twice(it.has_next) - _assert_equal_twice(it.sentinel, it.peek) - _assert_false_twice(it.has_next) - - def test_peek_with_one(self): - a = [] - it = peek_iter(a) - _assert_false_twice(it.has_next) - _assert_equal_twice([it.sentinel], it.peek, 1) - _assert_false_twice(it.has_next) - - a = ['1'] - it = peek_iter(a) - _assert_true_twice(it.has_next) - _assert_equal_twice(['1'], it.peek, 1) - assert next(it) == "1" - _assert_false_twice(it.has_next) - _assert_equal_twice([it.sentinel], it.peek, 1) - _assert_false_twice(it.has_next) - - a = ['1', '2'] - it = peek_iter(a) - _assert_true_twice(it.has_next) - _assert_equal_twice(['1'], it.peek, 1) - assert next(it) == "1" - _assert_true_twice(it.has_next) - _assert_equal_twice(['2'], it.peek, 1) - assert next(it) == "2" - _assert_false_twice(it.has_next) - _assert_equal_twice([it.sentinel], it.peek, 1) - _assert_false_twice(it.has_next) - - def test_peek_with_zero(self): - a = [] - it = peek_iter(a) - _assert_false_twice(it.has_next) - _assert_equal_twice([], it.peek, 0) - - a = ['1'] - it = peek_iter(a) - _assert_true_twice(it.has_next) - _assert_equal_twice([], it.peek, 0) - _assert_true_twice(it.has_next) - _assert_equal_twice([], it.peek, 0) - - a = ['1', '2'] - it = peek_iter(a) - _assert_true_twice(it.has_next) - _assert_equal_twice([], it.peek, 0) - _assert_true_twice(it.has_next) - _assert_equal_twice([], it.peek, 0) - - -class TestModifyIter: - def test_init_with_sentinel_args(self): - a = iter(['1', '2', '3', 'DONE']) - sentinel = 'DONE' - - def get_next(): - return next(a) - it = modify_iter(get_next, sentinel, int) - expected = [1, 2, 3] - assert expected == list(it) - - def test_init_with_sentinel_kwargs(self): - a = iter([1, 2, 3, 4]) - sentinel = 4 - - def get_next(): - return next(a) - it = modify_iter(get_next, sentinel, modifier=str) - expected = ['1', '2', '3'] - assert expected == list(it) - - def test_modifier_default(self): - a = ['', ' ', ' a ', 'b ', ' c', ' ', ''] - it = modify_iter(a) - expected = ['', ' ', ' a ', 'b ', ' c', ' ', ''] - assert expected == list(it) - - def test_modifier_not_callable(self): - with pytest.raises(TypeError): - modify_iter([1], modifier='not_callable') - - def test_modifier_rstrip(self): - a = ['', ' ', ' a ', 'b ', ' c', ' ', ''] - it = modify_iter(a, modifier=lambda s: s.rstrip()) - expected = ['', '', ' a', 'b', ' c', '', ''] - assert expected == list(it) - - def test_modifier_rstrip_unicode(self): - a = ['', ' ', ' a ', 'b ', ' c', ' ', ''] - it = modify_iter(a, modifier=lambda s: s.rstrip()) - expected = ['', '', ' a', 'b', ' c', '', ''] - assert expected == list(it)