Browse Source

Fix all references to earwigbot.config.config; update SitesDBManager

tags/v0.1^2
Ben Kurtovic 12 years ago
parent
commit
8a7eb798a3
14 changed files with 48 additions and 76 deletions
  1. +11
    -7
      earwigbot/bot.py
  2. +3
    -2
      earwigbot/commands/__init__.py
  3. +1
    -2
      earwigbot/commands/afc_status.py
  4. +1
    -2
      earwigbot/commands/chanops.py
  5. +1
    -2
      earwigbot/commands/ctcp.py
  6. +1
    -2
      earwigbot/commands/git.py
  7. +1
    -2
      earwigbot/commands/restart.py
  8. +2
    -3
      earwigbot/commands/threads.py
  9. +1
    -0
      earwigbot/tasks/__init__.py
  10. +1
    -2
      earwigbot/tasks/afc_copyvios.py
  11. +1
    -2
      earwigbot/tasks/afc_history.py
  12. +1
    -2
      earwigbot/tasks/afc_statistics.py
  13. +6
    -2
      earwigbot/wiki/__init__.py
  14. +17
    -46
      earwigbot/wiki/sitesdb.py

+ 11
- 7
earwigbot/bot.py View File

@@ -27,6 +27,7 @@ from earwigbot.commands import CommandManager
from earwigbot.config import BotConfig from earwigbot.config import BotConfig
from earwigbot.irc import Frontend, Watcher from earwigbot.irc import Frontend, Watcher
from earwigbot.tasks import TaskManager from earwigbot.tasks import TaskManager
from earwigbot.wiki import SitesDBManager


__all__ = ["Bot"] __all__ = ["Bot"]


@@ -51,6 +52,7 @@ class Bot(object):
self.logger = logging.getLogger("earwigbot") self.logger = logging.getLogger("earwigbot")
self.commands = CommandManager(self) self.commands = CommandManager(self)
self.tasks = TaskManager(self) self.tasks = TaskManager(self)
self.wiki = SitesDBManager(self.config)
self.frontend = None self.frontend = None
self.watcher = None self.watcher = None


@@ -100,12 +102,13 @@ class Bot(object):
sleep(5) sleep(5)


def run(self): def run(self):
self.config.load()
self.config.decrypt(config.wiki, "password")
self.config.decrypt(config.wiki, "search", "credentials", "key")
self.config.decrypt(config.wiki, "search", "credentials", "secret")
self.config.decrypt(config.irc, "frontend", "nickservPassword")
self.config.decrypt(config.irc, "watcher", "nickservPassword")
config = self.config
config.load()
config.decrypt(config.wiki, "password")
config.decrypt(config.wiki, "search", "credentials", "key")
config.decrypt(config.wiki, "search", "credentials", "secret")
config.decrypt(config.irc, "frontend", "nickservPassword")
config.decrypt(config.irc, "watcher", "nickservPassword")
self.commands.load() self.commands.load()
self.tasks.load() self.tasks.load()
self._start_irc_components() self._start_irc_components()
@@ -121,6 +124,7 @@ class Bot(object):
self._start_irc_components() self._start_irc_components()


def stop(self): def stop(self):
self._stop_irc_components()
with self.component_lock:
self._stop_irc_components()
self._keep_looping = False self._keep_looping = False
sleep(3) # Give a few seconds to finish closing IRC connections sleep(3) # Give a few seconds to finish closing IRC connections

+ 3
- 2
earwigbot/commands/__init__.py View File

@@ -58,9 +58,10 @@ class BaseCommand(object):
super(Command, self).__init__() first. super(Command, self).__init__() first.
""" """
self.bot = bot self.bot = bot
self.config = bot.config
self.logger = bot.commands.getLogger(self.name) self.logger = bot.commands.getLogger(self.name)


def _execute(self, data):
def _wrap_process(self, data):
"""Make a quick connection alias and then process() the message.""" """Make a quick connection alias and then process() the message."""
self.connection = self.bot.frontend self.connection = self.bot.frontend
self.process(data) self.process(data)
@@ -158,7 +159,7 @@ class CommandManager(object):
if hook in command.hooks: if hook in command.hooks:
if command.check(data): if command.check(data):
try: try:
command._execute(data)
command._wrap_process(data)
except Exception: except Exception:
e = "Error executing command '{0}':" e = "Error executing command '{0}':"
self.logger.exception(e.format(data.command)) self.logger.exception(e.format(data.command))


