Szerkesztő:BinBot/csonksablonlista.py

A Wikipédiából, a szabad enciklopédiából

This bot lists stub templates. If you need help in adaption, ask Bináris.

A bot a csonksablonokkal kapcsolatos feladatokat látja el, a Wikipédia:Csonk/Csonksablonok listája aloldalait frissíti. Ebben az állapotban, ahogy most van, végigmegy a csonksablonokat tartalmazó kategóriákon, mindegyikhez megkeresi a megfelelő lista címét a Sablon:Csonksablonokban, és oda feltölti az adott kategóriába tartozó csonksablonok áttekinthető listáját a kategóriába tartozó csonkok számával. A kikommentezett részeknek az előkészítés során volt szerepük, segédtáblázatokat, listákat készítettek egy ideiglenes allapra, és később még hasznosak lehetnek, ezért hagytam meg őket, mert a kommentjelek cseréjével működtethetők.

Jelenleg a bot nem fut folyamatosan, csak szükség esetén.

import re
# import codecs
import pywikibot
import pywikibot.pagegenerators as pg

class Csonkrobot:
    def __init__(self, catname, recurse=False, start=None):
        self.recurse = recurse
        self.start = start
        self.site = pywikibot.Site()
        self.cat = pywikibot.Category(self.site, catname)
        self.katlist = self.cat.categories()
        self.basecat = pywikibot.Category(self.site, 'Csonkokat jelölő sablonok')
        self.basetemplate = pywikibot.Page(self.site, 'Sablon:Csonksablonok')
        self.topicregex = re.compile(r'(?ism)Ez az? *(.*?) *lap')
        self.iconregex = re.compile(r'(?ism)kép *= *(.*?)\|')
        self.categoryregex = re.compile(
            r'(?ism)<includeonly>.*?\[\[(Kategória:.*?)(?:\||\]\]).*?</includeonly>')
        self.forbiddenlist = self.forbidden()
        self.notices = self.notice()
        self.listnotices = self.listnotice()
        self.targetpages = self.pagesnamesforcategories()
        self.substlimit = 200 # Ennyi sablon fölött substoljuk az elemző fv.-t.

    # __________________ UTILITIES __________________

    def makelists(self):
        """Elkészíti az összes kategória csonksablonlistáját."""
        summary = 'A csonksablonok listáinak frissítése bottal'
        heap = set()
        for subcat in self.basecat.subcategories(recurse=True):
            t = subcat.title(with_ns=False)
            if t in self.targetpages.keys():
                heap.add(subcat)
        for subcat in heap:
            self.cat = subcat
            self.katlist = subcat.categories()
            name = subcat.title(with_ns=False)
            table = self.listoftemplates()
            page = pywikibot.Page(self.site, self.targetpages[name])
            print(page)
            try:
                oldtext = page.get()
            except pywikibot.exceptions.NoPageError:
                oldtext = ''
            oldtext = oldtext[oldtext.find('\n'):]
            newtext = table[len('{{../fejléc}}~~~~~\n'):]
            # Tapasztalati feltétel a tartalom változatlanságára (-dátum):
            if oldtext[1:] != newtext[:-1]:
                page.put(table, summary)

    def dicwriter(self, templ):
        """Képernyőre írja egy csonksablon adatait."""
        print(templ)
        dic = self.dicmaker(templ)
        for k in dic:
            v = dic[k]
            if type(v) is unicode or type(v) is bool or type(v) is str:
                pywikibot.output('\t%s: %s' % (k, v))
            elif type(v) is list:
                pywikibot.output('\t%s %d' % (k, len(v)))
                try:
                    pywikibot.output('\t\t%s' % ', '.join(v))
                except TypeError:
                    print(v)
            else:
                print('\tIsmeretlen típus')

    def listoftemplates(self):
        """Táblázat egy kategória csonksablonjaiból és kategóriáikból."""
        # Legfeljebb egy beillesztett kategóriát jelenít meg.
        # Ez a csonksablonlistákra feltölthető változat.
        # Csak egy kategóriára használjuk egyszerre! (self.cat)
        new = '{{../fejléc}}~~~~~\n\n'
        new += self.listheader()
        lista = list(self.gen())
        if not len(lista):
            new += 'Ez a lista jelenleg üres. ' \
                +'A sablonokat az alkategóriákban találod.\n'
            return new
        listnotice = self.listnotices.get(self.cat.title(with_ns=False), None)
        if listnotice:
            new += '{{ambox|type=notice|text=%s}}\n' % listnotice
        subst = 'subst:' if len(lista) > self.substlimit else ''
        if subst:
            new += 'Ezen a lapon nagyon sok sablon van, ezért a költségesen '
            new += 'kiszámítható elemszámok nem követik a változásokat az '
            new += 'utolsó frissítés óta.\n'

        new += '{| {{széptáblázat-r}}\n'
        new += '! Sablon !! !! Megjelenés !! Beillesztett kategória !! Elem !! Alkat.\n'

        for templ in lista:
            dic = self.dicmaker(templ)
            try:
                kat = dic['insertedCats'][0]
            except IndexError:
                kat = 'Nem találom'
            kat2 = kat.replace('Kategória:', '')
            hasabbrevs = len(dic['abbrevs'])
            new += '|-\n|'
            if hasabbrevs:
                new += '{{plainlist|'
                new += '\n* {{sl|%s}}' % dic['name']
                for abb in dic['abbrevs']:
                    new += '\n* {{sl|%s}}' % abb.title(with_ns=False)
                new += '\n|stílus=white-space:nowrap;}}'
            elif len(dic['name']) > 32:
                new += 'style="font-size:80%;"| {{sl|' + dic['name'] + '}}'
            else:
                new += 'style="white-space:nowrap;"| {{sl|' + dic['name'] + '}}'
            new += '\n{{listacella|%s}}\n|' % dic['name']
            new += '{{%s|minta=igen}}' % dic['name']
            notice = self.notices.get(dic['name'][len('csonk-'):], None)
            if notice:
                new += notice
            if templ.title(with_ns=False) in self.forbiddenlist:
                new += '<p>Ezt a sablont lehetőleg ne használd! '
                new += 'Valószínűleg találsz alkalmasabbat az alkategóriákban.'
            new += '\n| [[:' + kat + ']]'
            new +=  ' || {{%sPAGESINCATEGORY:%s' % (subst, kat2)
            new += '|pages}} || {{%sPAGESINCATEGORY:%s' % (subst, kat2)
            new += '|subcats}}\n'
        new += '|}\n'
        return new

    def wikitable(self):
        """Wikitáblázatot készít egy kategória csonksablonjaiból és kategóriáikból."""
        # Legfeljebb egy beillesztett kategóriát jelenít meg.
        # Ez a munkapadra való változat, ami a cikk2 sablont használja.
        pakk = set() # Rekurzióban többször is előfordulhat egy kategória.
        new = '{| {{széptáblázat-r}}\n'
        new += '! Sablon !! Beillesztett kategória !! Elem !! Alkat. !! Minta !! PAGEN\n'
        for templ in self.gen():
            if templ in pakk:
                continue
            pakk.add(templ)
            dic = self.dicmaker(templ)
            try:
                kat = dic['insertedCats'][0]
            except IndexError:
                kat = 'Nem találom'
            kat2 = kat.replace('Kategória:', '')
            new += '|-\n| {{cikk2|' + dic['fullName'] + '}} || [[:'
            new += kat + ']] || {{subst:PAGESINCATEGORY:' + kat2
            new += '|pages}} || {{subst:PAGESINCATEGORY:' + kat2
            new += '|subcats}} || '
            new += ('{{pirosiksz}}', '')[dic['vanMinta']] + ' || '
            new += ('', '[[File:Important-3.svg]]')[dic['vanPagename']] + '\n'
        new += '|}\n'
        return new

    def tableofcategories(self):
        """A munkapadra listázza a kategóriákat a saját kategóriáikkal."""
        def katstring(cat):
            return '[[:%s|%s]]' % (cat.title(), cat.title(with_ns=False))

        def wrap(l):
            return '<br>'.join(l)

        stubcat = catlib.Category(self.site, 'Csonkok (labdarúgók)')
        # stubcat = catlib.Category(self.site, 'Életrajzi csonkok nemzetiség szerint')
        # stubcat = catlib.Category(self.site, 'Csonkok (település)')
        cats = list(set(stubcat.subcategories(recurse=True)))
        i = 0
        new = '{| {{széptáblázat-r}}\n'
        new += '!Kategória !! Szülőkategória (csonk) !! Szülőkategória ' \
                + '(tartalmi) !! Alkategória'
        for cat in cats:
            name = cat.title(with_ns=False)
            if name.startswith('Csonkok 20') or name == 'Szakaszcsonkok':
                continue # Ez kb. 230-at kiejt, ami nincs a rendszerben.
            new += '\n|-\n| '
            new += katstring(cat) + ' || '
            supercats = cat.categories()
            cskats = filter(
                lambda c: 'csonkok' in c.title().lower(), supercats)
            realkats = filter(
                lambda c: 'csonkok' not in c.title().lower(), supercats)
            if not len(realkats):
                i+=1
            new += wrap([katstring(sc) for sc in cskats]) + ' || '
            new += wrap([katstring(sc) for sc in realkats]) + ' || '
            subcats = cat.subcategories()
            new += wrap([katstring(sc) for sc in subcats])
        new += '\n|}\n'
        print(i)
        f = codecs.open('kattáblázat.txt', 'w', 'utf8')
        f.write(new)
        f.close()

    # __________________ LIBRARIES__________________

    def listheader(self):
        """Kiteszi a lista tetejére a szülő- és alkategóriákat."""
        text = "'''Kategória: [[:%s]];''' " % self.cat.title()
        parents = list(self.katlist) # Egyszeri listázástól kimerül!
        text += 'szülőkategóriái: ' if len(parents) > 1 \
                 else 'szülőkategóriája: '
        text += ', '.join(
            ['[[:%s]]' % kat.title() for kat in parents])
        if len(list(self.cat.subcategories())):
            text += '\n\nAlkategóriái: <categorytree>%s</categorytree>\n\n' \
                % self.cat.title(with_ns=False)
        else:
            text += '\n\nAlkategóriái nincsenek.\n\n'
        return text

    def dicmaker(self, templ):
        """Egy kategória adatait szótárba rendezi."""
        dic = {}
        text = templ.get()
        try:
            icon = self.iconregex.search(text).group(1)
        except AttributeError:
            icon = '???'
        try:
            topic = self.topicregex.search(text).group(1)
        except AttributeError:
            topic = '???'
        dic['fullName'] = templ.title()
        dic['name'] = templ.title(with_ns=False)
        dic['text'] = text
        dic['vanMinta'] = '{{#if:{{{minta|}}}|<!--ne kategorizáljon-->' in text
        dic['vanPagename'] = '|{{PAGENAME}}' in text
        dic['topic'] = topic
        dic['icon'] = icon
        dic['templateCats'] = templ.categories()
        dic['templateCatNames'] = [p.title() for p in dic['templateCats']]
        _sortkeyObjects = \
            [re.search(r'(?ism)\[\[%s\|(.*?)\]\]' % title, text)
                for title in dic['templateCatNames']]
        dic['templateCatSortkeys'] = \
            [m.group(1) if m is not None else 'ω' for m in _sortkeyObjects]
        dic['insertedCats'] = self.categoryregex.findall(text)
        dic['abbrevs'] = list(templ.getReferences(filter_redirects=True))
        return dic

    def gen(self):
        for templ in pg.CategorizedPageGenerator(
                self.cat, self.recurse, self.start):
            yield templ

    def checkcategories(self):
        """A sablonban fel nem sorolt csonksablon-kategóriák listája"""
        text = self.basetemplate.get()
        heap = set()
        for subcat in self.basecat.subcategories(recurse=True):
            if subcat.title() not in text:
                heap.add(subcat)
        return list(heap)

    def forbidden(self):
        l = ['Csonk', 'Csonk-életrajz', 'Csonk-focista', 'Csonk-tudomány',
            ]
        return l

    def notice(self):
        """A sablon alatt megjelenő megjegyzéseket lehet definiálni vele."""
        return {
            'közigazgatás':
                'Közigazgatási fogalmakhoz való. Közigazgatási egységekhez' \
                ' (megye, járás, kormányzóság stb.) használd a ' \
                '{{sl|csonk-közigazgatási egység}} sablont! A településekhez' \
                ' pedig külön lista van a fenti sablonban.',
            'közigazgatási egység':
                'A településekhez külön sablonok vannak!',
            'földrajz':
                'Máshova nem sorolható földrajzi' \
                ' objektumokhoz való. Közigazgatási egységekhez' \
                ' (megye, járás, kormányzóság stb.) használd a ' \
                '{{sl|csonk-közigazgatási egység}} sablont! A településekhez' \
                ' pedig külön lista van a fenti sablonban.',
            'földrajzi fogalom':
                'Földrajzi fogalmakhoz, magával a földrajztudománnyal' \
                ' kapcsolatos csonkokhoz való. Közigazgatási egységekhez' \
                ' (megye, járás, kormányzóság stb.) használd a ' \
                '{{sl|csonk-közigazgatási egység}} sablont! A településekhez' \
                ' pedig külön lista van a fenti sablonban.',
            'építészet':
                'Építészeti fogalmakhoz, áttekintő cikkekhez való. ' \
                'Világi épületekhez, hidakhoz, tornyokhoz, gátakhoz, ' \
                'emlékművekhez használd a {{sl|csonk-építmény}}, ' \
                'vallásiakhoz a {{sl|csonk-templom}} sablont!',
            'település':
                'Ezt a sablont lehetőleg ne használd! A legtöbb országhoz ' \
                'van külön sablon.',
            'magyar közigazgatás':
                'Ez a sablon magához a közigazgatáshoz való. Megyékhez, ' \
                'járásokhoz, kistérségekhez használd a ' \
                '{{sl|csonk-magyar közigazgatási egység}} sablont!',
            }

    def listnotice(self):
        """A listák tetejére tud szöveget definiálni."""
        return {
            'Településekről szóló csonkokat jelölő sablonok':
                'Magyarországhoz és Szlovákiához nem tartozik országszintű ' \
                'sablon. Használd a megyei, illetve kerületi csonksablonokat!',
            'Foglalkozás és ország szerinti kettős besorolású életrajzi ' \
                    'csonksablonok':
                'Ezen a lapon a leggyakoribb foglalkozás-nemzetiség ' \
                'párosítások láthatóak, foglalkozás szerint rendezve. '\
                'Ha nem találsz ilyen sablont, használhatod külön a ' \
                'nemzetiség vagy a foglalkoozás szerinti sablonokat, esetleg' \
                ' együtt is, pl. {{sl|csonk-német életrajz}} + {{sl|csonk-' \
                'jogász}}.',
            }

    def pagesnamesforcategories(self):
        """Kikeresi a listák címeit, ahova menteni kell."""
        rex = re.compile(
            r'\[\[(Wikipédia:Csonk/Csonksablonok listája/[^|]+?)'
            r'\|.*?\]\]\s*\(\[\[:Kategória:([^|]+?)\|kategória\]\]'
            )
        dic = {}
        for m in rex.findall(self.basetemplate.get()):
            dic[m[1]] = m[0]
        return dic

if __name__ == '__main__':
    catname ='Csonkokat jelölő sablonok'
    # catname ='Focisták életrajzi csonkjait jelölő sablonok ország szerint'
    # catname ='Biológia témájú csonkokat jelölő sablonok'
    # catname ='Tudomány témájú csonkokat jelölő sablonok'
    # catname ='Közlekedés témájú csonkokat jelölő sablonok'
    # catname ='Országokról szóló csonkokat jelölő sablonok'
    # catname ='Életrajzi témájú csonkokat jelölő sablonok ország szerint'
    # catname ='Sport témájú csonkokat jelölő sablonok'
    # catname ='Közigazgatási egységekről szóló csonkokat jelölő sablonok'
    bot = Csonkrobot(catname, recurse=False, start=None)
    bot.makelists()
    # print(bot.checkcategories())