Pārlūkot izejas kodu

Relocate BaseCommand to earwigbot.commands; _CommandManager class

tags/v0.1^2
Ben Kurtovic pirms 12 gadiem
vecāks
revīzija
1d02af98fa
22 mainītis faili ar 150 papildinājumiem un 175 dzēšanām
  1. +0
    -1
      earwigbot/classes/__init__.py
  2. +0
    -75
      earwigbot/classes/base_command.py
  3. +123
    -71
      earwigbot/commands/__init__.py
  4. +1
    -1
      earwigbot/commands/afc_report.py
  5. +1
    -1
      earwigbot/commands/afc_status.py
  6. +1
    -1
      earwigbot/commands/calc.py
  7. +1
    -1
      earwigbot/commands/chanops.py
  8. +1
    -1
      earwigbot/commands/crypt.py
  9. +3
    -3
      earwigbot/commands/ctcp.py
  10. +1
    -1
      earwigbot/commands/editcount.py
  11. +1
    -1
      earwigbot/commands/git.py
  12. +2
    -3
      earwigbot/commands/help.py
  13. +1
    -1
      earwigbot/commands/link.py
  14. +1
    -1
      earwigbot/commands/praise.py
  15. +1
    -1
      earwigbot/commands/registration.py
  16. +1
    -1
      earwigbot/commands/remind.py
  17. +1
    -1
      earwigbot/commands/replag.py
  18. +1
    -1
      earwigbot/commands/restart.py
  19. +1
    -1
      earwigbot/commands/rights.py
  20. +1
    -1
      earwigbot/commands/test.py
  21. +1
    -1
      earwigbot/commands/threads.py
  22. +6
    -6
      earwigbot/irc/frontend.py

+ 0
- 1
earwigbot/classes/__init__.py Parādīt failu

@@ -20,5 +20,4 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.


from earwigbot.classes.base_command import *
from earwigbot.classes.base_task import * from earwigbot.classes.base_task import *

+ 0
- 75
earwigbot/classes/base_command.py Parādīt failu

@@ -1,75 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2009-2012 by Ben Kurtovic <ben.kurtovic@verizon.net>
#
# 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.

import logging

__all__ = ["BaseCommand"]

class BaseCommand(object):
"""A base class for commands on IRC.

This docstring is reported to the user when they use !help <command>.
"""
# This is the command's name, as reported to the user when they use !help:
name = None

# Hooks are "msg", "msg_private", "msg_public", and "join". "msg" is the
# default behavior; if you wish to override that, change the value in your
# command subclass:
hooks = ["msg"]

def __init__(self, connection):
"""Constructor for new commands.

This is called once when the command is loaded (from
commands._load_command()). `connection` is a Connection object,
allowing us to do self.connection.say(), self.connection.send(), etc,
from within a method.
"""
self.connection = connection
logger_name = ".".join(("earwigbot", "commands", self.name))
self.logger = logging.getLogger(logger_name)
self.logger.setLevel(logging.DEBUG)

def check(self, data):
"""Returns whether this command should be called in response to 'data'.

Given a Data() instance, return True if we should respond to this
activity, or False if we should ignore it or it doesn't apply to us.

Most commands return True if data.command == self.name, otherwise they
return False. This is the default behavior of check(); you need only
override it if you wish to change that.
"""
if data.is_command and data.command == self.name:
return True
return False

def process(self, data):
"""Main entry point for doing a command.

Handle an activity (usually a message) on IRC. At this point, thanks
to self.check() which is called automatically by the command handler,
we know this is something we should respond to, so (usually) something
like 'if data.command != "command_name": return' is unnecessary.
"""
pass

+ 123
- 71
earwigbot/commands/__init__.py Parādīt failu

@@ -24,88 +24,140 @@
EarwigBot's IRC Command Manager EarwigBot's IRC Command Manager


This package provides the IRC "commands" used by the bot's front-end component. This package provides the IRC "commands" used by the bot's front-end component.
In __init__, you can find some functions used to load and run these commands.
This module contains the BaseCommand class (import with
`from earwigbot.commands import BaseCommand`) and an internal _CommandManager
class. This can be accessed through the singleton `command_manager`.
""" """


import logging import logging
import os import os
import sys import sys


from earwigbot.classes import BaseCommand
from earwigbot.config import config from earwigbot.config import config


__all__ = ["load", "get_all", "check"]
__all__ = ["BaseCommand", "command_manager"]


# Base directory when searching for commands:
base_dir = os.path.dirname(os.path.abspath(__file__))
class BaseCommand(object):
"""A base class for commands on IRC.


# Store commands in a dict, where the key is the command's name and the value
# is an instance of the command's class:
_commands = {}

# Logger for this module:
logger = logging.getLogger("earwigbot.tasks")

def _load_command(connection, filename):
"""Try to load a specific command from a module, identified by file name.

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 _commands, and report the
addition to the user. Any problems along the way will either be ignored or
reported.
"""
global _commands

# Strip .py from the end of the filename and join with our package name:
name = ".".join(("commands", filename[:-3]))
try:
__import__(name)
except:
logger.exception("Couldn't load file {0}".format(filename))
return

command = sys.modules[name].Command(connection)
if not isinstance(command, BaseCommand):
return

_commands[command.name] = command
logger.debug("Added command {0}".format(command.name))

def load(connection):
"""Load all valid commands into the _commands global variable.

`connection` is a Connection object that is given to each command's
constructor.
This docstring is reported to the user when they use !help <command>.
""" """
files = os.listdir(base_dir)
files.sort()
# This is the command's name, as reported to the user when they use !help:
name = None

# Hooks are "msg", "msg_private", "msg_public", and "join". "msg" is the
# default behavior; if you wish to override that, change the value in your
# command subclass:
hooks = ["msg"]

def __init__(self, connection):
"""Constructor for new commands.

This is called once when the command is loaded (from
commands._load_command()). `connection` is a Connection object,
allowing us to do self.connection.say(), self.connection.send(), etc,
from within a method.
"""
self.connection = connection
logger_name = ".".join(("earwigbot", "commands", self.name))
self.logger = logging.getLogger(logger_name)
self.logger.setLevel(logging.DEBUG)

def check(self, data):
"""Returns whether this command should be called in response to 'data'.

Given a Data() instance, return True if we should respond to this
activity, or False if we should ignore it or it doesn't apply to us.

Most commands return True if data.command == self.name, otherwise they
return False. This is the default behavior of check(); you need only
override it if you wish to change that.
"""
if data.is_command and data.command == self.name:
return True
return False

def process(self, data):
"""Main entry point for doing a command.

Handle an activity (usually a message) on IRC. At this point, thanks
to self.check() which is called automatically by the command handler,
we know this is something we should respond to, so (usually) something
like 'if data.command != "command_name": return' is unnecessary.
"""
pass


class _CommandManager(object):
def __init__(self):
self.logger = logging.getLogger("earwigbot.tasks")
self._base_dir = os.path.dirname(os.path.abspath(__file__))
self._connection = None
self._commands = {}

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

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.
"""
# Strip .py from the filename's end and join with our package name:
name = ".".join(("commands", filename[:-3]))
try:
__import__(name)
except:
self.logger.exception("Couldn't load file {0}".format(filename))
return


for filename in files:
if filename.startswith("_") or not filename.endswith(".py"):
continue
try: try:
_load_command(connection, filename)
command = sys.modules[name].Command(self._connection)
except AttributeError: except AttributeError:
pass # The file is doesn't contain a command, so just move on

msg = "Found {0} commands: {1}"
logger.info(msg.format(len(_commands), ", ".join(_commands.keys())))

def get_all():
"""Return our dict of all loaded commands."""
return _commands

def check(hook, data):
"""Given an event on IRC, check if there's anything we can respond to."""
# Parse command arguments into data.command and data.args:
data.parse_args()

for command in _commands.values():
if hook in command.hooks:
if command.check(data):
try:
command.process(data)
except:
logger.exception("Error executing command '{0}'".format(data.command))
break
return # No command in this module
if not isinstance(command, BaseCommand):
return

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)

msg = "Found {0} commands: {1}"
commands = ", ".join(self._commands.keys())
self.logger.info(msg.format(len(self._commands), commands))

def get_all(self):
"""Return our dict of all loaded commands."""
return self._commands

def check(self, hook, data):
"""Given an IRC event, check if there's anything we can respond to."""
# Parse command arguments into data.command and data.args:
data.parse_args()
for command in self._commands.values():
if hook in command.hooks:
if command.check(data):
try:
command.process(data)
except Exception:
e = "Error executing command '{0}'"
self.logger.exception(e.format(data.command))
break


command_manager = _CommandManager()

+ 1
- 1
earwigbot/commands/afc_report.py Parādīt failu

@@ -22,9 +22,9 @@


import re import re


from earwigbot.classes import BaseCommand
from earwigbot import tasks from earwigbot import tasks
from earwigbot import wiki from earwigbot import wiki
from earwigbot.commands import BaseCommand


class Command(BaseCommand): class Command(BaseCommand):
"""Get information about an AFC submission by name.""" """Get information about an AFC submission by name."""


+ 1
- 1
earwigbot/commands/afc_status.py Parādīt failu

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


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


class Command(BaseCommand): class Command(BaseCommand):


+ 1
- 1
earwigbot/commands/calc.py Parādīt failu

@@ -23,7 +23,7 @@
import re import re
import urllib import urllib


from earwigbot.classes import BaseCommand
from earwigbot.commands import BaseCommand


class Command(BaseCommand): class Command(BaseCommand):
"""A somewhat advanced calculator: see http://futureboy.us/fsp/frink.fsp """A somewhat advanced calculator: see http://futureboy.us/fsp/frink.fsp


+ 1
- 1
earwigbot/commands/chanops.py Parādīt failu

@@ -20,7 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.


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


class Command(BaseCommand): class Command(BaseCommand):


+ 1
- 1
earwigbot/commands/crypt.py Parādīt failu

@@ -22,8 +22,8 @@


import hashlib import hashlib


from earwigbot.classes import BaseCommand
from earwigbot import blowfish from earwigbot import blowfish
from earwigbot.commands import BaseCommand


class Command(BaseCommand): class Command(BaseCommand):
"""Provides hash functions with !hash (!hash list for supported algorithms) """Provides hash functions with !hash (!hash list for supported algorithms)


+ 3
- 3
earwigbot/commands/ctcp.py Parādīt failu

@@ -23,8 +23,8 @@
import platform import platform
import time import time


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


class Command(BaseCommand): class Command(BaseCommand):
@@ -64,6 +64,6 @@ 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 = config.irc.get("version", default)
vers = vers.replace("$1", earwigbot.__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
- 1
earwigbot/commands/editcount.py Parādīt failu

@@ -22,8 +22,8 @@


from urllib import quote_plus from urllib import quote_plus


from earwigbot.classes import BaseCommand
from earwigbot import wiki from earwigbot import wiki
from earwigbot.commands import BaseCommand


class Command(BaseCommand): class Command(BaseCommand):
"""Return a user's edit count.""" """Return a user's edit count."""


+ 1
- 1
earwigbot/commands/git.py Parādīt failu

@@ -24,7 +24,7 @@ import shlex
import subprocess import subprocess
import re import re


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


class Command(BaseCommand): class Command(BaseCommand):


+ 2
- 3
earwigbot/commands/help.py Parādīt failu

@@ -22,8 +22,7 @@


import re import re


from earwigbot import commands
from earwigbot.classes import BaseCommand
from earwigbot.commands import BaseCommand, command_manager
from earwigbot.irc import Data from earwigbot.irc import Data


class Command(BaseCommand): class Command(BaseCommand):
@@ -31,7 +30,7 @@ class Command(BaseCommand):
name = "help" name = "help"


def process(self, data): def process(self, data):
self.cmnds = commands.get_all()
self.cmnds = command_manager.get_all()
if not data.args: if not data.args:
self.do_main_help(data) self.do_main_help(data)
else: else:


+ 1
- 1
earwigbot/commands/link.py Parādīt failu

@@ -23,7 +23,7 @@
import re import re
from urllib import quote from urllib import quote


from earwigbot.classes import BaseCommand
from earwigbot.commands import BaseCommand


class Command(BaseCommand): class Command(BaseCommand):
"""Convert a Wikipedia page name into a URL.""" """Convert a Wikipedia page name into a URL."""


+ 1
- 1
earwigbot/commands/praise.py Parādīt failu

@@ -22,7 +22,7 @@


import random import random


from earwigbot.classes import BaseCommand
from earwigbot.commands import BaseCommand


class Command(BaseCommand): class Command(BaseCommand):
"""Praise people!""" """Praise people!"""


+ 1
- 1
earwigbot/commands/registration.py Parādīt failu

@@ -22,8 +22,8 @@


import time import time


from earwigbot.classes import BaseCommand
from earwigbot import wiki from earwigbot import wiki
from earwigbot.commands import BaseCommand


class Command(BaseCommand): class Command(BaseCommand):
"""Return when a user registered.""" """Return when a user registered."""


+ 1
- 1
earwigbot/commands/remind.py Parādīt failu

@@ -23,7 +23,7 @@
import threading import threading
import time import time


from earwigbot.classes import BaseCommand
from earwigbot.commands import BaseCommand


class Command(BaseCommand): class Command(BaseCommand):
"""Set a message to be repeated to you in a certain amount of time.""" """Set a message to be repeated to you in a certain amount of time."""


+ 1
- 1
earwigbot/commands/replag.py Parādīt failu

@@ -24,7 +24,7 @@ from os.path import expanduser


import oursql import oursql


from earwigbot.classes import BaseCommand
from earwigbot.commands import BaseCommand


class Command(BaseCommand): class Command(BaseCommand):
"""Return the replag for a specific database on the Toolserver.""" """Return the replag for a specific database on the Toolserver."""


+ 1
- 1
earwigbot/commands/restart.py Parādīt failu

@@ -20,7 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.


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


class Command(BaseCommand): class Command(BaseCommand):


+ 1
- 1
earwigbot/commands/rights.py Parādīt failu

@@ -20,8 +20,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.


from earwigbot.classes import BaseCommand
from earwigbot import wiki from earwigbot import wiki
from earwigbot.commands import BaseCommand


class Command(BaseCommand): class Command(BaseCommand):
"""Retrieve a list of rights for a given username.""" """Retrieve a list of rights for a given username."""


+ 1
- 1
earwigbot/commands/test.py Parādīt failu

@@ -22,7 +22,7 @@


import random import random


from earwigbot.classes import BaseCommand
from earwigbot.commands import BaseCommand


class Command(BaseCommand): class Command(BaseCommand):
"""Test the bot!""" """Test the bot!"""


+ 1
- 1
earwigbot/commands/threads.py Parādīt failu

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


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




+ 6
- 6
earwigbot/irc/frontend.py Parādīt failu

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


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


@@ -47,7 +47,7 @@ class Frontend(IRCConnection):
base = super(Frontend, self) base = super(Frontend, self)
base.__init__(cf["host"], cf["port"], cf["nick"], cf["ident"], base.__init__(cf["host"], cf["port"], cf["nick"], cf["ident"],
cf["realname"], self.logger) cf["realname"], self.logger)
commands.load(self)
command_manager.load(self)
self._connect() self._connect()


def _process_message(self, line): def _process_message(self, line):
@@ -59,7 +59,7 @@ class Frontend(IRCConnection):
data.nick, data.ident, data.host = self.sender_regex.findall(line[0])[0] data.nick, data.ident, data.host = self.sender_regex.findall(line[0])[0]
data.chan = line[2] data.chan = line[2]
# Check for 'join' hooks in our commands: # Check for 'join' hooks in our commands:
commands.check("join", data)
command_manager.check("join", data)


elif line[1] == "PRIVMSG": elif line[1] == "PRIVMSG":
data.nick, data.ident, data.host = self.sender_regex.findall(line[0])[0] data.nick, data.ident, data.host = self.sender_regex.findall(line[0])[0]
@@ -70,13 +70,13 @@ class Frontend(IRCConnection):
# This is a privmsg to us, so set 'chan' as the nick of the # This is a privmsg to us, so set 'chan' as the nick of the
# sender, then check for private-only command hooks: # sender, then check for private-only command hooks:
data.chan = data.nick data.chan = data.nick
commands.check("msg_private", data)
command_manager.check("msg_private", data)
else: else:
# Check for public-only command hooks: # Check for public-only command hooks:
commands.check("msg_public", data)
command_manager.check("msg_public", data)


# Check for command hooks that apply to all messages: # Check for command hooks that apply to all messages:
commands.check("msg", data)
command_manager.check("msg", data)


# If we are pinged, pong back: # If we are pinged, pong back:
elif line[0] == "PING": elif line[0] == "PING":


Notiek ielāde…
Atcelt
Saglabāt