+ 1
- 2
earwigbot/commands/afc_status.py View File

@@ -24,7 +24,6 @@ import re


from earwigbot import wiki from earwigbot import wiki
from earwigbot.commands import BaseCommand from earwigbot.commands import BaseCommand
from earwigbot.config import config


class Command(BaseCommand): class Command(BaseCommand):
"""Get the number of pending AfC submissions, open redirect requests, and """Get the number of pending AfC submissions, open redirect requests, and
@@ -39,7 +38,7 @@ class Command(BaseCommand):


try: try:
if data.line[1] == "JOIN" and data.chan == "#wikipedia-en-afc": if data.line[1] == "JOIN" and data.chan == "#wikipedia-en-afc":
if data.nick != config.irc["frontend"]["nick"]:
if data.nick != self.config.irc["frontend"]["nick"]:
return True return True
except IndexError: except IndexError:
pass pass


+ 1
- 2
earwigbot/commands/chanops.py View File

@@ -21,7 +21,6 @@
# SOFTWARE. # SOFTWARE.


from earwigbot.commands import BaseCommand from earwigbot.commands import BaseCommand
from earwigbot.config import config


class Command(BaseCommand): class Command(BaseCommand):
"""Voice, devoice, op, or deop users in the channel.""" """Voice, devoice, op, or deop users in the channel."""
@@ -39,7 +38,7 @@ class Command(BaseCommand):
self.connection.reply(data, msg) self.connection.reply(data, msg)
return return


if data.host not in config.irc["permissions"]["admins"]:
if data.host not in self.config.irc["permissions"]["admins"]:
msg = "you must be a bot admin to use this command." msg = "you must be a bot admin to use this command."
self.connection.reply(data, msg) self.connection.reply(data, msg)
return return


+ 1
- 2
earwigbot/commands/ctcp.py View File

@@ -25,7 +25,6 @@ import time


from earwigbot import __version__ from earwigbot import __version__
from earwigbot.commands import BaseCommand from earwigbot.commands import BaseCommand
from earwigbot.config import config


class Command(BaseCommand): class Command(BaseCommand):
"""Not an actual command, this module is used to respond to the CTCP """Not an actual command, this module is used to respond to the CTCP
@@ -63,7 +62,7 @@ class Command(BaseCommand):


elif command == "VERSION": elif command == "VERSION":
default = "EarwigBot - $1 - Python/$2 https://github.com/earwig/earwigbot" default = "EarwigBot - $1 - Python/$2 https://github.com/earwig/earwigbot"
vers = config.irc.get("version", default)
vers = self.config.irc.get("version", default)
vers = vers.replace("$1", __version__) vers = vers.replace("$1", __version__)
vers = vers.replace("$2", platform.python_version()) vers = vers.replace("$2", platform.python_version())
self.connection.notice(target, "\x01VERSION {0}\x01".format(vers)) self.connection.notice(target, "\x01VERSION {0}\x01".format(vers))

+ 1
- 2
earwigbot/commands/git.py View File

@@ -25,7 +25,6 @@ import subprocess
import re import re


from earwigbot.commands import BaseCommand from earwigbot.commands import BaseCommand
from earwigbot.config import config


class Command(BaseCommand): class Command(BaseCommand):
"""Commands to interface with the bot's git repository; use '!git' for a """Commands to interface with the bot's git repository; use '!git' for a
@@ -34,7 +33,7 @@ class Command(BaseCommand):


def process(self, data): def process(self, data):
self.data = data self.data = data
if data.host not in config.irc["permissions"]["owners"]:
if data.host not in self.config.irc["permissions"]["owners"]:
msg = "you must be a bot owner to use this command." msg = "you must be a bot owner to use this command."
self.connection.reply(data, msg) self.connection.reply(data, msg)
return return


+ 1
- 2
earwigbot/commands/restart.py View File

@@ -21,7 +21,6 @@
# SOFTWARE. # SOFTWARE.


from earwigbot.commands import BaseCommand from earwigbot.commands import BaseCommand
from earwigbot.config import config


class Command(BaseCommand): class Command(BaseCommand):
"""Restart the bot. Only the owner can do this.""" """Restart the bot. Only the owner can do this."""
@@ -32,7 +31,7 @@ class Command(BaseCommand):
return data.is_command and data.command in commands return data.is_command and data.command in commands


def process(self, data): def process(self, data):
if data.host not in config.irc["permissions"]["owners"]:
if data.host not in self.config.irc["permissions"]["owners"]:
msg = "you must be a bot owner to use this command." msg = "you must be a bot owner to use this command."
self.connection.reply(data, msg) self.connection.reply(data, msg)
return return


+ 2
- 3
earwigbot/commands/threads.py View File

@@ -24,7 +24,6 @@ import threading
import re import re


from earwigbot.commands import BaseCommand from earwigbot.commands import BaseCommand
from earwigbot.config import config
from earwigbot.irc import KwargParseException from earwigbot.irc import KwargParseException
from earwigbot.tasks import task_manager from earwigbot.tasks import task_manager


@@ -40,7 +39,7 @@ class Command(BaseCommand):


def process(self, data): def process(self, data):
self.data = data self.data = data
if data.host not in config.irc["permissions"]["owners"]:
if data.host not in self.config.irc["permissions"]["owners"]:
msg = "you must be a bot owner to use this command." msg = "you must be a bot owner to use this command."
self.connection.reply(data, msg) self.connection.reply(data, msg)
return return
@@ -80,7 +79,7 @@ class Command(BaseCommand):
if tname == "MainThread": if tname == "MainThread":
t = "\x0302MainThread\x0301 (id {1})" t = "\x0302MainThread\x0301 (id {1})"
normal_threads.append(t.format(thread.ident)) normal_threads.append(t.format(thread.ident))
elif tname in config.components:
elif tname in self.config.components:
t = "\x0302{0}\x0301 (id {1})" t = "\x0302{0}\x0301 (id {1})"
normal_threads.append(t.format(tname, thread.ident)) normal_threads.append(t.format(tname, thread.ident))
elif tname.startswith("reminder"): elif tname.startswith("reminder"):


+ 1
- 0
earwigbot/tasks/__init__.py View File

@@ -50,6 +50,7 @@ class BaseTask(object):
(or if you do, remember super(Task, self).__init()) - use setup(). (or if you do, remember super(Task, self).__init()) - use setup().
""" """
self.bot = bot self.bot = bot
self.config = bot.config
self.logger = bot.tasks.logger.getLogger(self.name) self.logger = bot.tasks.logger.getLogger(self.name)
self.setup() self.setup()




+ 1
- 2
earwigbot/tasks/afc_copyvios.py View File

@@ -27,7 +27,6 @@ from threading import Lock
import oursql import oursql


from earwigbot import wiki from earwigbot import wiki
from earwigbot.config import config
from earwigbot.tasks import BaseTask from earwigbot.tasks import BaseTask


class Task(BaseTask): class Task(BaseTask):
@@ -37,7 +36,7 @@ class Task(BaseTask):
number = 1 number = 1


def setup(self): def setup(self):
cfg = config.tasks.get(self.name, {})
cfg = self.config.tasks.get(self.name, {})
self.template = cfg.get("template", "AfC suspected copyvio") self.template = cfg.get("template", "AfC suspected copyvio")
self.ignore_list = cfg.get("ignoreList", []) self.ignore_list = cfg.get("ignoreList", [])
self.min_confidence = cfg.get("minConfidence", 0.5) self.min_confidence = cfg.get("minConfidence", 0.5)


+ 1
- 2
earwigbot/tasks/afc_history.py View File

@@ -32,7 +32,6 @@ from numpy import arange
import oursql import oursql


from earwigbot import wiki from earwigbot import wiki
from earwigbot.config import config
from earwigbot.tasks import BaseTask from earwigbot.tasks import BaseTask


# Valid submission statuses: # Valid submission statuses:
@@ -58,7 +57,7 @@ class Task(BaseTask):
name = "afc_history" name = "afc_history"


def setup(self): def setup(self):
cfg = config.tasks.get(self.name, {})
cfg = self.config.tasks.get(self.name, {})
self.num_days = cfg.get("days", 90) self.num_days = cfg.get("days", 90)
self.categories = cfg.get("categories", {}) self.categories = cfg.get("categories", {})




+ 1
- 2
earwigbot/tasks/afc_statistics.py View File

@@ -30,7 +30,6 @@ from time import sleep
import oursql import oursql


from earwigbot import wiki from earwigbot import wiki
from earwigbot.config import config
from earwigbot.tasks import BaseTask from earwigbot.tasks import BaseTask


# Chart status number constants: # Chart status number constants:
@@ -54,7 +53,7 @@ class Task(BaseTask):
number = 2 number = 2


