#!/usr/bin/env python3"""This bot goes over multiple pages of a wiki, and edits them without changes.This is for example used to get category links in templates working.Command-line arguments:-purge Purge the page instead of touching it*Touch* mode (default):-botflag Force botflag in case of edits with changes.*Purge* mode:-converttitles Convert titles to other variants if necessary-forcelinkupdate Update the links tables-forcerecursivelinkupdate Update the links table, and update the links tables for any page that uses this page as a template-redirects Automatically resolve redirects¶ms;"""## (C) Pywikibot team, 2009-2024## Distributed under the terms of the MIT license.#from__future__importannotationsfromcollectionsimportdefaultdictfromcontextlibimportsuppressimportpywikibotfrompywikibotimportconfig,pagegeneratorsfrompywikibot.botimportMultipleSitesBotfrompywikibot.exceptionsimport(LockedPageError,NoCreateError,NoPageError,PageSaveRelatedError,)docuReplacements={'¶ms;':pagegenerators.parameterHelp}# noqa: N816
[docs]deftreat(self,page)->None:"""Touch the given page."""try:page.touch(bot=self.opt.botflag)except(NoCreateError,NoPageError):pywikibot.error(f'Page {page.title(as_link=True)} does not exist.')exceptLockedPageError:pywikibot.error(f'Page {page.title(as_link=True)} is locked.')exceptPageSaveRelatedErrorase:pywikibot.error(f'Page {page} not saved:\n{e.args}')else:self.counter['touch']+=1
[docs]classPurgeBot(MultipleSitesBot):"""Purge each page on the generator."""available_options={'converttitles':None,'forcelinkupdate':None,'forcerecursivelinkupdate':None,'redirects':None}def__init__(self,*args,**kwargs):"""Initializer."""super().__init__(*args,**kwargs)self.pages=defaultdict(list)self.limit={}
[docs]deftreat(self,page)->None:"""Purge the given page. .. versionchanged:: 8.0 Enable batch purge using :meth:`APISite.purgepages() <pywikibot.site._apisite.APISite.purgepages>` """# We can have multiple sites, save pages and cache rate limitself.pages[page.site].append(page)self.limit.setdefault(page.site,page.site.ratelimit('purge'))self.purgepages()
[docs]defteardown(self):"""Purge remaining pages if no KeyboardInterrupt was made. .. versionadded:: 8.0 """ifself.generator_completed:withsuppress(KeyboardInterrupt):self.purgepages(flush=True)# show the counter even no purges were madeself.counter['purge']+=0
[docs]defpurgepages(self,flush=False):"""Purge a bulk of page if rate limit exceeded. .. versionadded:: 8.0 .. versionchanged:: 9.0 :meth:`site.APISite.ratelimit() <pywikibot.site._apisite.APISite.ratelimit>` method is used to determine bulk length and delay. """forsite,pagelistinself.pages.items():length=len(pagelist)ifflushorlength>=self.limit[site].hits:done=site.purgepages(pagelist,**self.opt)ifdone:self.counter['purge']+=lengthself.pages[site].clear()pywikibot.info(f"{length} pages{''ifdoneelse' not'} purged")ifnotflushandconfig.simulateisFalse:delay=self.limit[site].delay*(length+1)ifdelay:pywikibot.info(f'Waiting {delay} seconds due to purge rate limit')pywikibot.sleep(delay)
[docs]defmain(*args:str)->None:"""Process command line arguments and invoke bot. If args is an empty list, sys.argv is used. :param args: command line arguments """options={}unknown=[]# Process global and pagegenerators argslocal_args=pywikibot.handle_args(args)gen_factory=pagegenerators.GeneratorFactory()local_args=gen_factory.handle_args(local_args)bot_class=TouchBotforarginlocal_args:option=arg[1:]ifarg=='-purge':bot_class=PurgeBotelifarg.startswith('-'):options[option.lower()]=Trueelse:unknown.append(arg)ifnotpywikibot.bot.suggest_help(missing_generator=notgen_factory.gens,unknown_parameters=unknown):pywikibot.Site().login()gen=gen_factory.getCombinedGenerator(preload=bot_class==TouchBot)bot_class(generator=gen,**options).run()