jenkins-bot has submitted this change. (
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/738509 )
Change subject: [IMPR] Provide is_locked method
......................................................................
[IMPR] Provide is_locked method
- add APISite.get_globaluserinfo() method to retrieve global user
info for a given user or user ID. This enables to get global info like
global groups for any user.
- add globaluserinfo deleter to force reloading
- add APISite.is_locked() method
- rename User.isBlocked() to User.is_blocked() and deprecate the old
variant to be unified wit APISite.is_blocked()
- add force parameter to APISite.is_blocked like we have in User method
- add User.is_locked() method
- add is_locked to user_tests
- use renamed is_blocked in welcome.py script and also check for
global lock
Bug: T163629
Bug: T249392
Change-Id: I735b3b46fea82354f9beddbdfe7df0ee9670eba9
---
M pywikibot/page/__init__.py
M pywikibot/site/_apisite.py
M scripts/welcome.py
M tests/user_tests.py
4 files changed, 124 insertions(+), 30 deletions(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/page/__init__.py b/pywikibot/page/__init__.py
index 4b78130..0552e50 100644
--- a/pywikibot/page/__init__.py
+++ b/pywikibot/page/__init__.py
@@ -2871,14 +2871,36 @@
"""
return self.getprops(force).get('editcount', 0)
- def isBlocked(self, force: bool = False) -> bool:
- """
- Determine whether the user is currently blocked.
+ def is_blocked(self, force: bool = False) -> bool:
+ """Determine whether the user is currently blocked.
+
+ .. versionchanged:: 7.0
+ renamed from :meth:`isBlocked` method
:param force: if True, forces reloading the data from API
"""
return 'blockedby' in self.getprops(force)
+ @deprecated('is_blocked', since='7.0.0')
+ def isBlocked(self, force: bool = False) -> bool:
+ """Determine whether the user is currently blocked.
+
+ .. deprecated:: 7.0
+ use :meth:`is_blocked` instead
+
+ :param force: if True, forces reloading the data from API
+ """
+ return self.is_blocked(force)
+
+ def is_locked(self, force: bool = False) -> bool:
+ """Determine whether the user is currently locked globally.
+
+ .. versionadded:: 7.0
+
+ :param force: if True, forces reloading the data from API
+ """
+ return self.site.is_locked(self.username, force)
+
def isEmailable(self, force: bool = False) -> bool:
"""
Determine whether emails may be send to this user through MediaWiki.
diff --git a/pywikibot/site/_apisite.py b/pywikibot/site/_apisite.py
index 77658bc..74b45cd 100644
--- a/pywikibot/site/_apisite.py
+++ b/pywikibot/site/_apisite.py
@@ -14,12 +14,12 @@
from collections.abc import Iterable
from contextlib import suppress
from textwrap import fill
-from typing import Optional, Union
+from typing import Any, Optional, Union
from warnings import warn
import pywikibot
import pywikibot.family
-from pywikibot.backports import List
+from pywikibot.backports import Dict, List
from pywikibot.comms.http import get_authentication
from pywikibot.data import api
from pywikibot.exceptions import (
@@ -109,11 +109,12 @@
def __init__(self, code, fam=None, user=None):
"""Initializer."""
super().__init__(code, fam, user)
- self._msgcache = {}
- self._loginstatus = _LoginStatus.NOT_ATTEMPTED
- self._siteinfo = Siteinfo(self)
- self._paraminfo = api.ParamInfo(self)
+ self._globaluserinfo = {}
self._interwikimap = _InterwikiMap(self)
+ self._loginstatus = _LoginStatus.NOT_ATTEMPTED
+ self._msgcache = {}
+ self._paraminfo = api.ParamInfo(self)
+ self._siteinfo = Siteinfo(self)
self.tokens = TokenWallet(self)
def __getstate__(self):
@@ -450,7 +451,9 @@
To force retrieving userinfo ignoring cache, just delete this
property.
- self._userinfo will be a dict with the following keys and values:
+ .. seealso::
https://www.mediawiki.org/wiki/API:Userinfo
+
+ :return: A dict with the following keys and values:
- id: user id (numeric str)
- name: username (if user is logged in)
@@ -460,7 +463,6 @@
- message: present if user has a new message on talk page
- blockinfo: present if user is blocked (dict)
-
https://www.mediawiki.org/wiki/API:Userinfo
"""
if not hasattr(self, '_userinfo'):
uirequest = self._simple_request(
@@ -481,15 +483,24 @@
@userinfo.deleter
def userinfo(self):
- """Delete cached userinfo."""
+ """Delete cached userinfo.
+
+ ..versionadded:: 5.5
+ """
if hasattr(self, '_userinfo'):
del self._userinfo
- @property
- def globaluserinfo(self):
+ def get_globaluserinfo(self,
+ user: Union[str, int, None] = None,
+ force: bool = False) -> Dict[str, Any]:
"""Retrieve globaluserinfo from site and cache it.
- self._globaluserinfo will be a dict with the following keys and values:
+ .. versionadded:: 7.0
+
+ :param user: The user name or user ID whose global info is
+ retrieved. Defaults to the current user.
+ :param force: Whether the cache should be discarded.
+ :return: A dict with the following keys and values:
- id: user id (numeric str)
- home: dbname of home wiki
@@ -497,36 +508,87 @@
- groups: list of groups (could be empty)
- rights: list of rights (could be empty)
- editcount: global editcount
+
+ :raises TypeError: Inappropriate argument type of 'user'
"""
- if not hasattr(self, '_globaluserinfo'):
- uirequest = self._simple_request(
+ if user is None:
+ user = self.username
+ param = {}
+ elif isinstance(user, str):
+ param = {'guiuser': user}
+ elif isinstance(user, int):
+ param = {'guiid': user}
+ else:
+ raise TypeError("Inappropriate argument type of 'user'
({})"
+ .format(type(user).__name__))
+
+ if force or user not in self._globaluserinfo:
+ param.update(
action='query',
meta='globaluserinfo',
- guiprop='groups|rights|editcount'
+ guiprop='groups|rights|editcount',
)
+ uirequest = self._simple_request(**param)
uidata = uirequest.submit()
assert 'query' in uidata, \
"API userinfo response lacks 'query' key"
assert 'globaluserinfo' in uidata['query'], \
- "API userinfo response lacks 'userinfo' key"
- self._globaluserinfo = uidata['query']['globaluserinfo']
- ts = self._globaluserinfo['registration']
- iso_ts = pywikibot.Timestamp.fromISOformat(ts)
- self._globaluserinfo['registration'] = iso_ts
- return self._globaluserinfo
+ "API userinfo response lacks 'globaluserinfo' key"
+ data = uidata['query']['globaluserinfo']
+ ts = data['registration']
+ data['registration'] = pywikibot.Timestamp.fromISOformat(ts)
+ self._globaluserinfo[user] = data
+ return self._globaluserinfo[user]
- def is_blocked(self):
+ @property
+ def globaluserinfo(self) -> Dict[str, Any]:
+ """Retrieve globaluserinfo of the current user from site.
+
+ To get globaluserinfo for a given user or user ID use
+ :meth:`get_globaluserinfo` method instead
+
+ .. versionadded:: 3.0
"""
- Return True when logged in user is blocked.
+ return self.get_globaluserinfo()
+
+ @globaluserinfo.deleter
+ def globaluserinfo(self):
+ """Delete cached globaluserinfo of current user.
+
+ ..versionadded:: 7.0
+ """
+ with suppress(KeyError):
+ del self._globaluserinfo[self.username]
+
+ def is_blocked(self, force: bool = False) -> bool:
+ """Return True when logged in user is blocked.
To check whether a user can perform an action,
the method has_right should be used.
https://www.mediawiki.org/wiki/API:Userinfo
- :rtype: bool
+ .. versionadded:: 7.0
+ The *force* parameter
+
+ :param force: Whether the cache should be discarded.
"""
+ if force:
+ del self.userinfo
return 'blockinfo' in self.userinfo
+ def is_locked(self,
+ user: Union[str, int, None] = None,
+ force: bool = False) -> bool:
+ """Return True when given user is locked globally.
+
+ .. versionadded:: 7.0
+
+ :param user: The user name or user ID. Defaults to the current
+ user.
+ :param force: Whether the cache should be discarded.
+ """
+ return 'locked' in self.get_globaluserinfo(user, force)
+
def get_searched_namespaces(self, force=False):
"""
Retrieve the default searched namespaces for the user.
diff --git a/scripts/welcome.py b/scripts/welcome.py
index 6009db2..518cd19 100755
--- a/scripts/welcome.py
+++ b/scripts/welcome.py
@@ -768,8 +768,12 @@
return self._randomSignature
def skip_page(self, user) -> bool:
- """Check whether the user is to be skipped."""
- if user.isBlocked():
+ """Check whether the user is to be skipped.
+
+ .. versionchanged:: 7.0
+ also skip if user is locked globally
+ """
+ if user.is_blocked() or user.is_locked():
self.show_status(Msg.SKIP)
pywikibot.output('{} has been blocked!'.format(user.username))
diff --git a/tests/user_tests.py b/tests/user_tests.py
index a8368d1..7485349 100644
--- a/tests/user_tests.py
+++ b/tests/user_tests.py
@@ -56,7 +56,7 @@
self.assertFalse(user.isAnonymous())
self.assertIsInstance(user.registration(), pywikibot.Timestamp)
self.assertGreater(user.editCount(), 0)
- self.assertFalse(user.isBlocked())
+ self.assertFalse(user.is_blocked())
# self.assertTrue(user.isEmailable())
self.assertEqual(user.gender(), 'unknown')
self.assertIn('userid', user.getprops())
@@ -81,6 +81,7 @@
for contrib in contribs))
self.assertIn('user', user.groups())
self.assertIn('edit', user.rights())
+ self.assertFalse(user.is_locked())
def test_registered_user_without_timestamp(self):
"""Test registered user when registration timestamp is
None."""
@@ -155,6 +156,11 @@
'This is an autoblock ID'):
user.getUserTalkPage()
+ def test_locked_user(self):
+ """Test global lock."""
+ user = User(self.site, 'TonjaHeritage2')
+ self.assertTrue(user.is_locked())
+
class TestUserMethods(DefaultSiteTestCase):
--
To view, visit
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/738509
To unsubscribe, or for help writing mail filters, visit
https://gerrit.wikimedia.org/r/settings
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I735b3b46fea82354f9beddbdfe7df0ee9670eba9
Gerrit-Change-Number: 738509
Gerrit-PatchSet: 8
Gerrit-Owner: Xqt <info(a)gno.de>
Gerrit-Reviewer: D3r1ck01 <xsavitar.wiki(a)aol.com>
Gerrit-Reviewer: Framawiki <framawiki(a)tools.wmflabs.org>
Gerrit-Reviewer: Revi <wiki(a)revi.dev>
Gerrit-Reviewer: TheSandDoctor <majorjohn1(a)mail.com>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-CC: Mpaa <mpaa.wiki(a)gmail.com>
Gerrit-MessageType: merged