diff --git a/earwigbot/__init__.py b/earwigbot/__init__.py index fb656f3..282f66b 100644 --- a/earwigbot/__init__.py +++ b/earwigbot/__init__.py @@ -28,7 +28,7 @@ See README.md for a basic overview, or the docs/ directory for details. """ __author__ = "Ben Kurtovic" -__copyright__ = "Copyright (C) 2009, 2010, 2011 by Ben Kurtovic" +__copyright__ = "Copyright (C) 2009, 2010, 2011, 2012 by Ben Kurtovic" __license__ = "MIT License" __version__ = "0.1.dev" __email__ = "ben.kurtovic@verizon.net" diff --git a/earwigbot/commands/afc_report.py b/earwigbot/commands/afc_report.py index 75c2f64..9803a33 100644 --- a/earwigbot/commands/afc_report.py +++ b/earwigbot/commands/afc_report.py @@ -30,7 +30,7 @@ class Command(BaseCommand): name = "report" def process(self, data): - self.site = wiki.get_site() + self.site = self.bot.wiki.get_site() self.site._maxlag = None self.data = data diff --git a/earwigbot/commands/afc_status.py b/earwigbot/commands/afc_status.py index f03bf98..08333a9 100644 --- a/earwigbot/commands/afc_status.py +++ b/earwigbot/commands/afc_status.py @@ -22,7 +22,6 @@ import re -from earwigbot import wiki from earwigbot.commands import BaseCommand class Command(BaseCommand): @@ -45,7 +44,7 @@ class Command(BaseCommand): return False def process(self, data): - self.site = wiki.get_site() + self.site = self.bot.wiki.get_site() self.site._maxlag = None if data.line[1] == "JOIN": diff --git a/earwigbot/commands/editcount.py b/earwigbot/commands/editcount.py index 9c58726..92341b0 100644 --- a/earwigbot/commands/editcount.py +++ b/earwigbot/commands/editcount.py @@ -41,7 +41,7 @@ class Command(BaseCommand): else: name = ' '.join(data.args) - site = wiki.get_site() + site = self.bot.wiki.get_site() site._maxlag = None user = site.get_user(name) diff --git a/earwigbot/commands/registration.py b/earwigbot/commands/registration.py index 55b762f..6db8775 100644 --- a/earwigbot/commands/registration.py +++ b/earwigbot/commands/registration.py @@ -41,7 +41,7 @@ class Command(BaseCommand): else: name = ' '.join(data.args) - site = wiki.get_site() + site = self.bot.wiki.get_site() site._maxlag = None user = site.get_user(name) diff --git a/earwigbot/commands/rights.py b/earwigbot/commands/rights.py index 1a9dd99..65d3975 100644 --- a/earwigbot/commands/rights.py +++ b/earwigbot/commands/rights.py @@ -39,7 +39,7 @@ class Command(BaseCommand): else: name = ' '.join(data.args) - site = wiki.get_site() + site = self.bot.wiki.get_site() site._maxlag = None user = site.get_user(name) diff --git a/earwigbot/config.py b/earwigbot/config.py index 4cf0721..f2830e0 100644 --- a/earwigbot/config.py +++ b/earwigbot/config.py @@ -29,6 +29,8 @@ import yaml from earwigbot import blowfish +__all__ = ["BotConfig"] + class BotConfig(object): """ EarwigBot's YAML Config File Manager diff --git a/earwigbot/tasks/__init__.py b/earwigbot/tasks/__init__.py index 9a667be..aa6e35e 100644 --- a/earwigbot/tasks/__init__.py +++ b/earwigbot/tasks/__init__.py @@ -110,10 +110,10 @@ class BaseTask(object): try: site = self.site except AttributeError: - site = wiki.get_site() + site = self.bot.wiki.get_site() try: - cfg = self.bot.config.wiki["shutoff"] + cfg = self.config.wiki["shutoff"] except KeyError: return False title = cfg.get("page", "User:$1/Shutoff/Task $2") diff --git a/earwigbot/tasks/afc_catdelink.py b/earwigbot/tasks/afc_catdelink.py index 7888e70..ba57b5e 100644 --- a/earwigbot/tasks/afc_catdelink.py +++ b/earwigbot/tasks/afc_catdelink.py @@ -22,6 +22,8 @@ from earwigbot.tasks import BaseTask +__all__ = ["Task"] + class Task(BaseTask): """A task to delink mainspace categories in declined [[WP:AFC]] submissions.""" diff --git a/earwigbot/tasks/afc_copyvios.py b/earwigbot/tasks/afc_copyvios.py index 552654c..2e651aa 100644 --- a/earwigbot/tasks/afc_copyvios.py +++ b/earwigbot/tasks/afc_copyvios.py @@ -26,9 +26,10 @@ from threading import Lock import oursql -from earwigbot import wiki from earwigbot.tasks import BaseTask +__all__ = ["Task"] + class Task(BaseTask): """A task to check newly-edited [[WP:AFC]] submissions for copyright violations.""" @@ -62,7 +63,7 @@ class Task(BaseTask): if self.shutoff_enabled(): return title = kwargs["page"] - page = wiki.get_site().get_page(title) + page = self.bot.wiki.get_site().get_page(title) with self.db_access_lock: self.conn = oursql.connect(**self.conn_data) self.process(page) diff --git a/earwigbot/tasks/afc_dailycats.py b/earwigbot/tasks/afc_dailycats.py index b286924..5ce4b49 100644 --- a/earwigbot/tasks/afc_dailycats.py +++ b/earwigbot/tasks/afc_dailycats.py @@ -22,6 +22,8 @@ from earwigbot.tasks import BaseTask +__all__ = ["Task"] + class Task(BaseTask): """ A task to create daily categories for [[WP:AFC]].""" name = "afc_dailycats" diff --git a/earwigbot/tasks/afc_history.py b/earwigbot/tasks/afc_history.py index e59a5c0..eb5f0b5 100644 --- a/earwigbot/tasks/afc_history.py +++ b/earwigbot/tasks/afc_history.py @@ -34,11 +34,7 @@ import oursql from earwigbot import wiki from earwigbot.tasks import BaseTask -# Valid submission statuses: -STATUS_NONE = 0 -STATUS_PEND = 1 -STATUS_DECLINE = 2 -STATUS_ACCEPT = 3 +__all__ = ["Task"] class Task(BaseTask): """A task to generate charts about AfC submissions over time. @@ -56,6 +52,12 @@ class Task(BaseTask): """ name = "afc_history" + # Valid submission statuses: + STATUS_NONE = 0 + STATUS_PEND = 1 + STATUS_DECLINE = 2 + STATUS_ACCEPT = 3 + def setup(self): cfg = self.config.tasks.get(self.name, {}) self.num_days = cfg.get("days", 90) @@ -72,7 +74,7 @@ class Task(BaseTask): self.db_access_lock = Lock() def run(self, **kwargs): - self.site = wiki.get_site() + self.site = self.bot.wiki.get_site() with self.db_access_lock: self.conn = oursql.connect(**self.conn_data) @@ -136,7 +138,7 @@ class Task(BaseTask): stored = cursor.fetchall() status = self.get_status(title, pageid) - if status == STATUS_NONE: + if status == self.STATUS_NONE: if stored: cursor.execute(q_delete, (pageid,)) continue @@ -154,14 +156,14 @@ class Task(BaseTask): ns = page.namespace() if ns == wiki.NS_FILE_TALK: # Ignore accepted FFU requests - return STATUS_NONE + return self.STATUS_NONE if ns == wiki.NS_TALK: new_page = page.toggle_talk() sleep(2) if new_page.is_redirect(): - return STATUS_NONE # Ignore accepted AFC/R requests - return STATUS_ACCEPT + return self.STATUS_NONE # Ignore accepted AFC/R requests + return self.STATUS_ACCEPT cats = self.categories sq = self.site.sql_query @@ -169,16 +171,16 @@ class Task(BaseTask): match = lambda cat: list(sq(query, (cat.replace(" ", "_"), pageid))) if match(cats["pending"]): - return STATUS_PEND + return self.STATUS_PEND elif match(cats["unsubmitted"]): - return STATUS_NONE + return self.STATUS_NONE elif match(cats["declined"]): - return STATUS_DECLINE - return STATUS_NONE + return self.STATUS_DECLINE + return self.STATUS_NONE def get_date_counts(self, date): query = "SELECT COUNT(*) FROM page WHERE page_date = ? AND page_status = ?" - statuses = [STATUS_PEND, STATUS_DECLINE, STATUS_ACCEPT] + statuses = [self.STATUS_PEND, self.STATUS_DECLINE, self.STATUS_ACCEPT] counts = {} with self.conn.cursor() as cursor: for status in statuses: @@ -192,9 +194,9 @@ class Task(BaseTask): plt.xlabel(self.graph.get("xaxis", "Date")) plt.ylabel(self.graph.get("yaxis", "Submissions")) - pends = [d[STATUS_PEND] for d in data.itervalues()] - declines = [d[STATUS_DECLINE] for d in data.itervalues()] - accepts = [d[STATUS_ACCEPT] for d in data.itervalues()] + pends = [d[self.STATUS_PEND] for d in data.itervalues()] + declines = [d[self.STATUS_DECLINE] for d in data.itervalues()] + accepts = [d[self.STATUS_ACCEPT] for d in data.itervalues()] pends_declines = [p + d for p, d in zip(pends, declines)] ind = arange(len(data)) xsize = self.graph.get("xsize", 1200) diff --git a/earwigbot/tasks/afc_statistics.py b/earwigbot/tasks/afc_statistics.py index 0fcbec4..6601243 100644 --- a/earwigbot/tasks/afc_statistics.py +++ b/earwigbot/tasks/afc_statistics.py @@ -32,14 +32,7 @@ import oursql from earwigbot import wiki from earwigbot.tasks import BaseTask -# Chart status number constants: -CHART_NONE = 0 -CHART_PEND = 1 -CHART_DRAFT = 2 -CHART_REVIEW = 3 -CHART_ACCEPT = 4 -CHART_DECLINE = 5 -CHART_MISPLACE = 6 +__all__ = ["Task"] class Task(BaseTask): """A task to generate statistics for WikiProject Articles for Creation. @@ -52,6 +45,15 @@ class Task(BaseTask): name = "afc_statistics" number = 2 + # Chart status number constants: + CHART_NONE = 0 + CHART_PEND = 1 + CHART_DRAFT = 2 + CHART_REVIEW = 3 + CHART_ACCEPT = 4 + CHART_DECLINE = 5 + CHART_MISPLACE = 6 + def setup(self): self.cfg = cfg = self.config.tasks.get(self.name, {}) @@ -82,7 +84,7 @@ class Task(BaseTask): (self.save()). We will additionally create an SQL connection with our local database. """ - self.site = wiki.get_site() + self.site = self.bot.wiki.get_site() with self.db_access_lock: self.conn = oursql.connect(**self.conn_data) @@ -285,7 +287,7 @@ class Task(BaseTask): query = """DELETE FROM page, row USING page JOIN row ON page_id = row_id WHERE row_chart IN (?, ?) AND ADDTIME(page_special_time, '36:00:00') < NOW()""" - cursor.execute(query, (CHART_ACCEPT, CHART_DECLINE)) + cursor.execute(query, (self.CHART_ACCEPT, self.CHART_DECLINE)) def update(self, **kwargs): """Update a page by name, regardless of whether anything has changed. @@ -332,7 +334,7 @@ class Task(BaseTask): namespace = self.site.get_page(title).namespace() status, chart = self.get_status_and_chart(content, namespace) - if chart == CHART_NONE: + if chart == self.CHART_NONE: msg = "Could not find a status for [[{0}]]".format(title) self.logger.warn(msg) return @@ -366,7 +368,7 @@ class Task(BaseTask): namespace = self.site.get_page(title).namespace() status, chart = self.get_status_and_chart(content, namespace) - if chart == CHART_NONE: + if chart == self.CHART_NONE: self.untrack_page(cursor, pageid) return @@ -498,23 +500,23 @@ class Task(BaseTask): statuses = self.get_statuses(content) if "R" in statuses: - status, chart = "r", CHART_REVIEW + status, chart = "r", self.CHART_REVIEW elif "H" in statuses: - status, chart = "p", CHART_DRAFT + status, chart = "p", self.CHART_DRAFT elif "P" in statuses: - status, chart = "p", CHART_PEND + status, chart = "p", self.CHART_PEND elif "T" in statuses: - status, chart = None, CHART_NONE + status, chart = None, self.CHART_NONE elif "D" in statuses: - status, chart = "d", CHART_DECLINE + status, chart = "d", self.CHART_DECLINE else: - status, chart = None, CHART_NONE + status, chart = None, self.CHART_NONE if namespace == wiki.NS_MAIN: if not statuses: - status, chart = "a", CHART_ACCEPT + status, chart = "a", self.CHART_ACCEPT else: - status, chart = None, CHART_MISPLACE + status, chart = None, self.CHART_MISPLACE return status, chart @@ -613,23 +615,23 @@ class Task(BaseTask): returned if we cannot determine when the page was "special"-ed, or if it was "special"-ed more than 250 edits ago. """ - if chart ==CHART_NONE: + if chart ==self.CHART_NONE: return None, None, None - elif chart == CHART_MISPLACE: + elif chart == self.CHART_MISPLACE: return self.get_create(pageid) - elif chart == CHART_ACCEPT: + elif chart == self.CHART_ACCEPT: search_for = None search_not = ["R", "H", "P", "T", "D"] - elif chart == CHART_DRAFT: + elif chart == self.CHART_DRAFT: search_for = "H" search_not = [] - elif chart == CHART_PEND: + elif chart == self.CHART_PEND: search_for = "P" search_not = [] - elif chart == CHART_REVIEW: + elif chart == self.CHART_REVIEW: search_for = "R" search_not = [] - elif chart == CHART_DECLINE: + elif chart == self.CHART_DECLINE: search_for = "D" search_not = ["R", "H", "P", "T"] @@ -683,12 +685,12 @@ class Task(BaseTask): """ notes = "" - ignored_charts = [CHART_NONE, CHART_ACCEPT, CHART_DECLINE] + ignored_charts = [self.CHART_NONE, self.CHART_ACCEPT, self.CHART_DECLINE] if chart in ignored_charts: return notes statuses = self.get_statuses(content) - if "D" in statuses and chart != CHART_MISPLACE: + if "D" in statuses and chart != self.CHART_MISPLACE: notes += "|nr=1" # Submission was resubmitted if len(content) < 500: @@ -705,7 +707,7 @@ class Task(BaseTask): if time_since_modify > max_time: notes += "|no=1" # Submission hasn't been touched in over 4 days - if chart in [CHART_PEND, CHART_DRAFT]: + if chart in [self.CHART_PEND, self.CHART_DRAFT]: submitter = self.site.get_user(s_user) try: if submitter.blockinfo(): diff --git a/earwigbot/tasks/afc_undated.py b/earwigbot/tasks/afc_undated.py index e596d1d..93144e8 100644 --- a/earwigbot/tasks/afc_undated.py +++ b/earwigbot/tasks/afc_undated.py @@ -22,6 +22,8 @@ from earwigbot.tasks import BaseTask +__all__ = ["Task"] + class Task(BaseTask): """A task to clear [[Category:Undated AfC submissions]].""" name = "afc_undated" diff --git a/earwigbot/tasks/blptag.py b/earwigbot/tasks/blptag.py index 505b7d9..76f80be 100644 --- a/earwigbot/tasks/blptag.py +++ b/earwigbot/tasks/blptag.py @@ -22,6 +22,8 @@ from earwigbot.tasks import BaseTask +__all__ = ["Task"] + class Task(BaseTask): """A task to add |blp=yes to {{WPB}} or {{WPBS}} when it is used along with {{WP Biography}}.""" diff --git a/earwigbot/tasks/feed_dailycats.py b/earwigbot/tasks/feed_dailycats.py index a068af6..361b16d 100644 --- a/earwigbot/tasks/feed_dailycats.py +++ b/earwigbot/tasks/feed_dailycats.py @@ -22,6 +22,8 @@ from earwigbot.tasks import BaseTask +__all__ = ["Task"] + class Task(BaseTask): """A task to create daily categories for [[WP:FEED]].""" name = "feed_dailycats" diff --git a/earwigbot/tasks/wikiproject_tagger.py b/earwigbot/tasks/wikiproject_tagger.py new file mode 100644 index 0000000..6b63d6d --- /dev/null +++ b/earwigbot/tasks/wikiproject_tagger.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2009-2012 by Ben Kurtovic +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from earwigbot.tasks import BaseTask + +__all__ = ["Task"] + +class Task(BaseTask): + """A task to tag talk pages with WikiProject Banners.""" + name = "wikiproject_tagger" + + def setup(self): + pass + + def run(self, **kwargs): + pass diff --git a/earwigbot/tasks/wrongmime.py b/earwigbot/tasks/wrongmime.py index ed531d5..484fb7b 100644 --- a/earwigbot/tasks/wrongmime.py +++ b/earwigbot/tasks/wrongmime.py @@ -22,6 +22,8 @@ from earwigbot.tasks import BaseTask +__all__ = ["Task"] + class Task(BaseTask): """A task to tag files whose extensions do not agree with their MIME type.""" diff --git a/earwigbot/util.py b/earwigbot/util.py index 915747a..8b3ad5a 100755 --- a/earwigbot/util.py +++ b/earwigbot/util.py @@ -27,6 +27,8 @@ from os import path from earwigbot import __version__ from earwigbot.bot import Bot +__all__ = ["BotUtility", "main"] + class BotUtility(object): """ DOCSTRING NEEDED diff --git a/earwigbot/wiki/__init__.py b/earwigbot/wiki/__init__.py index 00b5dd4..f2f0e89 100644 --- a/earwigbot/wiki/__init__.py +++ b/earwigbot/wiki/__init__.py @@ -28,21 +28,21 @@ Wikipedia and other wiki sites. No connection whatsoever to python-wikitools written by Mr.Z-man, other than a similar purpose. We share no code. Import the toolset directly with `from earwigbot import wiki`. If using the -built-in integration with the rest of the bot, that's usually not necessary: -Bot() objects contain a `wiki` attribute containing a SitesDBManager object -tied to the sites.db file located in the same directory as config.yml. That -object has the principal methods get_site, add_site, and remove_site. +built-in integration with the rest of the bot, Bot() objects contain a `wiki` +attribute, which is a SitesDBManager object tied to the sites.db file located +in the same directory as config.yml. That object has the principal methods +get_site, add_site, and remove_site that should handle all of your Site (and +thus, Page, Category, and User) needs. """ import logging as _log logger = _log.getLogger("earwigbot.wiki") logger.addHandler(_log.NullHandler()) +from earwigbot.wiki.category import * from earwigbot.wiki.constants import * from earwigbot.wiki.exceptions import * - -from earwigbot.wiki.category import Category -from earwigbot.wiki.page import Page -from earwigbot.wiki.site import Site -from earwigbot.wiki.sitesdb import SitesDBManager -from earwigbot.wiki.user import User +from earwigbot.wiki.page import * +from earwigbot.wiki.site import * +from earwigbot.wiki.sitesdb import * +from earwigbot.wiki.user import * diff --git a/earwigbot/wiki/category.py b/earwigbot/wiki/category.py index c220674..67426f4 100644 --- a/earwigbot/wiki/category.py +++ b/earwigbot/wiki/category.py @@ -22,6 +22,8 @@ from earwigbot.wiki.page import Page +__all__ = ["Category"] + class Category(Page): """ EarwigBot's Wiki Toolset: Category Class diff --git a/earwigbot/wiki/constants.py b/earwigbot/wiki/constants.py index 22aef9c..8e818a6 100644 --- a/earwigbot/wiki/constants.py +++ b/earwigbot/wiki/constants.py @@ -27,13 +27,16 @@ This module defines some useful constants: * USER_AGENT - our default User Agent when making API queries * NS_* - default namespace IDs for easy lookup -Import with `from earwigbot.wiki import constants` or `from earwigbot.wiki.constants import *`. +Import directly with `from earwigbot.wiki import constants` or +`from earwigbot.wiki.constants import *`. These are also available from +earwigbot.wiki (e.g. `earwigbot.wiki.USER_AGENT`). """ # Default User Agent when making API queries: from earwigbot import __version__ as _v from platform import python_version as _p USER_AGENT = "EarwigBot/{0} (Python/{1}; https://github.com/earwig/earwigbot)".format(_v, _p()) +del _v, _p # Default namespace IDs: NS_MAIN = 0 diff --git a/earwigbot/wiki/page.py b/earwigbot/wiki/page.py index dfd5268..957878e 100644 --- a/earwigbot/wiki/page.py +++ b/earwigbot/wiki/page.py @@ -28,6 +28,8 @@ from urllib import quote from earwigbot.wiki.copyright import CopyrightMixin from earwigbot.wiki.exceptions import * +__all__ = ["Page"] + class Page(CopyrightMixin): """ EarwigBot's Wiki Toolset: Page Class diff --git a/earwigbot/wiki/site.py b/earwigbot/wiki/site.py index 5c0b1c7..f5a3aca 100644 --- a/earwigbot/wiki/site.py +++ b/earwigbot/wiki/site.py @@ -43,6 +43,8 @@ from earwigbot.wiki.exceptions import * from earwigbot.wiki.page import Page from earwigbot.wiki.user import User +__all__ = ["Site"] + class Site(object): """ EarwigBot's Wiki Toolset: Site Class diff --git a/earwigbot/wiki/user.py b/earwigbot/wiki/user.py index 880b804..2747e2d 100644 --- a/earwigbot/wiki/user.py +++ b/earwigbot/wiki/user.py @@ -26,6 +26,8 @@ from earwigbot.wiki.constants import * from earwigbot.wiki.exceptions import UserNotFoundError from earwigbot.wiki.page import Page +__all__ = ["User"] + class User(object): """ EarwigBot's Wiki Toolset: User Class diff --git a/setup.py b/setup.py index 315498b..67234d9 100644 --- a/setup.py +++ b/setup.py @@ -42,7 +42,7 @@ setup( url = "https://github.com/earwig/earwigbot", description = "EarwigBot is a Python robot that edits Wikipedia and interacts with people over IRC.", long_description = long_docs, - download_url = "https://github.com/earwig/earwigbot/tarball/{0}".format(__version__), + download_url = "https://github.com/earwig/earwigbot/tarball/v{0}".format(__version__), keywords = "earwig earwigbot irc wikipedia wiki mediawiki", license = "MIT License", classifiers = [