Selaa lähdekoodia

Added make_summary() and shutoff_enabled() methods to BaseTask; added config.tasks and config.wiki['shutoff']; added task numbering; wikitools cleanup.

tags/v0.1^2
Ben Kurtovic 13 vuotta sitten
vanhempi
commit
e14897399e
5 muutettua tiedostoa jossa 110 lisäystä ja 28 poistoa
  1. +58
    -0
      bot/classes/base_task.py
  2. +8
    -5
      bot/config.py
  3. +42
    -19
      bot/tasks/afc_statistics.py
  4. +1
    -2
      bot/wiki/category.py
  5. +1
    -2
      bot/wiki/page.py

+ 58
- 0
bot/classes/base_task.py Näytä tiedosto

@@ -1,8 +1,12 @@
# -*- coding: utf-8 -*-

import config
import wiki

class BaseTask(object):
"""A base class for bot tasks that edit Wikipedia."""
name = None
number = 0

def __init__(self):
"""Constructor for new tasks.
@@ -25,3 +29,57 @@ class BaseTask(object):
(e.g. start('mytask', action='save')).
"""
pass

def make_summary(self, comment):
"""Makes an edit summary by filling in variables in a config value.

config.wiki["summary"] is used, where $2 is replaced by the main
summary body, given as a method arg, and $1 is replaced by the task
number.

If the config value is not found, we just return the arg as-is.
"""
try:
summary = config.wiki["summary"]
except KeyError:
return comment
return summary.replace("$1", self.number).replace("$2", comment)

def shutoff_enabled(self, site=None):
"""Returns whether on-wiki shutoff is enabled for this task.

We check a certain page for certain content. This is determined by
our config file: config.wiki["shutoff"]["page"] is used as the title,
with $1 replaced by our username and $2 replaced by the task number,
and config.wiki["shutoff"]["disabled"] is used as the content.

If the page has that content or the page does not exist, then shutoff
is "disabled", meaning the bot is supposed to run normally, and we
return False. If the page's content is something other than what we
expect, shutoff is enabled, and we return True.

If a site is not provided, we'll try to use self.site if it's set.
Otherwise, we'll use our default site.
"""
if not site:
try:
site = self.site
except AttributeError:
site = wiki.get_site()

try:
cfg = config.wiki["shutoff"]
except KeyError:
return False
title = cfg.get("page", "User:$1/Shutoff/Task $2")
username = site.get_user().name()
title = title.replace("$1", username).replace("$2", self.number)
page = site.get_page(title)

try:
content = page.get()
except wiki.PageNotFoundError:
return False
if content == cfg.get("disabled", "run"):
return False
return True

+ 8
- 5
bot/config.py Näytä tiedosto

@@ -8,10 +8,11 @@ including encrypting and decrypting passwords and making a new config file from
scratch at the inital bot run.

Usually you'll just want to do "from core import config" and access config data
from within config's four global variables and one function:
from within config's five global variables and one function:

* config.components - a list of enabled components
* config.wiki - a dict of information about wiki-editing
* config.tasks - a dict of information for bot tasks
* config.irc - a dict of information about IRC
* config.metadata - a dict of miscellaneous information
* config.schedule() - returns a list of tasks scheduled to run at a given time
@@ -34,8 +35,8 @@ config_path = path.join(root_dir, "config.json")

_config = None # Holds data loaded from our config file

# Set our four easy-config-access global variables to None
components, wiki, irc, metadata = None, None, None, None
# Set our five easy-config-access global variables to None
components, wiki, tasks, irc, metadata = None, None, None, None, None

def _load():
"""Load data from our JSON config file (config.json) into _config."""
@@ -68,8 +69,9 @@ def load():
First, check if we have a valid config file, and if not, notify the user.
If there is no config file at all, offer to make one, otherwise exit.

Store data from our config file in four global variables (components, wiki,
irc, metadata) for easy access (as well as the internal _config variable).
Store data from our config file in five global variables (components, wiki,
tasks, irc, metadata) for easy access (as well as the internal _config
variable).

If everything goes well, return True if stored passwords are
encrypted in the file, or False if they are not.
@@ -88,6 +90,7 @@ def load():

components = _config.get("components", [])
wiki = _config.get("wiki", {})
tasks = _config.get("tasks", {})
irc = _config.get("irc", {})
metadata = _config.get("metadata", {})



+ 42
- 19
bot/tasks/afc_statistics.py Näytä tiedosto

@@ -1,9 +1,11 @@
# -*- coding: utf-8 -*-

import re
from os import path

from classes import BaseTask
import config
import wiki

class Task(BaseTask):
"""A task to generate statistics for WikiProject Articles for Creation.
@@ -16,35 +18,56 @@ class Task(BaseTask):
In the live bot, this is "Template:AFC statistics".
"""
name = "afc_statistics"
number = 2

def __init__(self):
self.filename = path.join(config.root_dir, "statistics.txt")
self.pagename = "User:EarwigBot/Sandbox/Statistics"
self.cfg = config.tasks.get(self.name, {})
self.pagename = cfg.get("page", "Template:AFC statistics")
default = "Updating statistics for [[WP:WPAFC|WikiProject Articles for creation]]."
self.summary = self.make_summary(cfg.get("summary", default))

def run(self, **kwargs):
try:
action = kwargs["action"]
except KeyError:
self.site = wiki.get_site()
action = kwargs.get("action")
if not action:
return

if action == "save":
self.save()
else:
try:
page = kwargs["page"]
except KeyError:
return
if action == "edit":
self.process_edit(page)
elif action == "move":
self.process_move(page)
elif action == "delete":
self.process_delete(page)
elif action == "restore":
self.process_restore(page)
return
page = kwargs.get("page")
if page:
methods = {
"edit": self.process_edit,
"move": self.process_move,
"delete": self.process_delete,
"restore": self.process_restore,
}
method = methods.get(action)
if method:
method(page)

def save(self):
pass
if self.shutoff_enabled():
return
try:
with open(self.filename) as fp:
statistics = fp.read()
except IOError:
pass

page = self.site.get_page(self.pagename)
text = page.get()
newtext = re.sub("(<!-- stat begin -->)(.*?)(<!-- stat end -->)",
"\\1~~~~\\3", text, flags=re.DOTALL)
if newtext == text:
return # Don't edit the page if we're not adding anything

newtext = re.sub("(<!-- sig begin -->)(.*?)(<!-- sig end -->)",
"\\1~~~~\\3", newtext)
page.edit(newtext, self.summary, minor=True)

def process_edit(self, page):
pass


+ 1
- 2
bot/wiki/category.py Näytä tiedosto

@@ -18,8 +18,7 @@ class Category(Page):

def __repr__(self):
"""Returns the canonical string representation of the Category."""
res = ", ".join(("Category(title={0!r}", "follow_redirects={1!r}",
"site={2!r})"))
res = "Category(title={0!r}, follow_redirects={1!r}, site={2!r})"
return res.format(self._title, self._follow_redirects, self._site)

def __str__(self):


+ 1
- 2
bot/wiki/page.py Näytä tiedosto

@@ -83,8 +83,7 @@ class Page(object):

def __repr__(self):
"""Returns the canonical string representation of the Page."""
res = ", ".join(("Page(title={0!r}", "follow_redirects={1!r}",
"site={2!r})"))
res = "Page(title={0!r}, follow_redirects={1!r}, site={2!r})"
return res.format(self._title, self._follow_redirects, self._site)

def __str__(self):


Ladataan…
Peruuta
Tallenna