Xqt has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/843988 )
Change subject: [IMPR] Allow all Site.categorymembers() parameters for Category.subcategories() ......................................................................
[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(-)
Approvals: Xqt: Verified; Looks good to me, approved
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()
pywikibot-commits@lists.wikimedia.org