From 322086b2d0921d4ee1d80d2ba33673a3a6e72b5e Mon Sep 17 00:00:00 2001 From: xqt Date: Thu, 29 Aug 2024 11:23:54 +0200 Subject: [PATCH] [IMPR] Add hints if an account is member of bot group but has no bot right - drop 'None' argument for bot parameter in BasePage.save() and BasePage.put() because it is useless to assume different behaviour for True and None values; edit bot flags only works with bot right. - add a hint to docstring that bot right is required for BotPassword and OAuth - catch arguments in BasePage._save from kwargs and pass them to Site.editpage() - deprecate 'None' argument for bot parameter in APISite.editpage() - show a warning if an account is member of the bot group but does not have the bot right granted (usually for OAuth and BotPassword) - update tests Bug: T373514 Change-Id: I9738c63779acc236750a3323427b70ec52745e8e --- pywikibot/page/_basepage.py | 36 ++++++++++++++++++++++++------------ pywikibot/site/_apisite.py | 16 +++++++++++++++- tests/deletionbot_tests.py | 4 ++-- tests/page_tests.py | 2 +- 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/pywikibot/page/_basepage.py b/pywikibot/page/_basepage.py index f6b1bab9c3..beaf75e4aa 100644 --- a/pywikibot/page/_basepage.py +++ b/pywikibot/page/_basepage.py @@ -1285,20 +1285,30 @@ def save(self, summary: str | None = None, watch: str | None = None, minor: bool = True, - bot: bool | None = None, + bot: bool = True, force: bool = False, asynchronous: bool = False, callback=None, apply_cosmetic_changes: bool | None = None, quiet: bool = False, **kwargs): - """ - Save the current contents of page's text to the wiki. + """Save the current contents of page's text to the wiki. .. versionchanged:: 7.0 boolean *watch* parameter is deprecated .. versionchanged:: 9.3 *botflag* parameter was renamed to *bot*. + .. versionchanged:: 9.4 + edits cannot be marked as bot edits if the bot account has no + ``bot`` right. Therefore a ``None`` argument for *bot* + parameter was dropped. + + .. hint:: Setting up :manpage:`OAuth` or :manpage:`BotPassword + ` login, you have to grant + ``High-volume (bot) access`` to get ``bot`` right even if the + account is member of the bots group granted by bureaucrats. + Otherwise edits cannot be marked with both flag and *bot* + argument will be ignored. .. seealso:: :meth:`APISite.editpage ` @@ -1313,10 +1323,11 @@ def save(self, * unwatch --- remove the page from the watchlist * preferences --- use the preference settings (Default) * nochange --- don't change the watchlist + If None (default), follow bot account's default settings :param minor: if True, mark this edit as minor - :param bot: if True, mark this edit as made by a bot (default: - True if user has bot status, False if not) + :param bot: if True, mark this edit as made by a bot if user has + ``bot`` right (default), if False do not mark it as bot edit. :param force: if True, ignore botMayEdit() setting :param asynchronous: if True, launch a separate thread to save asynchronously @@ -1351,15 +1362,13 @@ def save(self, cc=apply_cosmetic_changes, quiet=quiet, **kwargs) @allow_asynchronous - def _save(self, summary=None, watch=None, minor: bool = True, bot=None, - cc=None, quiet: bool = False, **kwargs): + def _save(self, summary=None, cc=None, quiet: bool = False, **kwargs): """Helper function for save().""" link = self.title(as_link=True) if cc or (cc is None and config.cosmetic_changes): summary = self._cosmetic_changes_hook(summary) - done = self.site.editpage(self, summary=summary, minor=minor, - watch=watch, bot=bot, **kwargs) + done = self.site.editpage(self, summary=summary, **kwargs) if not done: if not quiet: pywikibot.warning(f'Page {link} not saved') @@ -1414,14 +1423,13 @@ def put(self, newtext: str, summary: str | None = None, watch: str | None = None, minor: bool = True, - bot: bool | None = None, + bot: bool = True, force: bool = False, asynchronous: bool = False, callback=None, show_diff: bool = False, **kwargs) -> None: - """ - Save the page with the contents of the first argument as the text. + """Save the page with the contents of the first argument as the text. This method is maintained primarily for backwards-compatibility. For new code, using :meth:`save` is preferred; also ee that @@ -1431,6 +1439,10 @@ def put(self, newtext: str, The `show_diff` parameter .. versionchanged:: 9.3 *botflag* parameter was renamed to *bot*. + .. versionchanged:: 9.4 + edits cannot be marked as bot edits if the bot account has no + ``bot`` right. Therefore a ``None`` argument for *bot* + parameter was dropped. .. seealso:: :meth:`save` diff --git a/pywikibot/site/_apisite.py b/pywikibot/site/_apisite.py index e73349592f..2a3ec9cf1d 100644 --- a/pywikibot/site/_apisite.py +++ b/pywikibot/site/_apisite.py @@ -15,6 +15,7 @@ from contextlib import suppress from textwrap import fill from typing import TYPE_CHECKING, Any, NamedTuple, TypeVar +from warnings import warn import pywikibot from pywikibot import login @@ -2031,7 +2032,8 @@ def editpage( * nochange --- don't change the watchlist If None (default), follow bot account's default settings - :param bot: if True, mark edit with bot flag + :param bot: if True and bot right is given, mark edit with bot + flag :keyword str text: Overrides Page.text :keyword int | str section: Edit an existing numbered section or @@ -2109,7 +2111,19 @@ def editpage( token = self.tokens['csrf'] if bot is None: + issue_deprecation_warning("'None' argument for 'bot' parameter", + "'True' value", since='9.4.0') + bot = True + + if bot: bot = self.has_right('bot') + # show a warning if user is a bot member but hasn't bot right + if not bot and 'bot' in self.userinfo['groups']: + msg = '\n' + fill( + f"{self.user()} is within 'bot' group but 'bot' right" + " wasn't activated with OAuth or BotPassword settings" + ) + warn(msg) params = dict( action='edit', diff --git a/tests/deletionbot_tests.py b/tests/deletionbot_tests.py index eeec90e445..12a2849052 100755 --- a/tests/deletionbot_tests.py +++ b/tests/deletionbot_tests.py @@ -44,7 +44,7 @@ def test_undelete_existing(self): p1 = pywikibot.Page(site, 'User:Unicodesnowman/ExistingPage') if not p1.exists(): p1.text = 'pywikibot unit test page' - p1.save('unit test', bot=True) + p1.save('unit test') delete.main('-page:User:Unicodesnowman/ExistingPage', '-always', '-undelete', '-summary:pywikibot unit tests') @@ -76,7 +76,7 @@ def tearDownClass(cls): def save_page(cls): """Reset the test page content.""" cls.page.text = 'Pywikibot deletion test.' - cls.page.save('Pywikibot unit test', bot=True) + cls.page.save('Pywikibot unit test') @unittest.expectedFailure # T367299 def test_delete_mark(self): diff --git a/tests/page_tests.py b/tests/page_tests.py index a84ea05f73..0651e34d10 100755 --- a/tests/page_tests.py +++ b/tests/page_tests.py @@ -1077,7 +1077,7 @@ def test_delete(self): p = pywikibot.Page(site, 'User:Unicodesnowman/DeleteTest') # Ensure the page exists p.text = 'pywikibot unit test page' - p.save('Pywikibot unit test', bot=True) + p.save('Pywikibot unit test') # Test deletion res = p.delete(reason='Pywikibot unit test', prompt=False, mark=False)