Utilisateur:Eikubot/Entwurf-bot.py

#!/usr/bin/python
# -*- coding: utf-8 -*-
 
"""
Ce truc était un robot, mais maintenant,
c’est un assistant pour créer des articles.
"""
 
import os, sys
import re
import time
import gtk

import neti
try: import helpbro

except:
	class Foo:''
	helpbro = Foo(); helpbro.HelpBrowser=lambda:''
	print "Vous n’aurez pas d’aide."

interface = neti.interface

interface.DELAY = 5
interface.SLEEP_POINT_TIME = 1
interface.BOT = False
if len (sys.argv) > 1: interface.USER_NAME = sys.argv[1]
os.chdir (sys.path[0])
 
class ArticleError (Exception): pass
 
class ArticleFr:
        """
        Classe pour créer le texte d’un article, selon le modèle
        canonique du Wiktionnaire francophone.
 
        Utilisation basique :
        mon_article = ArticleFr ("oiseau", "nom", "fr", "m")
        mon_article.set_pron ("wazo")
        mon_article.add_def ("{{ucf|volatile}} à [[plumes]].", 
                             "''Fais comme l’'''oiseau''', et tout le bazar.''", 
                                                 "''Les chauves-souris ne sont pas des '''oiseaux'''.''")
        mon_article.add_def ("Seconde définition", "''Exemple pour la seconde définition.''")
        mon_article.put_on_wikt ()
 
        On vient de créer un article, de lui mettre des définitions et de l’ajouter
        au wiktionnaire.
 
        Mais avant d’appeler put_on_wikt (), on peut ajouter d’autres informations :
 
        * images :
        mon_article.add_img ("Mésange bleue.JPG", "La mésange bleue est un '''oiseau'''")
 
        * traductions (avec genre ou romanisation optionnels)
        mon_article.add_trad ("bird",  "en")
        mon_article.add_trad ("Vogel", "de", genre="m")
        mon_article.add_trad ("새",    "ko", roman="ㅅ|ㅐ")
 
        * synonymes, antonymes, holonymes, méronymes, hypéronymes, hyponymes, etc.
        mon_article.add_hyper ("animal", "m")
        mon_article.add_hypo  ("passereau", "m")
        mon_article.add_hypo  ("rapace", "m")
        mon_article.add_mero  ("aile", "f")
        mon_article.add_mero  ("plume", "f")
 
        * expressions
        mon_article.add_exp ("le petit oiseau va sortir")
        mon_article.add_exp ("drôle d’oiseau", "m")
        mon_article.add_exp ("oiseau de malheur", "m")
 
        Et on peut invoquer render () si on veut voir le résultat (par exemple, pour
        faire une vérification avant de le mettre sur le wiki).
 
        print "------Mon Article------\n" + mon_article.render ()
        """
        def __init__ (self, nom="", categ="", lang="", genre=""):
                self.nom = nom
                self.genre = genre
                self.pron = ""
                self.content = ""
                self.lang = lang
                self.categ = categ
                self.imgs = []
                self.defs = []
                self.trads = {}
                self.voirwp = ""
 
                self.sect_orthoalt = "" # autres orthographes
                self.sect_syn   = ""
                self.sect_qsyn   = ""
                self.sect_ant = "" # contraires
                self.sect_drv = "" # mots dérivés
                self.sect_apr = "" # mots apparentés étymologiquement
                self.sect_voc = "" # mots du même champ lexiacal
                self.sect_drvint = "" # dérivés étrangers
                self.sect_exp = "" # expressions
                self.sect_dial = "" # variantes dialectales
                self.sect_trad = "" #
                self.sect_hyper = "" # mots plus généraux
                self.sect_hypo  = "" # mots plus précis
                self.sect_holo  = "" # le mot en fait partie (maison>'''toit''')
                self.sect_mero  = "" # parties du mot ('''toit'''>tuile)
                self.sect_tropo = "" # verbe hyponyme (tuer>égorger)
                self.sect_voir = ""
        def render (self):
                if "" in (self.nom, self.categ, self.lang):
                        try: raise ArticleError, "il manque le nom, la catégorie grammaticale ou la langue."
                        except ArticleError, msg: sys.stderr.write ("Warning: %s\n"%msg)
                content = []
                self.make_sect_trad ()
                ## essentiel
                content.append ("== {{=%s=}} ==" % self.lang)
                content.append ("{{ébauche|%s}}" % self.lang)
                content.append ("{{-étym-}}\n: {{ébauche-étym|fr}}\n")
                content.append ("{{-%s-|%s}}"       % 
                                (self.categ, self.lang))
                for img in self.imgs:
                        content.append ("[[image:%s|thumb|%s (%d)]]"
                                       % img)
                ligne_forme = "'''%s'''"%self.nom
                if self.pron: ligne_forme += " {{pron|%s|%s}}"%(
                                self.pron, self.lang)
                if self.genre: ligne_forme += " {{%s}}"%self.genre
                content.append (ligne_forme)
                for definition in self.defs:
                        content.append (definition)
 
                ## bonus et trads
                for bonus_trad in (
                                self.sect_orthoalt,
                                self.sect_syn,
                                self.sect_qsyn,
                                self.sect_ant,
                                self.sect_drv,
                                self.sect_apr,
                                self.sect_voc,
                                self.sect_drvint,
                                self.sect_exp,
                                self.sect_dial,
                                self.sect_trad,
                                self.sect_hyper,
                                self.sect_hypo,
                                self.sect_holo,
                                self.sect_mero,
                                self.sect_tropo,
                                self.sect_voir):
                        if bonus_trad: content.append ("\n" + bonus_trad)
                content.append ("\n" + self.cledetri())
                return "\n".join (content)
        def cledetri (self):
                if self.lang=="ko": return ""
                nom = unicode (self.nom, "utf-8").lower ()
                nom = re.sub (u"[éèêë]", "e", nom)
                nom = re.sub (u"[áàâä]", "a", nom)
                nom = re.sub (u"ç", "c", nom)
                nom = re.sub (u"[íìîï]", "i", nom)
                nom = re.sub (u"[óòôö]", "o", nom)
                nom = re.sub (u"[úùûü]", "u", nom)
                nom = re.sub (u"ñ", "n", nom)
                nom = re.sub (u"’", "", nom)
                nom = nom.encode ("utf-8")
                if nom==self.nom: return "{{clé de tri}}"
                else: return "{{clé de tri|%s}}"%nom
        def set_lang (self, lang):
                self.lang = lang
        def set_categ (self, categ):
                self.categ = categ
        def set_genre (self, genre):
                self.genre = genre
        def set_nom (self, nom):
                self.nom = nom
        def add_img (self, img, legende="", n=1):
                self.imgs.append ((img, legende, n))
        def add_def (self, definition, *exemples):
                tmp_def = "" #  "# "
                if isinstance (definition, tuple):
                        return
                        precisions, definition = definition[0:-1], definition[-1]
                        for prec in precisions:
                                if prec in LISTE_PRECISIONS:
                                        tmp_def += "{{%s}} "%prec
                                else:
                                        tmp_def += "{{term|%s}} "%prec
                tmp_def += definition
                for i in exemples:
                        if i[0]==":": i = "#*: "+i[1:]
                        else:         i = "#* "+i
                        tmp_def += "\n" + i
                self.defs.append (tmp_def)
        def add_syn (self, syn, comment=""):
                if not self.sect_syn: self.sect_syn = "{{-syn-}}"
                if comment: comment= " "+comment
                self.sect_syn += "\n* [[%s]]%s"%(syn, comment)
        def add_qsyn (self, qsyn, comment=""):
                if not self.sect_qsyn: self.sect_qsyn = "{{-q-syn-}}"
                if comment: comment= " "+comment
                self.sect_qsyn += "\n* [[%s]]"%(qsyn, comment)
        def add_ant (self, ant, comment=""):
                if not self.sect_ant: self.sect_ant= "{{-ant-}}"
                if comment: comment= " "+comment
                self.sect_ant += "\n* [[%s]]%s"%(ant, comment)
        def add_drv (self, drv, comment=""):
                if not self.sect_drv: self.sect_drv= "{{-drv-}}"
                if comment: comment= " "+comment
                self.sect_drv += "\n* [[%s]]%s"%(drv, comment)
        def add_apr (self, apr, comment=""):
                if not self.sect_apr: self.sect_apr= "{{-apr-}}"
                if comment: comment= " "+comment
                self.sect_apr += "\n* [[%s]]%s"%(apr, comment)
        def add_voc (self, voc, comment=""):
                if not self.sect_voc: self.sect_voc= "{{-voc-}}"
                if comment: comment= " "+comment
                self.sect_voc += "\n* [[%s]]%s"%(voc, comment)
        def add_drvint (self, drvint, comment=""):
                if not self.sect_drvint: self.sect_drvint= "{{-drvint-}}"
                if comment: comment= " "+comment
                self.sect_drvint += "\n* [[%s]]%s"%(drvint, comment)
        def add_exp (self, exp, comment=""):
                if not self.sect_exp: self.sect_exp= "{{-exp-}}"
                if comment: comment= " "+comment
                self.sect_exp += "\n* [[%s]]%s"%(exp, comment)
        def add_dial (self, dial, comment=""):
                if not self.sect_dial: self.sect_dial= "{{-dial-}}"
                if comment: comment= " "+comment
                self.sect_dial += "\n* [[%s]]%s"%(dial, comment)
        def add_trad (self, trad, lang, genre="", roman=""):
                if genre: genre=" {{%s}}"%genre
                if not self.trads.has_key (lang):
                        self.trads [lang] = []
 
                if lang=="ko" and roman:
                        v = ""
                        if self.categ == "verb" or self.categ == "adj": 
                                v="|verbe=1"
                        roman = "{{ko-roman|%s%s}}"%(roman, v)
                        self.trads [lang].append ("{{trad|ko|%s|R=%s}}"%(trad,roman))
                elif roman:
                        self.trads [lang].append ("{{trad|%s|%s|R=%s}}"%(lang, trad,roman))
                else:
                        self.trads [lang].append ("{{trad|%s|%s}}%s"%(lang, trad, genre))
        def make_sect_trad (self):
                trads_sav={}
                if not self.trads: return
                self.sect_trad= "{{-trad-}}"
                self.sect_trad += "\n{{(}}"
                # d’abord les langues qu’on sait trier
                for lang in ("de", "en", "nds", "ko", "es", "eo", "fr", "pt"):
                        if self.trads.has_key (lang):
                                self.sect_trad += "\n* {{T|%s}} : %s"%(lang, ", ".join (self.trads[lang]))
                                trads_sav[lang]=self.trads.pop (lang)
                # ensuite les autres
                for lang in self.trads:
                        self.sect_trad += "\n* {{T|%s}} : %s"%(lang, ", ".join (self.trads[lang]))
                        trads_sav[lang]=self.trads.pop (lang)
                self.trads=trads_sav
                self.sect_trad += "\n{{)}}"
        def add_hyper (self, hyper, comment=""):
                if not self.sect_hyper: self.sect_hyper= "{{-hyper-}}"
                if comment: comment= " "+comment
                self.sect_hyper += "\n* [[%s]]%s"%(hyper, comment)
        def add_hypo (self, hypo, comment=""):
                if not self.sect_hypo: self.sect_hypo= "{{-hypo-}}"
                if comment: comment= " "+comment
                self.sect_hypo += "\n* [[%s]]%s"%(hypo, comment)
        def add_holo (self, holo, comment=""):
                if not self.sect_holo: self.sect_holo= "{{-holo-}}"
                if comment: comment= " "+comment
                self.sect_holo += "\n* [[%s]]%s"%(holo, comment)
        def add_mero (self, mero, comment=""):
                if not self.sect_mero: self.sect_mero= "{{-méro-}}"
                if comment: comment= " "+comment
                self.sect_mero += "\n* [[%s]]%s"%(mero, comment)
        def add_tropo (self, tropo, comment=""):
                if not self.sect_tropo: self.sect_tropo= "{{-tropo-}}"
                if comment: comment= " "+comment
                self.sect_tropo += "\n* [[%s]]%s"%(tropo, comment)
        def add_voir (self, voir, comment=""):
                if not self.sect_voir: self.sect_voir= "{{-voir-}}"
                if comment: comment= " "+comment
                self.sect_voir += "\n* [[%s]]%s"%(voir, comment)
        def set_pron (self, pron):
                self.pron = pron
        def add_voirWP (self, lien=""):
                "ajoute un lien vers Wikipédia"
                if not self.sect_voir: self.sect_voir = "{{-voir-}}"
                if lien: lien="|"+lien
                self.sect_voir += "\n* {{WP%s}}"%lien
        def put_on_wikt (self, prefix="Utilisateur:Eiku/brouillons/"):
                """Crée une page."""
                pagename = prefix + self.nom
                page = neti.Page (pagename)
                render = self.render ()
                if page.exists (): raise ArticleError, "La page existe déjà."
                commentaire = "(Assisté) Création: %s"%render[0:150].replace ("\n"," ")
                if not page.create (commentaire, render):
                        print "Échec de l’écriture de la page (probablement un problème de connexion à Internet)"
                        print "Sauvegarde de la page pour création ultérieure."
                        # sauvegarde de la page dans une liste de pages à créer
                        numero = 0
                        filename_a_creer = "pages_a_creer/%02d"%numero
                        while os.path.exists (filename_a_creer):
                                numero += 1
                                filename_a_creer = "pages_a_creer/%02d"%numero
                        open (filename_a_creer, "w").write (pagename + "\n" + self.render())
                else:
                        print "Réussite de l’écriture de la page."
        def replace_on_wikt (self, prefix="Utilisateur:Eiku/brouillons/"):
                """Remplace une page existante sans confirmation."""
                pagename = prefix + self.nom
                page = neti.Page (pagename)
                render = self.render ()
                page.write ("(bot) Remplacé par: %s"%render[0:150].replace ("\n"," "), 
                                render)
 
