Xqt has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/906547 )
Change subject: [bugfix] No longer lazy load cookies ......................................................................
[bugfix] No longer lazy load cookies
Lazy load of cookies was introduced with ba56084 when cookie files for each user was introduced because the username was needed first load the cookie. But this change needs an explicit login() call and was a regression against Pywikibot 7.6.
- always make a cookie-only login when a Site was initialzed - try to login if API response is 'notloggedin'; this is the same behaviour as for 'readapidenied'
Bug: T331315 Bug: T330488 Bug: T329132 Bug: T326779 Bug: T271858 Change-Id: I34caa567b883a5d0ae81eea5250fae01fcb29554 --- M tests/utils.py M pywikibot/site/_apisite.py M pywikibot/data/api/_requests.py 3 files changed, 67 insertions(+), 23 deletions(-)
Approvals: Xqt: Verified; Looks good to me, approved
diff --git a/pywikibot/data/api/_requests.py b/pywikibot/data/api/_requests.py index bbd5744..3c7bbc6 100644 --- a/pywikibot/data/api/_requests.py +++ b/pywikibot/data/api/_requests.py @@ -938,8 +938,11 @@ return True
def submit(self) -> dict: - """ - Submit a query and parse the response. + """Submit a query and parse the response. + + .. versionchanged:: 8.1 + in addition to *readapidenied* also try to login when API + response is *notloggedin*.
:return: a dict containing data retrieved from api.php """ @@ -1033,8 +1036,8 @@ self._ratelimited() continue
- # If readapidenied is returned try to login - if code == 'readapidenied' \ + # If notloggedin or readapidenied is returned try to login + if code in ('notloggedin', 'readapidenied') \ and self.site._loginstatus in (LoginStatus.NOT_ATTEMPTED, LoginStatus.NOT_LOGGED_IN): self.site.login() diff --git a/pywikibot/site/_apisite.py b/pywikibot/site/_apisite.py index ae8bb42..673d619 100644 --- a/pywikibot/site/_apisite.py +++ b/pywikibot/site/_apisite.py @@ -118,11 +118,13 @@ super().__init__(code, fam, user) self._globaluserinfo: Dict[Union[int, str], Any] = {} self._interwikimap = _InterwikiMap(self) - self._loginstatus = login.LoginStatus.NOT_ATTEMPTED self._msgcache: Dict[str, str] = {} self._paraminfo = api.ParamInfo(self) self._siteinfo = Siteinfo(self) self._tokens = TokenWallet(self) + self._loginstatus = login.LoginStatus.NOT_ATTEMPTED + with suppress(SiteDefinitionError): + self.login(cookie_only=True)
def __getstate__(self) -> Dict[str, Any]: """Remove TokenWallet before pickling, for security reasons.""" @@ -324,12 +326,17 @@ def login( self, autocreate: bool = False, - user: Optional[str] = None + user: Optional[str] = None, + *, + cookie_only: bool = False ) -> None: """Log the user in if not already logged in.
.. versionchanged:: 8.0 - lazy load cookies when logging in. + lazy load cookies when logging in. This was dropped in 8.1 + .. versionchanged:: 8.1 + the *cookie_only* parameter was added and cookies are loaded + whenever the site is initialized.
.. seealso:: :api:`Login`
@@ -337,6 +344,8 @@ using unified login :param user: bot user name. Overrides the username set by BaseSite initializer parameter or user config setting + :param cookie_only: Only try to login from cookie but do not + force to login with username/password settings.
:raises pywikibot.exceptions.NoUsernameError: Username is not recognised by the site. @@ -404,23 +413,22 @@
raise NoUsernameError(error_msg)
- login_manager = login.ClientLoginManager(site=self, - user=self.username()) - if login_manager.login(retry=True, autocreate=autocreate): - self._username = login_manager.username - del self.userinfo # force reloading + if not cookie_only: + login_manager = login.ClientLoginManager(site=self, + user=self.username()) + if login_manager.login(retry=True, autocreate=autocreate): + self._username = login_manager.username + del self.userinfo # force reloading
- # load userinfo - if self.userinfo['name'] == self.username(): - self._loginstatus = login.LoginStatus.AS_USER - return + # load userinfo + if self.userinfo['name'] == self.username(): + self._loginstatus = login.LoginStatus.AS_USER + return
- pywikibot.error('{} != {} after {}.login() and successful ' - '{}.login()' - .format(self.userinfo['name'], - self.username(), - type(self).__name__, - type(login_manager).__name__)) + pywikibot.error( + f"{self.userinfo['name']} != {self.username()} after " + f'{type(self).__name__}.login() and successful ' + f'{type(login_manager).__name__}.login()')
self._loginstatus = login.LoginStatus.NOT_LOGGED_IN # failure
@@ -538,7 +546,8 @@ assert 'userinfo' in uidata['query'], \ "API userinfo response lacks 'userinfo' key" self._userinfo = uidata['query']['userinfo'] - if 'anon' in self._userinfo or not self._userinfo.get('id'): + if self._loginstatus != login.LoginStatus.IN_PROGRESS \ + and ('anon' in self._userinfo or not self._userinfo.get('id')): pywikibot.warning('No user is logged in on site {}' .format(self)) return self._userinfo diff --git a/tests/utils.py b/tests/utils.py index c71658d..38c4105 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -400,6 +400,15 @@ interface=DryDataSite) return None
+ def login(self, *args, cookie_only=False, **kwargs): + """Overwrite login which is called when a site is initialized. + + .. versionadded: 8.1 + """ + if cookie_only: + return + raise Exception(f'Attempting to login with {type(self).__name__}') +
class DryDataSite(DrySite, pywikibot.site.DataSite):