def setup(self): def setup(self):
self.cfg = cfg = config.tasks.get(self.name, {})
self.cfg = cfg = self.config.tasks.get(self.name, {})


# Set some wiki-related attributes: # Set some wiki-related attributes:
self.pagename = cfg.get("page", "Template:AFC statistics") self.pagename = cfg.get("page", "Template:AFC statistics")


+ 6
- 2
earwigbot/wiki/__init__.py View File

@@ -27,7 +27,11 @@ This is a collection of classes and functions to read from and write to
Wikipedia and other wiki sites. No connection whatsoever to python-wikitools 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. written by Mr.Z-man, other than a similar purpose. We share no code.


Import the toolset with `from earwigbot import wiki`.
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.
""" """


import logging as _log import logging as _log
@@ -40,5 +44,5 @@ from earwigbot.wiki.exceptions import *
from earwigbot.wiki.category import Category from earwigbot.wiki.category import Category
from earwigbot.wiki.page import Page from earwigbot.wiki.page import Page
from earwigbot.wiki.site import Site from earwigbot.wiki.site import Site
from earwigbot.wiki.sitesdb import get_site, add_site, remove_site
from earwigbot.wiki.sitesdb import SitesDBManager
from earwigbot.wiki.user import User from earwigbot.wiki.user import User

+ 17
- 46
earwigbot/wiki/sitesdb.py View File

@@ -29,11 +29,10 @@ import stat
import sqlite3 as sqlite import sqlite3 as sqlite


from earwigbot import __version__ from earwigbot import __version__
from earwigbot.config import config
from earwigbot.wiki.exceptions import SiteNotFoundError from earwigbot.wiki.exceptions import SiteNotFoundError
from earwigbot.wiki.site import Site from earwigbot.wiki.site import Site


__all__ = ["SitesDBManager", "get_site", "add_site", "remove_site"]
__all__ = ["SitesDBManager"]


class SitesDBManager(object): class SitesDBManager(object):
""" """
@@ -47,31 +46,19 @@ class SitesDBManager(object):
remove_site -- removes a site from the database, given its name remove_site -- removes a site from the database, given its name


There's usually no need to use this class directly. All public methods There's usually no need to use this class directly. All public methods
here are available as earwigbot.wiki.get_site(), earwigbot.wiki.add_site(),
and earwigbot.wiki.remove_site(), which use a sites.db file located in the
same directory as our config.yml file. Lower-level access can be achieved
here are available as bot.wiki.get_site(), bot.wiki.add_site(), and
bot.wiki.remove_site(), which use a sites.db file located in the same
directory as our config.yml file. Lower-level access can be achieved
by importing the manager class by importing the manager class
(`from earwigbot.wiki.sitesdb import SitesDBManager`).
(`from earwigbot.wiki import SitesDBManager`).
""" """


def __init__(self, db_file):
"""Set up the manager with an attribute for the sitesdb filename."""
def __init__(self, config):
"""Set up the manager with an attribute for the BotConfig object."""
self.config = config
self._sitesdb = path.join(config.root_dir, "sitesdb")
self._cookie_file = path.join(config.root_dir, ".cookies")
self._cookiejar = None self._cookiejar = None
self._sitesdb = db_file

def _load_config(self):
"""Load the bot's config.

Called by a config-requiring function, such as get_site(), when config
has not been loaded. This will usually happen only if we're running
code directly from Python's interpreter and not the bot itself, because
bot.py and earwigbot.runner will already call these functions.
"""
is_encrypted = config.load()
if is_encrypted: # Passwords in the config file are encrypted
key = getpass("Enter key to unencrypt bot passwords: ")
config._decryption_key = key
config.decrypt(config.wiki, "password")


def _get_cookiejar(self): def _get_cookiejar(self):
"""Return a LWPCookieJar object loaded from our .cookies file. """Return a LWPCookieJar object loaded from our .cookies file.
@@ -89,8 +76,7 @@ class SitesDBManager(object):
if self._cookiejar: if self._cookiejar:
return self._cookiejar return self._cookiejar


cookie_file = path.join(config.root_dir, ".cookies")
self._cookiejar = LWPCookieJar(cookie_file)
self._cookiejar = LWPCookieJar(self._cookie_file)


