jenkins-bot submitted this change.

View Change

Approvals: Xqt: Looks good to me, approved jenkins-bot: Verified
[doc] Refer APISite.categorymembers for Category.articles parameters

- Only allow keyword arguments with Category.articles()
- use **kwargs to pass parameters to the underlying APISite.categorymembers()
- refer to categorymembers for parameter documentation
- raise TypeError instead of pywikibot.Error in categorymembers()
if category is not a Category page.
- update documentation

Bug: T320455
Change-Id: I83468a5cd3c062214c82542d6371a0daa84260d3
---
M pywikibot/page/_category.py
M pywikibot/site/_generators.py
2 files changed, 75 insertions(+), 75 deletions(-)

diff --git a/pywikibot/page/_category.py b/pywikibot/page/_category.py
index 398cd3c..4a7e718 100644
--- a/pywikibot/page/_category.py
+++ b/pywikibot/page/_category.py
@@ -5,10 +5,10 @@
# Distributed under the terms of the MIT license.
#
from collections import defaultdict
-from typing import Optional, Union
+from typing import Any, Optional, Union

import pywikibot
-from pywikibot.backports import Generator, List
+from pywikibot.backports import Generator, Iterable
from pywikibot.page._page import Page


@@ -119,61 +119,52 @@
if total == 0:
return

- def articles(self,
+ def articles(self, *,
recurse: Union[int, bool] = False,
total: Optional[int] = None,
- content: bool = False,
- namespaces: Union[int, List[int]] = None,
- sortby: Optional[str] = None,
- reverse: bool = False,
- starttime=None, endtime=None,
- startprefix: Optional[str] = None,
- endprefix: Optional[str] = None):
+ **kwargs: Any) -> Iterable[Page]:
"""
Yield all articles in the current category.

- By default, yields all *pages* in the category that are not
- subcategories!
+ By default, yields all pages in the category that are not
+ subcategories.
+
+ **Usage:**
+
+ >>> site = pywikibot.Site('wikipedia:test')
+ >>> cat = pywikibot.Category(site, 'Pywikibot')
+ >>> list(cat.articles())
+ [Page('Pywikibot nobots test')]
+ >>> for p in cat.articles(recurse=1, namespaces=2, total=3):
+ ... print(p.depth)
+ ...
+ 2
+ 3
+ 4
+
+ .. versionchanged:: 8.0.0
+ all parameters are keyword arguments only.

: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 articles in first-level
- subcats, but no deeper.)
+ levels. (Example: ``recurse=1`` will iterate articles in
+ first-level subcats, but no deeper.)
:param total: iterate no more than this number of pages in
total (at all levels)
- :param namespaces: only yield pages in the specified namespaces
- :param content: if True, retrieve the content of the current version
- of each page (default False)
- :param sortby: determines the order in which results are generated,
- valid values are "sortkey" (default, results ordered by category
- sort key) or "timestamp" (results ordered by time page was
- added to the category). This applies recursively.
- :param reverse: if True, generate results in reverse order
- (default False)
- :param starttime: if provided, only generate pages added after this
- time; not valid unless sortby="timestamp"
- :type starttime: pywikibot.Timestamp
- :param endtime: if provided, only generate pages added before this
- time; not valid unless sortby="timestamp"
- :type endtime: pywikibot.Timestamp
- :param startprefix: if provided, only generate pages >= this title
- lexically; not valid if sortby="timestamp"
- :param endprefix: if provided, only generate pages < this title
- lexically; not valid if sortby="timestamp"
- :rtype: typing.Iterable[pywikibot.Page]
+ :param kwargs: Additional parameters. Refer
+ :meth:`APISite.categorymembers()
+ <pywikibot.site._generators.GeneratorsMixin.categorymembers>`
+ for them except of *member_type*.
"""
+ if kwargs.pop('member_type', False):
+ raise TypeError(
+ "articles() got an unexpected keyword argument 'member_type'")
+
seen = set()
for member in self.site.categorymembers(self,
- namespaces=namespaces,
total=total,
- content=content,
- sortby=sortby,
- reverse=reverse,
- starttime=starttime,
- endtime=endtime,
- startprefix=startprefix,
- endprefix=endprefix,
- member_type=['page', 'file']):
+ member_type=['page', 'file'],
+ **kwargs):
if recurse:
seen.add(hash(member))
yield member
@@ -188,14 +179,7 @@
for subcat in self.subcategories():
for article in subcat.articles(recurse=recurse,
total=total,
- content=content,
- namespaces=namespaces,
- sortby=sortby,
- reverse=reverse,
- starttime=starttime,
- endtime=endtime,
- startprefix=startprefix,
- endprefix=endprefix):
+ **kwargs):
hash_value = hash(article)
if hash_value in seen:
continue
diff --git a/pywikibot/site/_generators.py b/pywikibot/site/_generators.py
index b3d6621..25f205f 100644
--- a/pywikibot/site/_generators.py
+++ b/pywikibot/site/_generators.py
@@ -461,19 +461,33 @@
titles=tltitle, namespaces=namespaces,
total=total, g_content=content)

