Source code for pywikibot.site._tokenwallet

"""Objects representing api tokens."""
#
# (C) Pywikibot team, 2008-2023
#
# Distributed under the terms of the MIT license.
#
from __future__ import annotations

from collections.abc import Container
from typing import TYPE_CHECKING, Any

from pywikibot.tools import deprecated, issue_deprecation_warning


if TYPE_CHECKING:
    from pywikibot.site import APISite


[docs] class TokenWallet(Container): """Container for tokens. You should not use this container class directly; use :attr:`APISite.tokens<pywikibot.site._apisite.APISite.tokens>` instead which gives access to the site's TokenWallet instance. """ def __init__(self, site: APISite) -> None: """Initializer.""" self.site: APISite = site self._tokens: dict[str, str] = {} self._currentuser: str | None = site.user() # guess the needed token in update_tokens self._last_token_key: str | None = None def __getitem__(self, key: str) -> str: """Get token value for the given key.""" if self.site.user() is None and key != 'login': self.site.login() if self.site.user() != self._currentuser: self._currentuser = self.site.user() self.clear() if not self._tokens: self._tokens = self.site.get_tokens([]) # Redirect old tokens which were used by outdated MediaWiki versions # but show a FutureWarning for this usage: # https://www.mediawiki.org/wiki/MediaWiki_1.37/Deprecation_of_legacy_API_token_parameters if key in {'edit', 'delete', 'protect', 'move', 'block', 'unblock', 'email', 'import', 'options'}: issue_deprecation_warning( f'Token {key!r}', "'csrf'", since='8.0.0') key = 'csrf' try: token = self._tokens[key] except KeyError: raise KeyError( f'Invalid token {key!r} for user {self._currentuser!r} on ' f'{self.site} wiki.') from None self._last_token_key = key return token def __contains__(self, key) -> bool: """Return True if the token name is cached for the current user.""" try: self[key] except KeyError: return False return True def __str__(self) -> str: """Return a str representation of the internal tokens dictionary.""" return str(self._tokens) def __repr__(self) -> str: """Return a representation of the TokenWallet. >>> import pywikibot >>> site = pywikibot.Site('wikipedia:test') >>> repr(site.tokens) "TokenWallet(pywikibot.Site('wikipedia:test'))" .. versionchanged:: 8.0 Provide a string which looks like a valid Python expression. """ user = f', user={self._currentuser!r}' if self._currentuser else '' return (f'{type(self).__name__}' f'(pywikibot.Site({self.site.sitename!r}{user}))')
[docs] def clear(self): """Clear the self._tokens cache. Tokens are reloaded when needed. .. versionadded:: 8.0 """ self._tokens.clear()
[docs] def update_tokens(self, tokens: list[str]) -> list[str]: """Return a list of new tokens for a given list of tokens. This method can be used if a token is outdated and has to be renewed but the token type is unknown and we only have the old token. It first gets the token names from all given tokens, clears the cache and returns fresh new tokens of the found types. **Usage:** >>> import pywikibot >>> site = pywikibot.Site() >>> tokens = [site.tokens['csrf']] # doctest: +SKIP >>> new_tokens = site.tokens.update_tokens(tokens) # doctest: +SKIP .. code-block:: Python :caption: An example for replacing request token parameters r._params['token'] = r.site.tokens.update_tokens(r._params['token']) .. versionadded:: 8.0 """ # find the token types types = [key for key, value in self._tokens.items() for token in tokens if value == token] or [self._last_token_key] self.clear() # clear the cache return [self[token_type] for token_type in types]
[docs] @deprecated('clear()', since='8.0.0') def load_tokens(self, *args: Any, **kwargs: Any) -> None: """Clear cache to lazy load tokens when needed. .. deprecated:: 8.0 Use :meth:`clear` instead. .. versionchanged:: 8.0 Clear the cache instead of loading tokens. All parameters are ignored. """ self.clear()