'''
class CompEntry (gtk.Entry):
        def __init__ (self):
                gtk.Entry.__init__ (self)
                self.completer = gtk.EntryCompletion ()
'''
 
class GUI_Definition (gtk.VBox):
        def __init__ (self, parent):
                gtk.VBox.__init__ (self)
                self.papa = parent
                self.papa.pack_start(self, expand=True, fill=True)
                # textarea
                sw = gtk.ScrolledWindow ()
                tv = gtk.TextView ()
                sw.add (tv)
                sw.set_policy( gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
                tv.set_right_margin (13)
                tv.set_left_margin (13)
                tv.set_wrap_mode (gtk.WRAP_WORD)
                tv.set_accepts_tab (False)
                self.pack_start (sw, expand=True, fill=True)
                tv.show_all ()
                self.buf = tv.get_buffer()
                self.tv = tv
        def get_def (self):
                buf = self.buf
                text = buf.get_text (buf.get_start_iter (), buf.get_end_iter ())
                #if text.startswith ("# "): text = text[2:]
                return text
 
class GUI_ArticleCreator (gtk.Window):
        def __init__ (self):
                gtk.Window.__init__ (self)
                self.set_default_size(600, 400)
                self.set_title ("Ajouter un mot")
                box = gtk.VBox ()
                self.table = gtk.Table (6, 2)
                self.table.set_col_spacing (0, 10)
                box.pack_start (self.table, expand=False, fill=True)
                self.add (box)
                self.entries = []
                self.entry_focused = 0
 
                self.win = gtk.Window ()
                #self.definition
                self.funcs = []
                self.nlignes = 1
                # Mot vedette
                self.vedette = self.add_entry ()
                # Langue
                self.langue = self.add_entry ("Langue")
                self.langue.set_text ("fr")
                # Catégorie
                def on_categ_changed ():
                        txt = self.categ.get_text ()
                        if txt in ("nom", "loc-nom"):
                                self.genre.show ()
                        else:
                                self.genre.set_text ("")
                                self.genre.hide ()
                self.categ = self.add_entry ("Catégorie")
                self.categ.set_text ("nom")
                self.categ.connect ("changed", lambda *w: on_categ_changed ())
                # Genre
                self.genre = self.add_entry ("Genre")
                # Prononciation
                self.pron = self.add_entry ("Prononciation")
                # Définitions
                self.definitions = GUI_Definition (box)
                self.entries.append (self.definitions.tv)
                def on_anything_changed (*w):
                        self.on_valide ()
                for e in [self.vedette, self.langue, self.categ, self.genre, self.pron, self.definitions.buf]:
                        e.connect ("changed", on_anything_changed)
                # bonus
                pass
                # Bouton
                hb = gtk.HBox ()
                box.pack_start (hb, expand=False, fill=True)
                #bouton = gtk.Button ("Prévisualiser")
                #bouton.connect ("clicked", lambda *w: self.on_valide ())
                #hb.pack_start (bouton, expand=True, fill=False)
                bouton_help = gtk.Button ("Aide")
                bouton_help.connect ('clicked', lambda *w: helpbro.HelpBrowser())
                hb.pack_start (bouton_help, expand=True, fill=False)
                bouton_help_edit = gtk.Button ("(edit)")
                bouton_help_edit.connect ('clicked', lambda *w: os.system('gvim wikt-help.txt'))
                hb.pack_start (bouton_help_edit, expand=True, fill=False)
                bouton_send = gtk.Button ("Envoyer")
                bouton_send.connect ("clicked", lambda *w: self.on_send ())
                hb.pack_start (bouton_send, expand=False, fill=False)
                # Preview
                self.prev = exp = gtk.Expander ()
                sw = gtk.ScrolledWindow ()
                sw.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
                tv = gtk.TextView ()
                tv.set_wrap_mode (gtk.WRAP_WORD)
                tv.set_editable (False)
                sw.set_size_request(200, 300)
                self.prev_buf = tv.get_buffer ()
                sw.add (tv)
                exp.add (sw)
                box.add (exp)
                exp.set_expanded (False)
                self.continuer = True
                on_anything_changed ()
        def focus_next (self, *w):
                self.entry_focused = (self.entry_focused + 1) % len (self.entries)
                self.entries [self.entry_focused].grab_focus ()
 
        def add_entry (self, label=None):
                entry = gtk.Entry ()
                a = gtk.EXPAND | gtk.FILL
                b = gtk.SHRINK | gtk.FILL
                if label:
                        self.table.attach (gtk.Label (label), 0, 1, self.nlignes, self.nlignes + 1, b, b)
                        self.table.attach (entry, 1, 2, self.nlignes, self.nlignes + 1, a,b)
                else:
                        self.table.attach (entry, 0, 2, self.nlignes, self.nlignes + 1, a,b)
                self.entries.append (entry)
                entry.connect ("activate", self.focus_next)
                self.nlignes += 1
                return entry
        def on_valide (self):
                art = ArticleFr ()
                art.set_nom   (self.vedette.get_text())
                art.set_genre (self.genre.get_text  ())
                art.set_lang  (self.langue.get_text ())
                art.set_categ (self.categ.get_text  ())
                art.set_pron  (self.pron.get_text   ())
                art.defs = []
                art.add_def   (self.definitions.get_def ())
                self.prev.set_expanded (True)
                self.prev_buf.set_text (art.render ())
                return art
        def on_send (self):
                art = self.on_valide ()
                #art.put_on_wikt ()
                art.put_on_wikt (prefix='')
                self.destroy ()
                self.continuer = True
        def on_destroy (self):
                self.destroy ()
                gtk.main_quit ()
                self.continuer = False
        def run (self):
                self.connect ('destroy', lambda *w: self.on_destroy())
                self.show_all ()
                gtk.main ()
                return self.continuer
 
def main ():
        """Appelle juste l’interface"""
        # Interface
        while GUI_ArticleCreator ().run (): ''
 
if __name__ == "__main__":
        try: main ()
        except KeyboardInterrupt: print "\033[31mLeaving: User typed Ctrl+C.\033[0m"