- def categorymembers(self, category, *,
- namespaces=None,
- sortby: Optional[str] = None,
- reverse: bool = False,
- starttime=None,
- endtime=None,
- total: Optional[int] = None,
- content: bool = False,
- member_type=None,
- startprefix: Optional[str] = None,
- endprefix: Optional[str] = None):
+ def categorymembers(
+ self,
+ category: 'pywikibot.Category', *,
+ namespaces=None,
+ sortby: Optional[str] = None,
+ reverse: bool = False,
+ starttime: Optional[pywikibot.time.Timestamp] = None,
+ endtime: Optional[pywikibot.time.Timestamp] = None,
+ total: Optional[int] = None,
+ startprefix: Optional[str] = None,
+ endprefix: Optional[str] = None,
+ content: bool = False,
+ member_type: Union[str, Iterable[str], None] = None
+ ) -> Iterable['pywikibot.Page']:
"""Iterate members of specified category.

+ You should not use this method directly; instead use one of the
+ following:
+
+ - :meth:`pywikibot.Category.articles`
+ - :meth:`pywikibot.Category.members`
+ - :meth:`pywikibot.Category.subcategories`
+
+ .. versionchanged:: 4.0.0
+ parameters except *category* are keyword arguments only.
+ .. versionchanged:: 8.0.0
+ raises TypeError instead of Error if no Category is specified
.. seealso:: :api:`Categorymembers`

:param category: The Category to iterate.
@@ -491,7 +505,6 @@
(default False)
:param starttime: if provided, only generate pages added after this
time; not valid unless sortby="timestamp"
- :type starttime: time.Timestamp
:param endtime: if provided, only generate pages added before this
time; not valid unless sortby="timestamp"
:param startprefix: if provided, only generate pages >= this title
@@ -500,19 +513,20 @@
lexically; not valid if sortby="timestamp"
:param content: if True, load the current content of each iterated page
(default False)
- :param member_type: member type; if member_type includes 'page' and is
- used in conjunction with sortby="timestamp", the API may limit
- results to only pages in the first 50 namespaces.
- :type member_type: str or iterable of str;
- values: page, subcat, file
- :rtype: typing.Iterable[pywikibot.Page]
+ :param member_type: member type; values must be ``page``,
+ ``subcat``, ``file``. If member_type includes ``page`` and
+ is used in conjunction with sortby="timestamp", the API may
+ limit results to only pages in the first 50 namespaces.
+
:raises KeyError: a namespace identifier was not resolved
:raises TypeError: a namespace identifier has an inappropriate
type such as NoneType or bool
+ :raises TypeError: no Category is specified
+ :raises ValueError: invalid values given
"""
if category.namespace() != 14:
- raise Error('categorymembers: non-Category page {!r} specified'
- .format(category))
+ raise TypeError(
+ f'categorymembers: non-Category page {category!r} specified')

cmtitle = category.title(with_section=False).encode(self.encoding())
cmargs = {
@@ -524,12 +538,13 @@
if sortby in ['sortkey', 'timestamp']:
cmargs['gcmsort'] = sortby
elif sortby:
- raise ValueError('categorymembers: invalid sortby value {!r}'
- .format(sortby))
+ raise ValueError(
+ f'categorymembers: invalid sortby value {sortby!r}')

if starttime and endtime and starttime > endtime:
raise ValueError(
'categorymembers: starttime must be before endtime')
+
if startprefix and endprefix and startprefix > endprefix:
raise ValueError(
'categorymembers: startprefix must be less than endprefix')
@@ -543,6 +558,7 @@

if 'page' in member_type:
excluded_namespaces = set()
+
if 'file' not in member_type:
excluded_namespaces.add(6)
if 'subcat' not in member_type:
@@ -551,8 +567,8 @@
if namespaces:
if excluded_namespaces.intersection(namespaces):
raise ValueError(
- 'incompatible namespaces {!r} and member_type {!r}'
- .format(namespaces, member_type))
+ f'incompatible namespaces {namespaces!r} and '
+ f'member_type {member_type!r}')
# All excluded namespaces are not present in `namespaces`.
else:
# If the number of namespaces is greater than permitted by

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

Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I83468a5cd3c062214c82542d6371a0daa84260d3
Gerrit-Change-Number: 841471
Gerrit-PatchSet: 5
Gerrit-Owner: Xqt <info@gno.de>
Gerrit-Reviewer: RoySmith <roy@panix.com>
Gerrit-Reviewer: Xqt <info@gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged