jenkins-bot has submitted this change and it was merged.
Change subject: [FEAT] Bot: Add Bot subclasses ......................................................................
[FEAT] Bot: Add Bot subclasses
This adds Bot subclasses which implement 'treat_page' and automatically set 'current_page'. Five subclasses check that only certain types of pages are treated.
Change-Id: I80164eaca587d2fc92c8eed6c71440f833412cac --- M pywikibot/__init__.py M pywikibot/bot.py M scripts/capitalize_redirects.py M scripts/cosmetic_changes.py M scripts/create_categories.py M scripts/delete.py 6 files changed, 179 insertions(+), 54 deletions(-)
Approvals: John Vandenberg: Looks good to me, approved jenkins-bot: Verified
diff --git a/pywikibot/__init__.py b/pywikibot/__init__.py index 7fd7983..38ee92c 100644 --- a/pywikibot/__init__.py +++ b/pywikibot/__init__.py @@ -29,7 +29,7 @@ from pywikibot.bot import ( output, warning, error, critical, debug, stdout, exception, input, input_choice, input_yn, inputChoice, handle_args, showHelp, ui, log, - calledModuleName, Bot, WikidataBot, QuitKeyboardInterrupt, + calledModuleName, Bot, CurrentPageBot, WikidataBot, QuitKeyboardInterrupt, # the following are flagged as deprecated on usage handleArgs, ) @@ -70,7 +70,7 @@ 'stdout', 'output', 'warning', 'error', 'critical', 'debug', 'exception', 'input_choice', 'input', 'input_yn', 'inputChoice', 'handle_args', 'handleArgs', 'showHelp', 'ui', 'log', - 'calledModuleName', 'Bot', 'WikidataBot', + 'calledModuleName', 'Bot', 'CurrentPageBot', 'WikidataBot', 'Error', 'InvalidTitle', 'BadTitle', 'NoPage', 'SectionError', 'SiteDefinitionError', 'NoSuchSite', 'UnknownSite', 'UnknownFamily', 'NoUsername', 'UserBlocked', 'UserActionRefuse', diff --git a/pywikibot/bot.py b/pywikibot/bot.py index ef9673b..1b4bb34 100644 --- a/pywikibot/bot.py +++ b/pywikibot/bot.py @@ -1149,6 +1149,135 @@ self.__class__.__name__)
+class CurrentPageBot(Bot): + + """A bot which automatically sets 'current_page' on each treat().""" + + ignore_save_related_errors = True + ignore_server_errors = False + + def treat_page(self): + """Process one page (Abstract method).""" + raise NotImplementedError('Method %s.treat_page() not implemented.' + % self.__class__.__name__) + + def treat(self, page): + """Set page to current page and treat that page.""" + self.current_page = page + self.treat_page() + + def put_current(self, new_text, ignore_save_related_errors=None, + ignore_server_errors=None, **kwargs): + """ + Call L{Bot.userPut} but use the current page. + + It compares the new_text to the current page text. + + @param new_text: The new text + @type new_text: basestring + @param ignore_save_related_errors: Ignore save related errors and + automatically print a message. If None uses this instances default. + @type ignore_save_related_errors: bool or None + @param ignore_server_errors: Ignore server errors and automatically + print a message. If None uses this instances default. + @type ignore_server_errors: bool or None + @param kwargs: Additional parameters directly given to L{Bot.userPut}. + @type kwargs: dict + """ + if ignore_save_related_errors is None: + ignore_save_related_errors = self.ignore_save_related_errors + if ignore_server_errors is None: + ignore_server_errors = self.ignore_server_errors + self.userPut(self.current_page, self.current_page.text, new_text, + ignore_save_related_errors=ignore_save_related_errors, + ignore_server_errors=ignore_server_errors, + **kwargs) + + +class ExistingPageBot(CurrentPageBot): + + """A CurrentPageBot class which only treats existing pages.""" + + def treat(self, page): + """Treat page if it exists and handle NoPage from it.""" + if not page.exists(): + pywikibot.warning('Page "{0}" does not exist on {1}.'.format( + page.title(), page.site)) + return + try: + super(ExistingPageBot, self).treat(page) + except pywikibot.NoPage as e: + if e.page != page: + raise + pywikibot.warning( + 'During handling of page "{0}" on {1} a NoPage exception was ' + 'raised.'.format(page.title(), page.site)) + + +class FollowRedirectPageBot(CurrentPageBot): + + """A CurrentPageBot class which follows the redirect.""" + + def treat(self, page): + """Treat target if page is redirect and the page otherwise.""" + if page.isRedirectPage(): + page = page.getRedirectTarget() + super(FollowRedirectPageBot, self).treat(page) + + +class CreatingPageBot(CurrentPageBot): + + """A CurrentPageBot class which only treats not exisiting pages.""" + + def treat(self, page): + """Treat page if doesn't exist.""" + if page.exists(): + pywikibot.warning('Page "{0}" does already exist on {1}.'.format( + page.title(), page.site)) + return + super(CreatingPageBot, self).treat(page) + + +class RedirectPageBot(CurrentPageBot): + + """A RedirectPageBot class which only treats redirects.""" + + def treat(self, page): + """Treat only redirect pages and handle IsNotRedirectPage from it.""" + if not page.isRedirectPage(): + pywikibot.warning('Page "{0}" on {1} is skipped because it is not ' + 'a redirect'.format(page.title(), page.site)) + return + try: + super(RedirectPageBot, self).treat(page) + except pywikibot.IsNotRedirectPage as e: + if e.page != page: + raise + pywikibot.warning( + 'During handling of page "{0}" on {1} a IsNotRedirectPage ' + 'exception was raised.'.format(page.title(), page.site)) + + +class NoRedirectPageBot(CurrentPageBot): + + """A NoRedirectPageBot class which only treats non-redirects.""" + + def treat(self, page): + """Treat only non-redirect pages and handle IsRedirectPage from it.""" + if page.isRedirectPage(): + pywikibot.warning('Page "{0}" on {1} is skipped because it is a ' + 'redirect'.format(page.title(), page.site)) + return + try: + super(NoRedirectPageBot, self).treat(page) + except pywikibot.IsRedirectPage as e: + if e.page != page: + raise + pywikibot.warning( + 'During handling of page "{0}" on {1} a IsRedirectPage ' + 'exception was raised.'.format(page.title(), page.site)) + + class WikidataBot(Bot):
""" diff --git a/scripts/capitalize_redirects.py b/scripts/capitalize_redirects.py index 6c2422b..f0a27d7 100644 --- a/scripts/capitalize_redirects.py +++ b/scripts/capitalize_redirects.py @@ -33,14 +33,15 @@ #
import pywikibot -from pywikibot import i18n, pagegenerators, Bot +from pywikibot import i18n, pagegenerators +from pywikibot.bot import FollowRedirectPageBot, ExistingPageBot
docuReplacements = { '¶ms;': pagegenerators.parameterHelp }
-class CapitalizeBot(Bot): +class CapitalizeBot(FollowRedirectPageBot, ExistingPageBot):
"""Capitalization Bot."""
@@ -60,18 +61,14 @@ super(CapitalizeBot, self).__init__(**kwargs) self.generator = generator
- def treat(self, page): - """Load the given page and create capitalized redirects.""" - if not page.exists(): - return - if page.isRedirectPage(): - page = page.getRedirectTarget() - page_t = page.title() - self.current_page = page + def treat_page(self): + """Capitalize redirects of the current page.""" + page_t = self.current_page.title() + site = self.current_page.site if self.getOption('titlecase'): - page_cap = pywikibot.Page(page.site, page_t.title()) + page_cap = pywikibot.Page(site, page_t.title()) else: - page_cap = pywikibot.Page(page.site, page_t.capitalize()) + page_cap = pywikibot.Page(site, page_t.capitalize()) if page_cap.exists(): pywikibot.output(u'%s already exists, skipping...\n' % page_cap.title(asLink=True)) @@ -86,12 +83,12 @@ self.options['always'] = True if self.getOption('always') or choice == 'y': comment = i18n.twtranslate( - page.site, + site, 'capitalize_redirects-create-redirect', {'to': page_t}) - page_cap.text = u"#%s %s" % (page.site.redirect(), - page.title(asLink=True, - textlink=True)) + page_cap.text = u"#%s %s" % (site.redirect(), + self.current_page.title( + asLink=True, textlink=True)) try: page_cap.save(comment) except: diff --git a/scripts/cosmetic_changes.py b/scripts/cosmetic_changes.py index 5b90caa..3d5f5b2 100755 --- a/scripts/cosmetic_changes.py +++ b/scripts/cosmetic_changes.py @@ -77,7 +77,8 @@ from pywikibot.tools import MediaWikiVersion import pywikibot import isbn -from pywikibot import config, i18n, textlib, pagegenerators, Bot +from pywikibot import config, i18n, textlib, pagegenerators +from pywikibot.bot import ExistingPageBot, NoRedirectPageBot from pywikibot.page import url2unicode from pywikibot.tools import deprecate_arg
@@ -194,6 +195,12 @@
self.fixArabicLetters, ) + + @classmethod + def from_page(cls, page, diff, ignore): + """Create toolkit based on the page.""" + return cls(page.site, diff=diff, namespace=page.namespace(), + pageTitle=page.title(), ignore=ignore)
def safe_execute(self, method, text): """Execute the method and catch exceptions if enabled.""" @@ -891,7 +898,7 @@ return text
-class CosmeticChangesBot(Bot): +class CosmeticChangesBot(ExistingPageBot, NoRedirectPageBot):
"""Cosmetic changes bot."""
@@ -905,29 +912,22 @@
self.generator = generator
- def treat(self, page): + def treat_page(self): + """Treat page with the cosmetic toolkit.""" try: - self.current_page = page - ccToolkit = CosmeticChangesToolkit(page.site, diff=False, - namespace=page.namespace(), - pageTitle=page.title(), - ignore=self.getOption('ignore')) - changedText = ccToolkit.change(page.get()) + ccToolkit = CosmeticChangesToolkit.from_page( + self.current_page, True, self.getOption('ignore')) + changedText = ccToolkit.change(self.current_page.get()) if changedText is not False: - self.userPut(page, page.text, changedText, - comment=self.getOption('comment'), - async=self.getOption('async')) - except pywikibot.NoPage: - pywikibot.output("Page %s does not exist?!" - % page.title(asLink=True)) - except pywikibot.IsRedirectPage: - pywikibot.output("Page %s is a redirect; skipping." - % page.title(asLink=True)) + self.put_current(newtext=changedText, + comment=self.getOption('comment'), + async=self.getOption('async')) except pywikibot.LockedPage: - pywikibot.output("Page %s is locked?!" % page.title(asLink=True)) + pywikibot.output("Page %s is locked?!" + % self.current_page.title(asLink=True)) except pywikibot.EditConflict: pywikibot.output("An edit conflict has occured at %s." - % page.title(asLink=True)) + % self.current_page.title(asLink=True))
def main(*args): diff --git a/scripts/create_categories.py b/scripts/create_categories.py index f6ef329..90f2536 100755 --- a/scripts/create_categories.py +++ b/scripts/create_categories.py @@ -47,7 +47,8 @@ self.basename = basename self.comment = u'Creating new category'
- def create_category(self, page): + def treat(self, page): + """Create category in commons for that page.""" title = page.title(withNamespace=False)
newpage = pywikibot.Category(pywikibot.Site('commons', 'commons'), @@ -69,10 +70,6 @@ else: # FIXME: Add overwrite option pywikibot.output(u'%s already exists, skipping' % newpage.title()) - - def run(self): - for page in self.generator: - self.create_category(page)
def main(*args): diff --git a/scripts/delete.py b/scripts/delete.py index 93f6f8a..870fad3 100644 --- a/scripts/delete.py +++ b/scripts/delete.py @@ -34,7 +34,7 @@ #
import pywikibot -from pywikibot import i18n, pagegenerators, Bot +from pywikibot import i18n, pagegenerators, CurrentPageBot
# This is required for the text that is shown when you run this script # with the parameter -help. @@ -43,7 +43,7 @@ }
-class DeletionRobot(Bot): +class DeletionRobot(CurrentPageBot):
""" This robot allows deletion of pages en masse. """
@@ -63,20 +63,22 @@
self.summary = summary
- def treat(self, page): + def treat_page(self): """Process one page from the generator.""" - self.current_page = page if self.getOption('undelete'): - if page.exists(): - pywikibot.output(u'Skipping: %s already exists.' % page) + if self.current_page.exists(): + pywikibot.output(u'Skipping: {0} already exists.'.format( + self.current_page)) else: - page.undelete(self.summary) + self.current_page.undelete(self.summary) else: - if page.exists(): - page.delete(self.summary, not self.getOption('always'), - self.getOption('always')) + if self.current_page.exists(): + self.current_page.delete(self.summary, + not self.getOption('always'), + self.getOption('always')) else: - pywikibot.output(u'Skipping: %s does not exist.' % page) + pywikibot.output(u'Skipping: {0} does not exist.'.format( + self.current_page))
def main(*args):