Revision: 7849
Author:   russblau
Date:     2009-12-31 17:56:33 +0000 (Thu, 31 Dec 2009)

Log Message:
-----------
Port redirect.py to rewrite branch; to do this, some options had to be removed 
and some command-line arguments changed.  Because this is a port rather than a 
newly-written script, it may contain some unused variables/methods and could 
benefit from refactoring.

Added Paths:
-----------
    branches/rewrite/scripts/redirect.py

Added: branches/rewrite/scripts/redirect.py
===================================================================
--- branches/rewrite/scripts/redirect.py                                (rev 0)
+++ branches/rewrite/scripts/redirect.py        2009-12-31 17:56:33 UTC (rev 
7849)
@@ -0,0 +1,792 @@
+# -*- coding: utf-8 -*-
+"""
+Script to resolve double redirects, and to delete broken redirects. Requires
+access to MediaWiki's maintenance pages or to a XML dump file. Delete
+function requires adminship.
+
+Syntax:
+
+    python redirect.py action [-arguments ...]
+
+where action can be one of these:
+
+double         Fix redirects which point to other redirects
+broken         Delete redirects where targets don\'t exist. Requires adminship.
+both           Both of the above. Permitted only with -api. Implies -api.
+
+and arguments can be:
+
+-moves         Use the page move log to find double-redirect candidates. Only
+               works with action "double".
+
+-namespace:n   Namespace to process. Can be given multiple times, for several
+               namespaces.  If omitted, only the main (article) namespace is
+               treated.
+
+-offset:n      With -moves, the number of hours ago to start scanning moved
+               pages. Otherwise, ignored.
+
+-start:title   The starting page title in each namespace. Page need not exist.
+
+-until:title   The possible last page title in each namespace. Page needs not
+               exist.
+
+-total:n       The maximum count of redirects to work upon. If omitted, there
+               is no limit.
+
+-always        Don't prompt you for each replacement.
+
+"""
+
+# XML not yet implemented: deleted help text follows
+##-xml           Retrieve information from a local XML dump
+##               (http://download.wikimedia.org). Argument can also be given as
+##               "-xml:filename.xml". Cannot be used with -api or -moves.
+##               If neither of -xml -api -moves is given, info will be loaded
+##               from a special page of the live wiki.
+
+#
+# (C) Daniel Herding, 2004.
+#     Purodha Blissenbach, 2009.
+#
+# Distributed under the terms of the MIT license.
+#
+#
+import pywikibot
+from pywikibot import config
+# import xmlreader
+import re, sys
+
+__version__='$Id: redirect.py 7789 2009-12-17 19:20:12Z xqt $'
+
+# Summary message for fixing double redirects
+msg_double={
+    'als':u'Bötli: Uflösig vun de doppleti Wyterleitig zue %s',
+    'ar': u'روبوت: تصليح تحويلة مزدوجة → %s',
+    'bat-smg': u'Robots: Taisuoms dvėgobs paradresavėms → %s',
+    'be-x-old': u'Робат: выпраўленьне падвойнага перанакіраваньня → %s',
+    'br': u'Kempennet adkas doubl gant robot → %s',
+    'cs': u'Robot opravil dvojité přesměrování → %s',
+    'de': u'Bot: Korrigiere doppelte Weiterleitung zu %s',
+    'en': u'Robot: Fixing double redirect to %s',
+    'es': u'Robot: Arreglando doble redirección → %s',
+    'fa': u'ربات:اصلاح تغییر مسیر دوتایی → %s',
+    'fi': u'Botti korjasi kaksinkertaisen ohjauksen → %s',
+    'fr': u'Robot: répare double redirection à %s',
+    'ga': u'Róbó: Ag socrú athsheolta dúbailte → %s',
+    'he': u'בוט: מתקן הפניה כפולה → %s',
+    'hr': u'Bot: Popravak dvostrukih preusmjeravanja → %s',
+    'ia': u'Robot: reparation de duple redirection → %s',
+    'is': u'Vélmenni: Lagfæri tvöfalda tilvísun → %s',
+    'it': u'Bot: Sistemo i redirect doppi a %s',
+    'ja': u'ロボットによる: 二重リダイレクト修正 → %s',
+    'ka': u'რობოტი: ორმაგი გადამისამართების გასწორება → %s',
+    'ko': u'로봇: 이중 넘겨주기 수정 → %s',
+    'kk': u'Бот: Шынжырлы айдатуды түзетті → %s',
+    'ksh':u'Bot: [[special:doubleredirects|Dubbel Ömlëijdong]] fottjemaat → 
%s',
+    'lb': u'Bot: Duebel Viruleedung gefléckt → %s',
+    'lt': u'robotas: Taisomas dvigubas peradresavimas → %s',
+    'mk': u'Бот: Исправка на двојни пренасочувања → %s',
+    'nds':u'Bot: Dubbelte Wiederleiden rutmakt → %s',
+    'nl': u'Bot: dubbele doorverwijzing gecorrigeerd aan %s',
+    'nn': u'robot: retta dobbel omdirigering → %s',
+    'no': u'bot: Retter dobbel omdirigering → %s',
+    'pl': u'Robot naprawia podwójne przekierowanie → %s',
+    'pt': u'Bot: Corrigido duplo redirecionamento → %s',
+    'ru': u'Робот: исправление двойного перенаправления → %s',
+    'sr': u'Бот: Поправка дуплих преусмерења → %s',
+    'sv': u'Robot: Rättar dubbel omdirigering → %s',
+    'szl':u'Robot sprowjo tuplowane przekerowańa → %s',
+    'th': u'โรบอต: แก้หน้าเปลี่ยนทางซ้ำซ้อน → %s',
+    'tr': u'Bot değişikliği: Yönlendirmeye olan yönlendirme → %s',
+    'uk': u'Робот: виправлення подвійного перенаправлення → %s',
+    'war':u'Robot: Gin-ayad in nagduduha nga redirek → %s',
+    'yi': u'באט: פארראכטן פארטאפלטע ווייטערפירונג → %s',
+    'zh': u'機器人:修正雙重重定向 → %s',
+    'zh-yue': u'機械人:拉直連串跳轉 → %s',
+    'zh-classical': u'僕:復修渡口 → %s',
+}
+
+# Reason for deleting broken redirects
+reason_broken={
+    'ar': u'روبوت: هدف التحويلة غير موجود',
+    'be-x-old': u'Робат: мэта перанакіраваньня не існуе',
+    'cs': u'Přerušené přesměrování',
+    'de': u'Bot: Weiterleitungsziel existiert nicht',
+    'en': u'[[WP:CSD#G8|G8]]: [[Wikipedia:Redirect|Redirect]] to a deleted or 
non-existent page',
+    'es': u'Robot: La página a la que redirige no existe',
+    'fa': u'ربات:تغییرمسیر مقصد ندارد',
+    'fi': u'Botti: Ohjauksen kohdesivua ei ole olemassa',
+    'fr': u'Robot : Cible du redirect inexistante',
+    'ga': u'Róbó : Targaid athsheoladh ar iarraidh',
+    'he': u'בוט: יעד ההפניה אינו קיים',
+    'it': u'Bot: Il redirect indirizza ad una pagina inesistente',
+    'ja': u'ロボットによる:リダイレクトの目標は存在しませんでした',
+    'ka': u'რობოტი: გადამისამართებული გვერდი არ არსებობს',
+    'ko': u'로봇: 끊긴 넘겨주기',
+    'kk': u'Бот: Айдату нысанасы жоқ болды',
+    'ksh':u'Bot: Dė [[Special:BrokenRedirects|Ömlëijdong jingk ennet Liiere]]',
+    'lt': u'robotas: Peradresavimas į niekur',
+    'nds':u'Bot: Kaputte Wiederleiden rutmakt',
+    'nl': u'Bot: doelpagina doorverwijzing bestaat niet',
+    'nn': u'robot: målet for omdirigeringa eksisterer ikkje',
+    'no': u'robot: målet for omdirigeringen eksisterer ikke',
+    'pl': u'Robot: cel przekierowania nie istnieje',
+    'pt': u'Bot: Redirecionamento não existe',
+    'ru': u'Робот: перенаправление в никуда',
+    'sr': u'Бот: Преусмерење не постоји',
+    'th': u'โรบอต: หน้าเปลี่ยนทางเสีย',
+    'tr': u'Bot değişikliği: Var olmayan sayfaya olan yönlendirme',
+    'war':u'Robot: Waray dida an karadto-an han redirek',
+    'yi': u'באט: ווײַטערפֿירן ציל עקזיסטירט נישט',
+    'zh': u'機器人:該重定向的目標不存在',
+    'zh-yue': u'機械人:跳轉目標唔存在',
+}
+
+# Summary message for putting broken redirect to speedy delete
+sd_tagging_sum = {
+    'ar': u'روبوت: وسم للحذف السريع',
+    'cs': u'Robot označil ke smazání',
+    'en': u'Robot: Tagging for speedy deletion',
+    'ga': u'Róbó: Ag maircáil le luas-scrios',
+    'it': u'Bot: +Da cancellare subito',
+    'ja': u'ロボットによる:迷子のリダイレクトを即時削除へ',
+    'ksh':u'Bot: Di Ömlëijdong jeiht noh nörjendwoh.',
+    'nds':u'Bot: Kaputte Wiederleiden ward nich brukt',
+    'nl': u'Bot: gemarkeerd voor snelle verwijdering',
+    'war':u'Robot: Nautod o nagbinalikbalik nga redirek',
+    'zh': u'機器人: 將損壞的重定向提報快速刪除',
+}
+
+# Insert deletion template into page with a broken redirect
+sd_template = {
+    'ar': u'{{شطب|تحويلة مكسورة}}',
+    'cs': u'{{smazat|přerušené přesměrování}}',
+    'en': u'{{db-r1}}',
+    'ga': u'{{scrios|Athsheoladh briste}}',
+    'it': u'{{Cancella subito|9}}',
+    'ja': u'{{即時削除|壊れたリダイレクト}}',
+    'ksh':u'{{Schmieß fott}}Di Ömlëijdong jeiht noh nörjendwoh hen.<br 
/>--~~~~~\n\n',
+    'nds':u'{{delete}}Kaputte Wiederleiden, wat nich brukt ward.<br 
/>--~~~~\n\n',
+    'war':u'{{delete}}Nautod o nagbinalikbalik nga redirek.--~~~~\n\n',
+    'zh': u'{{delete|R1}}',
+}
+
+class RedirectGenerator:
+    def __init__(self, xmlFilename=None, namespaces=[], offset=-1,
+                 use_move_log=False, use_api=False, start=None, until=None,
+                 number=None):
+        self.site = pywikibot.getSite()
+##        self.xmlFilename = xmlFilename
+        self.namespaces = namespaces
+        if use_api and self.namespaces == []:
+            self.namespaces = [ 0 ]
+        self.offset = offset
+        self.use_move_log = use_move_log
+        self.use_api = use_api
+        self.api_start = start
+        self.api_until = until
+        self.api_number = number
+
+##    def get_redirects_from_dump(self, alsoGetPageTitles=False):
+##        '''
+##        Load a local XML dump file, look at all pages which have the
+##        redirect flag set, and find out where they're pointing at. Return
+##        a dictionary where the redirect names are the keys and the redirect
+##        targets are the values.
+##        '''
+##        xmlFilename = self.xmlFilename
+##        redict = {}
+##        # open xml dump and read page titles out of it
+##        dump = xmlreader.XmlDump(xmlFilename)
+##        redirR = self.site.redirectRegex()
+##        readPagesCount = 0
+##        if alsoGetPageTitles:
+##            pageTitles = set()
+##        for entry in dump.parse():
+##            readPagesCount += 1
+##            # always print status message after 10000 pages
+##            if readPagesCount % 10000 == 0:
+##                pywikibot.output(u'%i pages read...' % readPagesCount)
+##            if len(self.namespaces) > 0:
+##                if pywikibot.Page(self.site, entry.title).namespace() \
+##                        not in self.namespaces:
+##                    continue
+##            if alsoGetPageTitles:
+##                pageTitles.add(entry.title.replace(' ', '_'))
+##
+##            m = redirR.match(entry.text)
+##            if m:
+##                target = m.group(1)
+##                # There might be redirects to another wiki. Ignore these.
+##                for code in self.site.family.langs.keys():
+##                    if target.startswith('%s:' % code) \
+##                            or target.startswith(':%s:' % code):
+##                        if code == self.site.language():
+##                        # link to our wiki, but with the lang prefix
+##                            target = target[(len(code)+1):]
+##                            if target.startswith(':'):
+##                                target = target[1:]
+##                        else:
+##                            pywikibot.output(
+##                                u'NOTE: Ignoring %s which is a redirect to 
%s:'
+##                                % (entry.title, code))
+##                            target = None
+##                            break
+##                # if the redirect does not link to another wiki
+##                if target:
+##                    source = entry.title.replace(' ', '_')
+##                    target = target.replace(' ', '_')
+##                    # remove leading and trailing whitespace
+##                    target = target.strip('_')
+##                    # capitalize the first letter
+##                    if not pywikibot.getSite().nocapitalize:
+##                        source = source[:1].upper() + source[1:]
+##                        target = target[:1].upper() + target[1:]
+##                    if '#' in target:
+##                        target = target[:target.index('#')].rstrip("_")
+##                    if '|' in target:
+##                        pywikibot.output(
+##                            u'HINT: %s is a redirect with a pipelink.'
+##                            % entry.title)
+##                        target = target[:target.index('|')].rstrip("_")
+##                    if target: # in case preceding steps left nothing
+##                        redict[source] = target
+##        if alsoGetPageTitles:
+##            return redict, pageTitles
+##        else:
+##            return redict
+##
+    def get_redirect_pages_via_api(self):
+        """Return generator that yields Pages that are redirects."""
+        for ns in self.namespaces:
+            done = False
+            gen = self.site.allpages(start=self.api_start,
+                                     namespace=ns,
+                                     filterredir=True)
+            if self.api_number:
+                gen.set_maximum_items(self.api_number)
+            for p in gen:
+                done = self.api_until \
+                           and p.title(withNamespace=False) >= self.api_until
+                if done:
+                    return
+                yield p
+
+    def _next_redirect_group(self):
+        """
+        Return a generator that retrieves pageids from the API 500 at a time
+        and yields them as a list
+        """
+        apiQ = []
+        for page in self.get_redirect_pages_via_api():
+            apiQ.append(str(page._pageid))
+            if len(apiQ) >= 500:
+                yield apiQ
+                apiQ = []
+        if apiQ:
+            yield apiQ
+
+    def get_redirects_via_api(self, maxlen=8):
+        """
+        Return a generator that yields tuples of data about redirect Pages:
+            0 - page title of a redirect page
+            1 - type of redirect:
+                         0 - broken redirect, target page title missing
+                         1 - normal redirect, target page exists and is not a
+                             redirect
+                 2..maxlen - start of a redirect chain of that many redirects
+                             (currently, the API seems not to return sufficient
+                             data to make these return values possible, but
+                             that may change)
+                  maxlen+1 - start of an even longer chain, or a loop
+                             (currently, the API seems not to return sufficient
+                             data to allow this return values, but that may
+                             change)
+                      None - start of a redirect chain of unknown length, or 
loop
+            2 - target page title of the redirect, or chain (may not exist)
+            3 - target page of the redirect, or end of chain, or page title 
where
+                chain or loop detecton was halted, or None if unknown
+        """
+        for apiQ in self._next_redirect_group():
+            gen = pywikibot.data.api.Request(action="query", redirects="",
+                                             pageids=apiQ)
+            data = gen.submit()
+            if 'error' in data:
+                raise RuntimeError("API query error: %s" % data)
+            if data == [] or "query" not in data:
+                raise RuntimeError("No results given.")
+            redirects = {}
+            pages = {}
+            redirects = dict((x['from'], x['to'])
+                             for x in data['query']['redirects'])
+
+            for pagetitle in data['query']['pages'].values():
+                if 'missing' in pagetitle and 'pageid' not in pagetitle:
+                    pages[pagetitle['title']] = False
+                else:
+                    pages[pagetitle['title']] = True
+            for redirect in redirects:
+                target = redirects[redirect]
+                result = 0
+                final = None
+                try:
+                    if pages[target]:
+                        final = target
+                        try:
+                            while result <= maxlen:
+                               result += 1
+                               final = redirects[final]
+                            # result = None
+                        except KeyError:
+                            pass
+                except KeyError:
+                    result = None
+                    pass
+                yield (redirect, result, target, final)
+
+    def retrieve_broken_redirects(self):
+        if self.use_api:
+            count = 0
+            for (pagetitle, type, target, final) \
+                    in self.get_redirects_via_api(maxlen=2):
+                if type == 0:
+                    yield pagetitle
+                    if self.api_number:
+                        count += 1
+                        if count >= self.api_number:
+                            break
+
+##        elif self.xmlFilename == None:
+##            # retrieve information from the live wiki's maintenance page
+##            # broken redirect maintenance page's URL
+##            path = self.site.broken_redirects_address(default_limit=False)
+##            pywikibot.output(u'Retrieving special page...')
+##            maintenance_txt = self.site.getUrl(path)
+##
+##            # regular expression which finds redirects which point to a
+##            # non-existing page inside the HTML
+##            Rredir = re.compile('\<li\>\<a href=".+?" title="(.*?)"')
+##
+##            redir_names = Rredir.findall(maintenance_txt)
+##            pywikibot.output(u'Retrieved %d redirects from special page.\n'
+##                             % len(redir_names))
+##            for redir_name in redir_names:
+##                yield redir_name
+##        else:
+##            # retrieve information from XML dump
+##            pywikibot.output(
+##                u'Getting a list of all redirects and of all page titles...')
+##            redirs, pageTitles = self.get_redirects_from_dump(
+##                                            alsoGetPageTitles=True)
+##            for (key, value) in redirs.iteritems():
+##                if value not in pageTitles:
+##                    yield key
+
+    def retrieve_double_redirects(self):
+        if self.use_move_log:
+            for redir_page in self.get_moved_pages_redirects():
+                yield redir_page.title()
+            return
+        else:
+            count = 0
+            for (pagetitle, type, target, final) \
+                    in self.get_redirects_via_api(maxlen=2):
+                if type != 0 and type != 1:
+                    yield pagetitle
+                    if self.api_number:
+                        count += 1
+                        if count >= self.api_number:
+                            break
+
+##        elif self.xmlFilename == None:
+##            # retrieve information from the live wiki's maintenance page
+##            # double redirect maintenance page's URL
+###            pywikibot.config.special_page_limit = 1000
+##            path = self.site.double_redirects_address(default_limit = False)
+##            pywikibot.output(u'Retrieving special page...')
+##            maintenance_txt = self.site.getUrl(path)
+##
+##            # regular expression which finds redirects which point to
+##            # another redirect inside the HTML
+##            Rredir = re.compile('\<li\>\<a href=".+?" title="(.*?)">')
+##            redir_names = Rredir.findall(maintenance_txt)
+##            pywikibot.output(u'Retrieved %i redirects from special page.\n'
+##                             % len(redir_names))
+##            for redir_name in redir_names:
+##                yield redir_name
+##        else:
+##            redict = self.get_redirects_from_dump()
+##            num = 0
+##            for (key, value) in redict.iteritems():
+##                num += 1
+##                # check if the value - that is, the redirect target - is a
+##                # redirect as well
+##                if num > self.offset and value in redict:
+##                    yield key
+##                    pywikibot.output(u'\nChecking redirect %i of %i...'
+##                                     % (num + 1, len(redict)))
+
+    def get_moved_pages_redirects(self):
+        '''generate redirects to recently-moved pages'''
+        # this will run forever, until user interrupts it
+        import datetime
+
+        if self.offset <= 0:
+            self.offset = 1
+        start = datetime.datetime.utcnow() \
+                - datetime.timedelta(0, self.offset*3600)
+        # self.offset hours ago
+        offset_time = start.strftime("%Y%m%d%H%M%S")
+
+        move_gen = self.site.logevents(logtype="move", start=offset_time)
+        if self.api_number:
+            move_gen.set_maximum_items(self.api_number)
+        for logentry in move_gen:
+            moved_page = logentry.title()
+            try:
+                if not moved_page.isRedirectPage():
+                    continue
+            except pywikibot.BadTitle:
+                continue
+            except pywikibot.ServerError:
+                continue
+            # moved_page is now a redirect, so any redirects pointing
+            # to it need to be changed
+            try:
+                for page in moved_page.getReferences(follow_redirects=True,
+                                                     redirectsOnly=True):
+                    yield page
+            except pywikibot.NoPage:
+                # original title must have been deleted after move
+                continue
+
+
+class RedirectRobot:
+    def __init__(self, action, generator, always=False, number=None):
+        self.site = pywikibot.getSite()
+        self.action = action
+        self.generator = generator
+        self.always = always
+        self.number = number
+        self.exiting = False
+
+    def prompt(self, question):
+        if not self.always:
+            choice = pywikibot.inputChoice(question,
+                                           ['Yes', 'No', 'All', 'Quit'],
+                                           ['y', 'N', 'a', 'q'], 'N')
+            if choice == 'n':
+                return False
+            elif choice == 'q':
+                self.exiting = True
+                return False
+            elif choice == 'a':
+                self.always = True
+        return True
+
+    def delete_broken_redirects(self):
+        # get reason for deletion text
+        reason = pywikibot.translate(self.site, reason_broken)
+        for redir_name in self.generator.retrieve_broken_redirects():
+            self.delete_1_broken_redirect( redir_name, reason)
+            if self.exiting:
+                break
+
+    def delete_1_broken_redirect(self, redir_name, reason):
+            redir_page = pywikibot.Page(self.site, redir_name)
+            # Show the title of the page we're working on.
+            # Highlight the title in purple.
+            pywikibot.output(u"\n\n>>> \03{lightpurple}%s\03{default} <<<"
+                              % redir_page.title())
+            try:
+                targetPage = redir_page.getRedirectTarget()
+            except pywikibot.IsNotRedirectPage:
+                pywikibot.output(u'%s is not a redirect.' % redir_page.title())
+            except pywikibot.NoPage:
+                pywikibot.output(u'%s doesn\'t exist.' % redir_page.title())
+            else:
+                try:
+                    targetPage.get()
+                except pywikibot.NoPage:
+                    if self.prompt(
+            u'Redirect target %s does not exist. Do you want to delete %s?'
+                                   % (targetPage.title(asLink=True),
+                                      redir_page.title(asLink=True))):
+                        try:
+                            redir_page.delete(reason, prompt = False)
+                        except pywikibot.NoUsername:
+                            if targetPage.site().lang in sd_template \
+                                    and targetPage.site().lang in 
sd_tagging_sum:
+                                pywikibot.output(
+            u"No sysop in user-config.py, put page to speedy deletion.")
+                                content = redir_page.get(get_redirect=True)
+                                content = pywikibot.translate(
+                                    targetPage.site().lang,
+                                    sd_template)+"\n"+content
+                                summary = pywikibot.translate(
+                                    targetPage.site().lang,
+                                    sd_tagging_sum)
+                                redir_page.put(content, summary)
+
+                except pywikibot.IsRedirectPage:
+                    pywikibot.output(
+            u'Redirect target %s is also a redirect! Won\'t delete anything.'
+                        % targetPage.title(asLink=True))
+                else:
+                    #we successfully get the target page, meaning that
+                    #it exists and is not a redirect: no reason to touch it.
+                    pywikibot.output(
+            u'Redirect target %s does exist! Won\'t delete anything.'
+                        % targetPage.title(asLink=True))
+            pywikibot.output(u'')
+
+    def fix_double_redirects(self):
+        for redir_name in self.generator.retrieve_double_redirects():
+            self.fix_1_double_redirect(redir_name)
+            if self.exiting:
+                break
+
+    def fix_1_double_redirect(self,  redir_name):
+            redir = pywikibot.Page(self.site, redir_name)
+            # Show the title of the page we're working on.
+            # Highlight the title in purple.
+            pywikibot.output(u"\n\n>>> \03{lightpurple}%s\03{default} <<<"
+                              % redir.title())
+            newRedir = redir
+            redirList = []  # bookkeeping to detect loops
+            while True:
+                redirList.append(u'%s:%s' % (newRedir.site().lang,
+                                             
newRedir.title(withSection=False)))
+                try:
+                    targetPage = newRedir.getRedirectTarget()
+                except pywikibot.IsNotRedirectPage:
+                    if len(redirList) == 1:
+                        pywikibot.output(u'Skipping: Page %s is not a 
redirect.'
+                                         % redir.title(asLink=True))
+                        break  #do nothing
+                    elif len(redirList) == 2:
+                        pywikibot.output(
+                            u'Skipping: Redirect target %s is not a redirect.'
+                            % newRedir.title(asLink=True))
+                        break  # do nothing
+                except pywikibot.SectionError:
+                    pywikibot.output(
+                        u'Warning: Redirect target section %s doesn\'t exist.'
+                          % newRedir.title(asLink=True))
+                except pywikibot.BadTitle, e:
+                    # str(e) is in the format 'BadTitle: [[Foo]]'
+                    pywikibot.output(
+                        u'Warning: Redirect target %s is not a valid page 
title.'
+                          % str(e)[10:])
+                #sometimes this error occures. Invalid Title starting with a 
'#'
+                except pywikibot.InvalidTitle, err:
+                    pywikibot.output(u'Warning: %s' % err)
+                    break
+                except pywikibot.NoPage:
+                    if len(redirList) == 1:
+                        pywikibot.output(u'Skipping: Page %s does not exist.'
+                                            % redir.title(asLink=True))
+                        break
+                    else:
+                        if self.always:
+                            pywikibot.output(
+                                u"Skipping: Redirect target %s doesn't exist."
+                                % newRedir.title(asLink=True))
+                            break  # skip if automatic
+                        else:
+                            pywikibot.output(
+                                u"Warning: Redirect target %s doesn't exist."
+                                % newRedir.title(asLink=True))
+                except pywikibot.ServerError:
+                    pywikibot.output(u'Skipping: Server Error')
+                    break
+                else:
+                    pywikibot.output(
+                        u'   Links to: %s.'
+                          % targetPage.title(asLink=True))
+                    if targetPage.site() != self.site:
+                        pywikibot.output(
+                u'Warning: redirect target (%s) is on a different site.'
+                             % (targetPage.title(asLink=True)))
+                        if self.always:
+                            break  # skip if automatic
+                    # watch out for redirect loops
+                    if redirList.count(u'%s:%s'
+                                       % (targetPage.site().lang,
+                                          targetPage.title(withSection=False))
+                                      ) > 0:
+                        pywikibot.output(
+                           u'Warning: Redirect target %s forms a redirect 
loop.'
+                              % targetPage.title(asLink=True))
+                        break ###xqt doesn't work. edits twice!
+                        try:
+                            content = targetPage.get(get_redirect=True)
+                        except pywikibot.SectionError:
+                            content = pywikibot.Page(
+                                          targetPage.site(),
+                                          targetPage.title(withSection=False)
+                                      ).get(get_redirect=True)
+                        if targetPage.site().lang in sd_template \
+                                and targetPage.site().lang in sd_tagging_sum:
+                            pywikibot.output(u"Tagging redirect for deletion")
+                            # Delete the two redirects
+                            content = pywikibot.translate(
+                                        targetPage.site().lang,
+                                        sd_template)+"\n"+content
+                            summ = pywikibot.translate(targetPage.site().lang,
+                                                       sd_tagging_sum)
+                            targetPage.put(content, summ)
+                            redir.put(content, summ)
+                        break # TODO Better implement loop redirect
+                    else:
+                        newRedir = targetPage
+                        continue
+                try:
+                    oldText = redir.get(get_redirect=True)
+                except pywikibot.BadTitle:
+                    pywikibot.output(u"Bad Title Error")
+                    break
+                text = self.site.redirectRegex().sub(
+                        '#%s %s' %
+                            (self.site.redirect( True ),
+                             targetPage.title(asLink=True)),
+                        oldText)
+                if text == oldText:
+                    break
+                summary = pywikibot.translate(self.site, msg_double)\
+                          % targetPage.title(asLink=True)
+                pywikibot.showDiff(oldText, text)
+                if self.prompt(u'Do you want to accept the changes?'):
+                    try:
+                        redir.put(text, summary)
+                    except pywikibot.LockedPage:
+                        pywikibot.output(u'%s is locked.' % redir.title())
+                    except pywikibot.SpamfilterError, error:
+                        pywikibot.output(
+                            u"Saving page [[%s]] prevented by spam filter: %s"
+                             % (redir.title(), error.url))
+                    except pywikibot.PageNotSaved, error:
+                        pywikibot.output(u"Saving page [[%s]] failed: %s"
+                             % (redir.title(), error))
+                    except pywikibot.NoUsername:
+                        pywikibot.output(
+                            u"Page [[%s]] not saved; sysop privileges 
required."
+                             % redir.title())
+                    except pywikibot.Error, error:
+                        pywikibot.output(
+                        u"Unexpected error occurred trying to save [[%s]]: %s"
+                             % (redir.title(), error))
+                break
+
+    def fix_double_or_delete_broken_redirects(self):
+        # TODO: part of this should be moved to generator, the rest merged 
into self.run()
+        # get reason for deletion text
+        delete_reason = pywikibot.translate(self.site, reason_broken)
+        count = 0
+        for (redir_name, code, target, final)\
+                in self.generator.get_redirects_via_api(maxlen=2):
+            if code == 1:
+                continue
+            elif code == 0:
+                self.delete_1_broken_redirect(redir_name, delete_reason)
+                count += 1
+            else:
+                self.fix_1_double_redirect(redir_name)
+                count += 1
+            if self.exiting or (self.number and count >= self.number):
+                break
+
+    def run(self):
+        # TODO: make all generators return a redirect type indicator,
+        #       thus make them usable with 'both'
+        if self.action == 'double':
+            self.fix_double_redirects()
+        elif self.action == 'broken':
+            self.delete_broken_redirects()
+        elif self.action == 'both':
+            self.fix_double_or_delete_broken_redirects()
+
+def main(*args):
+    # read command line parameters
+    # what the bot should do (either resolve double redirs, or delete broken
+    # redirs)
+    action = None
+    # where the bot should get his infos from (either None to load the
+    # maintenance special page from the live wiki, or the filename of a
+    # local XML dump file)
+    xmlFilename = None
+    # Which namespace should be processed when using a XML dump
+    # default to -1 which means all namespaces will be processed
+    namespaces = []
+    # at which redirect shall we start searching double redirects again
+    # (only with dump); default to -1 which means all redirects are checked
+    offset = -1
+    moved_pages = False
+    api = True  # rewrite always uses api, probably should get rid of this
+    start = ''
+    until = ''
+    number = None
+    always = False
+    for arg in pywikibot.handleArgs(*args):
+        if arg == 'double' or arg == 'do':
+            action = 'double'
+        elif arg == 'broken' or arg == 'br':
+            action = 'broken'
+        elif arg == 'both':
+            action = 'both'
+        elif arg.startswith('-xml'):
+            if len(arg) == 4:
+                xmlFilename = pywikibot.input(
+                                u'Please enter the XML dump\'s filename: ')
+            else:
+                xmlFilename = arg[5:]
+        elif arg.startswith('-moves'):
+            moved_pages = True
+        elif arg.startswith('-namespace:'):
+            ns = arg[11:]
+            if ns == '':
+        ## "-namespace:" does NOT yield -namespace:0 further down the road!
+                ns = pywikibot.input(
+                        u'Please enter a namespace by its number: ')
+#                       u'Please enter a namespace by its name or number: ')
+#  TODO! at least for some generators.
+            if ns == '':
+               ns = '0'
+            try:
+                ns = int(ns)
+            except ValueError:
+#-namespace:all Process all namespaces. Works only with the API read interface.
+               pass
+            if not ns in namespaces:
+               namespaces.append(ns)
+        elif arg.startswith('-offset:'):
+            offset = int(arg[8:])
+        elif arg.startswith('-start:'):
+            start = arg[7:]
+        elif arg.startswith('-until:'):
+            until = arg[7:]
+        elif arg.startswith('-total:'):
+            number = int(arg[8:])
+        elif arg == '-always':
+            always = True
+        else:
+            pywikibot.output(u'Unknown argument: %s' % arg)
+
+    if xmlFilename:
+        pywikibot.output("Sorry, xmlreader is not yet implemented in rewrite",
+                        level=pywikibot.ERROR)
+    elif not action: # or (xmlFilename and moved_pages)
+                     # or (api and xmlFilename):
+        pywikibot.showHelp('redirect')
+    else:
+        gen = RedirectGenerator(xmlFilename, namespaces, offset, moved_pages,
+                                api, start, until, number)
+        bot = RedirectRobot(action, gen, always, number)
+        bot.run()
+
+if __name__ == '__main__':
+    try:
+        main()
+    finally:
+        pywikibot.stopme()



_______________________________________________
Pywikipedia-svn mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/pywikipedia-svn

Reply via email to