Xqt submitted this change.

View Change

Approvals: Xqt: Verified; Looks good to me, approved
[IMPR] Allow all Site.categorymembers() parameters for Category.subcategories()

- enable all parameters of Site.categorymembers() with
Category.subcategories() method
- drop cache because a lot of parameters are used now
- call Category.members() to implement Category.subcategories to prevent
code duplication
- update tests

Change-Id: Iad5570767cbe497e107d8b8f989bc50a7ef16560
---
M pywikibot/page/_category.py
M tests/category_tests.py
2 files changed, 30 insertions(+), 111 deletions(-)

diff --git a/pywikibot/page/_category.py b/pywikibot/page/_category.py
index 173bf67..d6ea85f 100644
--- a/pywikibot/page/_category.py
+++ b/pywikibot/page/_category.py
@@ -58,25 +58,38 @@
title_with_sort_key += '|' + key
return f'[[{title_with_sort_key}]]'

- def subcategories(self,
+ def subcategories(self, *,
recurse: Union[int, bool] = False,
- total: Optional[int] = None,
- content: bool = False):
- """
- Iterate all subcategories of the current category.
+ **kwargs: Any) -> Iterable[Page]:
+ """Iterate all subcategories of the current category.

- :param recurse: if not False or 0, also iterate subcategories of
+ **Usage:**
+
+ >>> site = pywikibot.Site('wikipedia:en')
+ >>> cat = pywikibot.Category(site, 'Contents')
+ >>> next(cat.subcategories())
+ Category('Category:Wikipedia administration')
+ >>> len(list(cat.subcategories(recurse=2, total=50)))
+ 50
+
+ .. seealso:: :attr:`categoryinfo`
+
+ .. versionchanged:: 8.0
+ all parameters are keyword arguments only. Additional
+ parameters are supported.
+
+ :param recurse: if not False or 0, also iterate articles in
subcategories. If an int, limit recursion to this number of
- levels. (Example: recurse=1 will iterate direct subcats and
- first-level sub-sub-cats, but no deeper.)
- :param total: iterate no more than this number of
- subcategories in total (at all levels)
- :param content: if True, retrieve the content of the current version
- of each category description page (default False)
+ levels. (Example: ``recurse=1`` will iterate articles in
+ first-level subcats, but no deeper.)
+ :param kwargs: Additional parameters. Refer to
+ :meth:`APISite.categorymembers()
+ <pywikibot.site._generators.GeneratorsMixin.categorymembers>`
+ for complete list (*member_type* excluded).
"""
-
- def is_cache_valid(cache: dict, content: bool) -> bool:
- return cache['content'] or not content
+ if kwargs.pop('member_type', False):
+ raise TypeError('subcategories() got an unexpected keyword '
+ "argument 'member_type'")

if not self.categoryinfo['subcats']:
return
@@ -84,50 +97,8 @@
if not isinstance(recurse, bool) and recurse:
recurse -= 1

- if (not hasattr(self, '_subcats')
- or not is_cache_valid(self._subcats, content)):
- cache = {'data': [], 'content': content}
-
- for subcat in self.site.categorymembers(
- self, member_type='subcat', total=total, content=content):
- cache['data'].append(subcat)
- yield subcat
- if total is not None:
- total -= 1
- if total == 0:
- return
-
- if recurse:
- for item in subcat.subcategories(
- recurse, total=total, content=content):
- yield item
- if total is None:
- continue
-
- total -= 1
- if total == 0:
- return
-
- # cache is valid only if all subcategories are fetched (T88217)
- self._subcats = cache
- else:
- for subcat in self._subcats['data']:
- yield subcat
- if total is not None:
- total -= 1
- if total == 0:
- return
-
- if recurse:
- for item in subcat.subcategories(
- recurse, total=total, content=content):
- yield item
- if total is None:
- continue
-
- total -= 1
- if total == 0:
- return
+ yield from self.members(member_type='subcat', recurse=recurse,
+ **kwargs)

def articles(self, *,
recurse: Union[int, bool] = False,
diff --git a/tests/category_tests.py b/tests/category_tests.py
index 3bd8f1f..862ed62 100755
--- a/tests/category_tests.py
+++ b/tests/category_tests.py
@@ -107,58 +107,6 @@
subcategories_total = list(cat.subcategories(total=2))
self.assertLength(subcategories_total, 2)

- def test_subcategories_cache_length(self):
- """Test the subcategories cache length."""
- site = self.get_site()
-
- # test cache is valid only if all members of cat are iterated.
- cat = pywikibot.Category(site, 'Category:Wikipedians by gender')
- subcategories = list(cat.subcategories(total=2))
- self.assertLength(subcategories, 2)
- self.assertFalse(hasattr(cat, '_subcats'))
-
- subcategories = list(cat.subcategories())
- self.assertGreater(len(subcategories), 2)
- self.assertTrue(hasattr(cat, '_subcats'))
-
- # new cat, no cached data.
- cat = pywikibot.Category(site, 'Category:Wikipedians by gender')
-
- # cache not available yet due to partial iteration.
- gen = cat.subcategories()
- _ = next(gen)
- self.assertFalse(hasattr(cat, '_subcats'))
-
- # cache available.
- _ = list(gen)
- self.assertTrue(hasattr(cat, '_subcats'))
-
- def test_subcategories_cache_content(self):
- """Test the subcategories cache content."""
- site = self.get_site()
- cat = pywikibot.Category(site, 'Category:Wikipedians by gender')
-
- subcategories = list(cat.subcategories(content=False))
- cache_id_1 = id(cat._subcats)
- cache_len_1 = len(subcategories)
- subcat = subcategories[0]
- self.assertFalse(subcat.has_content())
-
- # toggle content.
- subcategories = list(cat.subcategories(content=True))
- cache_len_2 = len(subcategories)
- cache_id_2 = id(cat._subcats)
- subcat = subcategories[0]
- self.assertTrue(subcat.has_content())
- # cache reloaded.
- self.assertNotEqual(cache_id_1, cache_id_2)
- self.assertTrue(cache_len_1, cache_len_2)
-
- # cache not reloaded.
- _ = list(cat.subcategories(content=True))
- cache_id_3 = id(cat._subcats)
- self.assertEqual(cache_id_2, cache_id_3)
-
def test_subcategories_recurse(self):
"""Test the subcategories method with recurse=True."""
site = self.get_site()

To view, visit change 843988. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: Iad5570767cbe497e107d8b8f989bc50a7ef16560
Gerrit-Change-Number: 843988
Gerrit-PatchSet: 3
Gerrit-Owner: Xqt <info@gno.de>
Gerrit-Reviewer: Mpaa <mpaa.wiki@gmail.com>
Gerrit-Reviewer: Xqt <info@gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged