소스 검색

CommandManager as attr of Bot, plus cleanup

tags/v0.1^2
Ben Kurtovic 12 년 전
부모
커밋
abe58a07f6
6개의 변경된 파일74개의 추가작업 그리고 63개의 파일을 삭제
  1. +13
    -9
      earwigbot/bot.py
  2. +34
    -41
      earwigbot/commands/__init__.py
  3. +4
    -4
      earwigbot/irc/frontend.py
  4. +5
    -3
      earwigbot/irc/watcher.py
  5. +14
    -4
      earwigbot/util.py
  6. +4
    -2
      setup.py

+ 13
- 9
earwigbot/bot.py 파일 보기

@@ -23,10 +23,13 @@
import threading
from time import sleep, time

from earwigbot.commands import CommandManager
from earwigbot.config import BotConfig
from earwigbot.irc import Frontend, Watcher
from earwigbot.tasks import task_manager

__all__ = ["Bot"]

class Bot(object):
"""
The Bot class is the core of EarwigBot, essentially responsible for
@@ -46,16 +49,14 @@ class Bot(object):
def __init__(self, root_dir):
self.config = BotConfig(root_dir)
self.logger = logging.getLogger("earwigbot")
self.commands = CommandManager(self)
self.tasks = None
self.frontend = None
self.watcher = None

self._keep_scheduling = True
self._lock = threading.Lock()

def _start_thread(self, name, target):
thread = threading.Thread(name=name, target=target)
thread.start()

def _wiki_scheduler(self):
while self._keep_scheduling:
time_start = time()
@@ -68,17 +69,18 @@ class Bot(object):
def _start_components(self):
if self.config.components.get("irc_frontend"):
self.logger.info("Starting IRC frontend")
self.frontend = Frontend(self.config)
self._start_thread(name, self.frontend.loop)
self.frontend = Frontend(self)
self.commands.load()
threading.Thread(name=name, target=self.frontend.loop).start()

if self.config.components.get("irc_watcher"):
self.logger.info("Starting IRC watcher")
self.watcher = Watcher(self.config, self.frontend)
self._start_thread(name, self.watcher.loop)
self.watcher = Watcher(self)
threading.Thread(name=name, target=self.watcher.loop).start()

if self.config.components.get("wiki_scheduler"):
self.logger.info("Starting wiki scheduler")
self._start_thread(name, self._wiki_scheduler)
threading.Thread(name=name, target=self._wiki_scheduler).start()

def _loop(self):
while 1:
@@ -104,6 +106,7 @@ class Bot(object):
with self._lock:
self.config.load()
#if self.config.components.get("irc_frontend"):
# self.commands.load()

def stop(self):
if self.frontend:
@@ -111,3 +114,4 @@ class Bot(object):
if self.watcher:
self.watcher.stop()
self._keep_scheduling = False
sleep(3) # Give a few seconds to finish closing IRC connections

+ 34
- 41
earwigbot/commands/__init__.py 파일 보기

@@ -25,17 +25,16 @@ EarwigBot's IRC Command Manager

This package provides the IRC "commands" used by the bot's front-end component.
This module contains the BaseCommand class (import with
`from earwigbot.commands import BaseCommand`) and an internal _CommandManager
class. This can be accessed through the `command_manager` singleton.
`from earwigbot.commands import BaseCommand`) and an internal CommandManager
class. This can be accessed through `bot.commands`.
"""

import imp
import logging
import os
import sys
from os import listdir, path
from re import sub

from earwigbot.config import config

__all__ = ["BaseCommand", "command_manager"]
__all__ = ["BaseCommand", "CommandManager"]

class BaseCommand(object):
"""A base class for commands on IRC.
@@ -88,32 +87,33 @@ class BaseCommand(object):
pass


class _CommandManager(object):
def __init__(self):
class CommandManager(object):
def __init__(self, bot):
self.bot = bot
self.logger = logging.getLogger("earwigbot.tasks")
self._base_dir = os.path.dirname(os.path.abspath(__file__))
self._connection = None
self._dirs = [path.dirname(__file__), bot.config.root_dir]
self._commands = {}

def _load_command(self, filename):
"""Load a specific command from a module, identified by filename.
def _load_command(self, name, path):
"""Load a specific command from a module, identified by name and path.

Given a Connection object and a filename, we'll first try to import
it, and if that works, make an instance of the 'Command' class inside
(assuming it is an instance of BaseCommand), add it to self._commands,
and log the addition. Any problems along the way will either be
ignored or logged.
We'll first try to import it using imp magic, and if that works, make
an instance of the 'Command' class inside (assuming it is an instance
of BaseCommand), add it to self._commands, and log the addition. Any
problems along the way will either be ignored or logged.
"""
# Strip .py from the filename's end and join with our package name:
name = ".".join(("commands", filename[:-3]))
f, path, desc = imp.find_module(name, [path])
try:
__import__(name)
except:
self.logger.exception("Couldn't load file {0}".format(filename))
module = imp.load_module(name, f, path, desc)
except Exception:
e = "Couldn't load module {0} from {1}"
self.logger.exception(e.format(name, path))
return
finally:
f.close()

try:
command = sys.modules[name].Command(self._connection)
command = module.Command(self.bot.frontend)
except AttributeError:
return # No command in this module
if not isinstance(command, BaseCommand):
@@ -122,20 +122,16 @@ class _CommandManager(object):
self._commands[command.name] = command
self.logger.debug("Added command {0}".format(command.name))

def load(self, connection):
"""Load all valid commands into self._commands.

`connection` is a Connection object that is given to each command's
constructor.
"""
self._connection = connection

files = os.listdir(self._base_dir)
files.sort()
for filename in files:
if filename.startswith("_") or not filename.endswith(".py"):
continue
self._load_command(filename)
def load(self):
"""Load (or reload) all valid commands into self._commands."""
dirs = [path.join(path.dirname(__file__), "commands"),
path.join(bot.config.root_dir, "commands")]
for dir in dirs:
files = listdir(dir)
files = [sub("\.pyc?$", "", f) for f in files if f[0] != "_"]
files = list(set(files)) # Remove duplicates
for filename in sorted(files):
self._load_command(filename, dir)

msg = "Found {0} commands: {1}"
commands = ", ".join(self._commands.keys())
@@ -158,6 +154,3 @@ class _CommandManager(object):
e = "Error executing command '{0}'"
self.logger.exception(e.format(data.command))
break


command_manager = _CommandManager()

+ 4
- 4
earwigbot/irc/frontend.py 파일 보기

@@ -23,7 +23,6 @@
import logging
import re

from earwigbot.commands import command_manager
from earwigbot.irc import IRCConnection, Data, BrokenSocketException

__all__ = ["Frontend"]
@@ -40,14 +39,15 @@ class Frontend(IRCConnection):
"""
sender_regex = re.compile(":(.*?)!(.*?)@(.*?)\Z")

def __init__(self, config):
self.config = config
def __init__(self, bot):
self.bot = bot
self.config = bot.config
self.logger = logging.getLogger("earwigbot.frontend")

cf = config.irc["frontend"]
base = super(Frontend, self)
base.__init__(cf["host"], cf["port"], cf["nick"], cf["ident"],
cf["realname"], self.logger)
command_manager.load(self)
self._connect()

def _process_message(self, line):


+ 5
- 3
earwigbot/irc/watcher.py 파일 보기

@@ -38,14 +38,16 @@ class Watcher(IRCConnection):
to channels on the IRC frontend.
"""

def __init__(self, config, frontend=None):
self.config = config
def __init__(self, bot):
self.bot = bot
self.config = bot.config
self.frontend = bot.frontend
self.logger = logging.getLogger("earwigbot.watcher")

cf = config.irc["watcher"]
base = super(Watcher, self)
base.__init__(cf["host"], cf["port"], cf["nick"], cf["ident"],
cf["realname"], self.logger)
self.frontend = frontend
self._prepare_process_hook()
self._connect()



+ 14
- 4
earwigbot/util.py 파일 보기

@@ -36,12 +36,22 @@ class BotUtility(object):
return __version__

def run(self):
print "EarwigBot v{0}\n".format(self.version())

def main(self):
root_dir = path.abspath(path.curdir())
bot = Bot(root_dir)
bot.run()
try:
bot.run()
finally:
bot.stop()

def main(self):
print "EarwigBot v{0}\n".format(self.version())
parser = argparse.ArgumentParser(description=BotUtility.__doc__)

parser.add_argument("-V", "--version", action="version",
version=self.version())

args = parser.parse_args()
# args.func(args)


main = BotUtility().main


+ 4
- 2
setup.py 파일 보기

@@ -30,8 +30,10 @@ from setuptools import setup
setup(
name = "earwigbot",
entry_points = {"console_scripts": ["earwigbot = earwigbot.util:main"]},
install_requires = ["PyYAML>=3.10", "oursql>=0.9.3", "oauth2>=1.5.211",
"numpy>=1.6.1", "matplotlib>=1.1.0"],
install_requires = ["PyYAML>=3.10",
"oursql>=0.9.3",
"oauth2>=1.5.211",
"matplotlib>=1.1.0"],
version = "0.1.dev",
author = "Ben Kurtovic",
author_email = "ben.kurtovic@verizon.net",


불러오는 중...
취소
저장