User:Interwicket/code/botstatus
< User:Interwicket | code
Python pywikipedia framework bot code to produce a status report for the bot.
Edit this page, copy everything in between the "source" tags, and save it as botstatus.py
in your usual bot working directory.
There are no command line options.
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
This bot task reads user information from the WMF projects, and writes a status report for
the bot account home wiki.
It intentionally has no parameters, it follows the configuration as loaded by any other task
using the framework.
The status report is always written to User:(username)/Status on the home project. If you want it
somewhere else (on that project), run this program once, then move it, leaving the redirect in place.
The heading for the page is User:(username)/Status/Header and works the same way, you may redirect
it from the /Header subpage of whereever you have moved the page. The /Header page is up to you
to create.
It was written on Python version 2.6.1, with a view to running on Python 3. It may work on
earlier versions.
Any issues, questions, ideas please write on [[:en:wikt:User:Robert Ullmann]] or send "e-mail to user"
from there.
Robert Ullmann, 6.3.9
"""
import wikipedia
import sys
import re
import urllib
from config import mylang, family, usernames
class FLwiki:
def __init__(self, code, family):
self.lc = code
self.family = family
self.user = usernames[family][code]
self.lastcheck = None
self.status = None
self.userpage = False
self.edits = 0
self.lockedwiki = False
try:
self.site = wikipedia.getSite(code, family)
except wikipedia.NoSuchSite:
self.site = None
self.lockedwiki = True
class FLdict(dict):
def __init__(self, family):
self.family = family
def __missing__(self, code):
self[code] = FLwiki(code, self.family)
return self[code]
# so we can just reference the dictionary (;-)
def globalp(flw):
# predicate that returns True if we are a global bot, and flw is in global bots list
# check this username, unless (usual case) we already have
if flw.user != globalp.user:
# go look at userlist:
msite = wikipedia.getSite("meta", "meta")
userurl = urllib.quote(flw.user.encode(flw.site.encoding()))
gutext = msite.getUrl("/w/index.php?title=Special%3AGlobalUsers&group=Global_bot" +
"&limit=1&username=" + userurl)
# the odd character is a L-to-R mark, in there presumably in case the username is RTL (!)
globalp.status = (u"<ul><li>" + flw.user + u" \u200e(") in gutext
globalp.user = flw.user
if globalp.status: print "(user " + repr(flw.user) + " is a global bot)"
else: print "(user " + repr(flw.user) + " is not a global bot)"
if not globalp.status: return False
# user is global bot, now check wiki:
if not globalp.text:
mgp = wikipedia.Page(msite,"Bot policy/Implementation")
print '(reading global policy page from meta)'
globalp.text = mgp.get()
# format is {{/project|fa|wiktionary|aaa=yes|globalbots=yes}}
if "{{/project|" + flw.lc + "|" + flw.family + "|aaa=yes|globalbots=yes}}" in globalp.text:
return True
if "{{/project|" + flw.lc + "|" + flw.family + "|aaa=no|globalbots=yes}}" in globalp.text:
return True
# also list of other projects, format :* [[he:Project:Bot policy|hewiki]]
f2 = flw.family
if f2 == 'wikipedia': f2 = 'wiki'
for line in globalp.text.splitlines():
if line.startswith(':* [[') and '|' + flw.lc + f2 + ']]' in line: return True
# getting more hacked all the time ...
return False
globalp.text = None
globalp.user = ''
globalp.status = None
redits = re.compile('editcount="(\d+)"')
def getflstatus(flw):
# can we just tell caller the status for this one?
if flw.lockedwiki:
flw.status = 'blocked'
print '(%s.%s is locked)' % (flw.lc, flw.family)
return flw.status
try:
ustat = flw.site.getUrl(
"/w/api.php?action=query&list=users&ususers=" + flw.user +
"&usprop=blockinfo|groups|editcount&format=xml")
except Exception, e:
print "exception trying to read user status from %s.%s:" % (flw.lc, flw.family), str(e)
flw.status = "exception"
return "exception"
# edit count?
mo = redits.search(ustat)
if mo: flw.edits = int(mo.group(1))
# we can be bot, or blocked, or not known:
# [first line needs improving, other groups will break it]
if "<g>bot</g>" in ustat: flw.status = "bot"
if "blockedby=" in ustat: flw.status = "blocked" # over-rides "bot", as it can be both
if "missing=" in ustat: flw.status = "missing"
if not flw.status: flw.status = "user"
# global? overridden by local bot flag or blocked status
if flw.status == "user" and globalp(flw): flw.status = "globalbot"
print "%s.%s: %s, %d edits" % (flw.lc, flw.family, flw.status, flw.edits)
return flw.status
def updstatus(flws, mysite, user):
try:
page = wikipedia.Page(mysite, "User:" + user + "/Status")
text = page.get()
except wikipedia.NoPage:
pass
except wikipedia.IsRedirectPage:
# follow it
page = page.getRedirectTarget()
try:
text = page.get()
except Exception, e:
print "exception getting redirected status page", repr(e)
return
except Exception, e:
print "exception getting status page", repr(e)
return
# page text:
text = "{{/Header}}\n\n"
for fam in sorted(flws):
text += "====" + fam + "====\n"
text += """{| class="wikitable sortable"
! code
! language
! status
! edits
! contributions
|-
"""
lines = []
for code in sorted(flws[fam]):
flw = flws[fam][code]
if flw.lockedwiki: continue
# if flw.edits:
if True:
if code != mylang: flc = ':' + code + ':'
else: flc = ''
if fam != family: flf = fam + ':'
else: flf = ''
if flf == 'meta:': flc = ''
contribs = "[[%s%sSpecial:Contributions/%s|%s]]" % (flc, flf, flw.user, flw.user)
else: contribs = ''
lines.append("| '''%s''' || {{#language:%s}} || %s || %d || %s"
% (flw.lc, flw.lc, flw.status, flw.edits, contribs))
text += '\n|-\n'.join(sorted(lines)) + "\n|}\n\n"
try:
page.put(text, comment = "update status table")
except wikipedia.NoPage:
pass
except Exception, e:
print "exception writing status table", str(e)
# main procedure
# for each family with configured usernames, read status from each wiki
# then write report
def main():
mysite = wikipedia.getSite(mylang, family)
mysite.forceLogin()
flws = { } # dict of FLdict, [fam][code]
for fam in usernames:
if not usernames[fam]: continue
flws[fam] = FLdict(fam)
for code in usernames[fam]: getflstatus(flws[fam][code])
me = usernames[family][mylang]
updstatus(flws, mysite, me)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print "(keyboard interrupt)"
# mostly just suppress traceback
finally:
wikipedia.stopme()