jenkins-bot has submitted this change and it was merged.
Change subject: [FEAT] Request: Recover from bad tokens ......................................................................
[FEAT] Request: Recover from bad tokens
When a badtoken error happens it checks all parameters if one of them is using a cached token value and then buffers the type for that the token value is used. It then rerequests all tokens for the buffered types and is then changing those parameters to have the new value.
Bug: T61678 Change-Id: I0c2f7b3e8726e26c68651bd5714f6f42d1f3bedf --- M pywikibot/data/api.py M tests/api_tests.py 2 files changed, 51 insertions(+), 0 deletions(-)
Approvals: John Vandenberg: Looks good to me, approved jenkins-bot: Verified
diff --git a/pywikibot/data/api.py b/pywikibot/data/api.py index b57a61d..a9d30a6 100644 --- a/pywikibot/data/api.py +++ b/pywikibot/data/api.py @@ -1688,6 +1688,39 @@ if code == 'readapidenied' and self.site._loginstatus in (-3, -1): self.site.login() continue + if code == 'badtoken': + user_tokens = self.site.tokens._tokens[self.site.user()] + # all token values mapped to their type + tokens = dict((token, t_type) + for t_type, token in user_tokens.items()) + # determine which tokens are bad + invalid_param = {} + for name, param in self._params.items(): + if len(param) == 1 and param[0] in tokens: + invalid_param[name] = tokens[param[0]] + # doesn't care about the cache so can directly load them + if invalid_param: + pywikibot.log( + u'Bad token error for {0}. Tokens for "{1}" used in ' + u'request; invalidated them.'.format( + self.site.user(), + '", "'.join(sorted(set(invalid_param.values()))))) + self.site.tokens.load_tokens(set(invalid_param.values())) + # fix parameters; lets hope that it doesn't mistake actual + # parameters as tokens + for name, t_type in invalid_param.items(): + self[name] = self.site.tokens[t_type] + continue + else: + # otherwise couldn't find any … weird there is nothing what + # can be done here because it doesn't know which parameters + # to fix + pywikibot.log( + u'Bad token error for {0} but no parameter is using a ' + u'token. Current tokens: {1}'.format( + self.site.user(), + ', '.join('{0}: {1}'.format(*e) + for e in user_tokens.items()))) # raise error try: pywikibot.log(u"API Error: query=\n%s" diff --git a/tests/api_tests.py b/tests/api_tests.py index d827f9c..897340e 100644 --- a/tests/api_tests.py +++ b/tests/api_tests.py @@ -683,6 +683,24 @@ self.assertRaises(pywikibot.NoUsername, req.submit)
+class TestBadTokenRecovery(TestCase): + + """Test that the request recovers from bad tokens.""" + + family = 'wikipedia' + code = 'test' + + write = True + + def test_bad_token(self): + site = self.get_site() + site.tokens._tokens.setdefault(site.user(), {})['edit'] = 'INVALID' + page = pywikibot.Page(site, 'Pywikibot bad token test') + page.text = ('This page is testing whether pywikibot-core rerequests ' + 'a token when a badtoken error was received.') + page.save(comment='Bad token test') + + if __name__ == '__main__': try: unittest.main()
pywikibot-commits@lists.wikimedia.org