try: try:
self._cookiejar.load() self._cookiejar.load()
@@ -163,10 +149,12 @@ class SitesDBManager(object):
This calls _load_site_from_sitesdb(), so SiteNotFoundError will be This calls _load_site_from_sitesdb(), so SiteNotFoundError will be
raised if the site is not in our sitesdb. raised if the site is not in our sitesdb.
""" """
cookiejar = self._get_cookiejar()
(name, project, lang, base_url, article_path, script_path, sql, (name, project, lang, base_url, article_path, script_path, sql,
namespaces) = self._load_site_from_sitesdb(name) namespaces) = self._load_site_from_sitesdb(name)

config = self.config
login = (config.wiki.get("username"), config.wiki.get("password")) login = (config.wiki.get("username"), config.wiki.get("password"))
cookiejar = self._get_cookiejar()
user_agent = config.wiki.get("userAgent") user_agent = config.wiki.get("userAgent")
use_https = config.wiki.get("useHTTPS", False) use_https = config.wiki.get("useHTTPS", False)
assert_edit = config.wiki.get("assert") assert_edit = config.wiki.get("assert")
@@ -265,9 +253,6 @@ class SitesDBManager(object):
cannot be found in the sitesdb, SiteNotFoundError will be raised. An cannot be found in the sitesdb, SiteNotFoundError will be raised. An
empty sitesdb will be created if none is found. empty sitesdb will be created if none is found.
""" """
if not config.is_loaded():
self._load_config()

# Someone specified a project without a lang, or vice versa: # Someone specified a project without a lang, or vice versa:
if (project and not lang) or (not project and lang): if (project and not lang) or (not project and lang):
e = "Keyword arguments 'lang' and 'project' must be specified together." e = "Keyword arguments 'lang' and 'project' must be specified together."
@@ -276,7 +261,7 @@ class SitesDBManager(object):
# No args given, so return our default site: # No args given, so return our default site:
if not name and not project and not lang: if not name and not project and not lang:
try: try:
default = config.wiki["defaultSite"]
default = self.config.wiki["defaultSite"]
except KeyError: except KeyError:
e = "Default site is not specified in config." e = "Default site is not specified in config."
raise SiteNotFoundError(e) raise SiteNotFoundError(e)
@@ -322,17 +307,15 @@ class SitesDBManager(object):
site info). Raises SiteNotFoundError if not enough information has site info). Raises SiteNotFoundError if not enough information has
been provided to identify the site (e.g. a project but not a lang). been provided to identify the site (e.g. a project but not a lang).
""" """
if not config.is_loaded():
self._load_config()

if not base_url: if not base_url:
if not project or not lang: if not project or not lang:
e = "Without a base_url, both a project and a lang must be given." e = "Without a base_url, both a project and a lang must be given."
raise SiteNotFoundError(e) raise SiteNotFoundError(e)
base_url = "//{0}.{1}.org".format(lang, project) base_url = "//{0}.{1}.org".format(lang, project)
cookiejar = self._get_cookiejar()


config = self.config
login = (config.wiki.get("username"), config.wiki.get("password")) login = (config.wiki.get("username"), config.wiki.get("password"))
cookiejar = self._get_cookiejar()
user_agent = config.wiki.get("userAgent") user_agent = config.wiki.get("userAgent")
use_https = config.wiki.get("useHTTPS", False) use_https = config.wiki.get("useHTTPS", False)
assert_edit = config.wiki.get("assert") assert_edit = config.wiki.get("assert")
@@ -358,9 +341,6 @@ class SitesDBManager(object):
was given but not a language, or vice versa. Will create an empty was given but not a language, or vice versa. Will create an empty
sitesdb if none was found. sitesdb if none was found.
""" """
if not config.is_loaded():
self._load_config()

# Someone specified a project without a lang, or vice versa: # Someone specified a project without a lang, or vice versa:
if (project and not lang) or (not project and lang): if (project and not lang) or (not project and lang):
e = "Keyword arguments 'lang' and 'project' must be specified together." e = "Keyword arguments 'lang' and 'project' must be specified together."
@@ -381,12 +361,3 @@ class SitesDBManager(object):
return self._remove_site_from_sitesdb(name) return self._remove_site_from_sitesdb(name)


return False return False

_root = path.split(path.split(path.dirname(path.abspath(__file__)))[0])[0]
_dbfile = path.join(_root, "sites.db")
_manager = SitesDBManager(_dbfile)
del _root, _dbfile

get_site = _manager.get_site
add_site = _manager.add_site
remove_site = _manager.remove_site

Loading…
Cancel
Save