refactored config

This commit is contained in:
iou1name 2019-10-08 12:39:13 -04:00
parent d06b8f2fdc
commit b552c35baa
20 changed files with 107 additions and 253 deletions

1
.gitignore vendored
View File

@ -10,3 +10,4 @@ logs/
*.txt *.txt
*.db-journal *.db-journal
tourettes.py tourettes.py
config.py

View File

@ -1,56 +1,10 @@
# Fulvia # Fulvia
## NIGGER DICKS 2: Electric Boogaloo
It's like Sopel, except rewritten from scratch using Twisted as a base and over half the features ripped out. It's like Sopel, except rewritten from scratch using Twisted as a base and over half the features ripped out.
## Requirements ## Requirements
Python 3.6+ Python 3.6+
Python packages: `twisted python-dateutil requests bs4 wolframalpha pyenchant emoji Pillow xml2dict ipython numpy numpngw` Python packages: `twisted python-dateutil requests bs4 wolframalpha pyenchant emoji Pillow xml2dict ipython numpy numpngw`
## Config
`nickname` - The nickname the bot will use.
`realname` - The realname the bot will use.
`username` - The user ident the bot will use.
`prefix` - The command prefix the bot will listen for.
`homedir` - The bot's home directory. Required for the bot to get certain pathing right. In the future that will be obtained automatically.
`server` - The server address to connect to.
`port` - The server port to connect to. SSL will probably not work.
`use_ssl` - Place holder.
`channels` - Which channels to join upon connection.
`db_filename` - Filename to use for the bot's database.
`owner` - The bot's owner. Use for permission purposes on restricted commands. Outranks admins. Should be the full hostmask of the user.
`admins` - Comma-delineated list of admins the bot will recognize for restricted commands. Should be the full hostmask for each one.
`default_time_format` - The format used for all timestamp operations. See the official python docs for the `time` library for more information.
`disabled_modules` - Comma-delineated list of modules *not* to load on startup. Modules should be specified without the `.py` extension.
### Example default.cfg
```
[core]
nickname = DiceBot9002
realname = DiceBot9002
username = DiceBot9002
prefix = .
homedir = /home/iou1name/fulvia
server = irc.steelbea.me
port = 6667
use_ssl = false
channels = #SomaIsGay,#test
db_filename = DiceBot9002.db
owner = iou1name!~iou1name@operational.operator
admins =
default_time_format = [%Y-%m-%d %H:%M:%S]
disabled_modules = countdown
[wolfram]
app_id = API_KEY
units = nonmetric
[movie]
tmdb_api_key = API_KEY
[currency]
api_key = API_KEY
```
## TODO ## TODO
Fix the movie table Fix the movie table
Consider re-adding the following modules: `etymology, ip` Consider re-adding the following modules: `etymology, ip`

50
bot.py
View File

@ -5,7 +5,6 @@ The core bot class for Fulvia.
import os import os
import sys import sys
import time import time
import functools
import threading import threading
import traceback import traceback
from datetime import datetime from datetime import datetime
@ -15,35 +14,30 @@ from twisted.words.protocols import irc
import db import db
import tools import tools
import config
import loader import loader
from trigger import Trigger from trigger import Trigger
class Fulvia(irc.IRCClient): class Fulvia(irc.IRCClient):
def __init__(self, config): def __init__(self):
self.config = config self.nickname = config.nickname
"""The bot's config, loaded from file.""" self.nick = config.nickname
self.nickname = config.core.nickname
self.nick = config.core.nickname
"""The bot's current nickname.""" """The bot's current nickname."""
self.realname = config.core.realname self.realname = config.realname
"""The bot's 'real name', used in whois.""" """The bot's 'real name', used in whois."""
self.username = config.core.username self.username = config.username
"""The bot's username ident used for logging into the server.""" """The bot's username ident used for logging into the server."""
self.host = "" self.host = ""
"""The bot's host, virtual or otherwise. To be filled in later.""" """The bot's host, virtual or otherwise. To be filled in later."""
self.prefix = config.core.prefix self.static = "static"
"""The command prefix the bot watches for."""
self.static = os.path.join(config.homedir, "static")
os.makedirs(self.static, exist_ok=True) os.makedirs(self.static, exist_ok=True)
"""The path to the bot's static file directory.""" """The path to the bot's static file directory."""
self.log_path = os.path.join(config.homedir, "logs") self.log_path = "logs"
os.makedirs(self.static, exist_ok=True) os.makedirs(self.static, exist_ok=True)
"""The path to the bot's log files.""" """The path to the bot's log files."""
@ -68,7 +62,7 @@ class Fulvia(irc.IRCClient):
modules need it. modules need it.
""" """
self.db = db.FulviaDB(self.config) self.db = db.FulviaDB()
""" """
A class with some basic interactions for the bot's sqlite3 databse. A class with some basic interactions for the bot's sqlite3 databse.
""" """
@ -100,7 +94,7 @@ class Fulvia(irc.IRCClient):
self._user_joined = [] self._user_joined = []
"""These get called when a user joins a channel.""" """These get called when a user joins a channel."""
self._disabled_modules = self.config.core.disabled_modules.split(",") self._disabled_modules = config.disabled_modules
"""These modules will NOT be loaded when load_modules() is called.""" """These modules will NOT be loaded when load_modules() is called."""
self.load_modules() self.load_modules()
@ -117,7 +111,7 @@ class Fulvia(irc.IRCClient):
self.url_callbacks = {} self.url_callbacks = {}
# ensure they're empty # ensure they're empty
modules = loader.find_modules(self.config.homedir) modules = loader.find_modules()
loaded = 0 loaded = 0
failed = 0 failed = 0
for name, path in modules.items(): for name, path in modules.items():
@ -215,7 +209,7 @@ class Fulvia(irc.IRCClient):
""" """
# TODO: use time module instead of datetime # TODO: use time module instead of datetime
t = datetime.fromtimestamp(time.time()) t = datetime.fromtimestamp(time.time())
timestamp = t.strftime(self.config.core.default_time_format) timestamp = t.strftime(config.default_time_format)
self._log_dump[channel].append(timestamp + " " + text) self._log_dump[channel].append(timestamp + " " + text)
if time.time() - self._last_log_dump > 1: if time.time() - self._last_log_dump > 1:
@ -248,9 +242,9 @@ class Fulvia(irc.IRCClient):
self.log(channel, line) self.log(channel, line)
funcs = [] funcs = []
if message.startswith(self.prefix) and message != self.prefix: if message.startswith(config.prefix) and message != config.prefix:
command = message.partition(" ")[0] command = message.partition(" ")[0]
command = command.replace(self.prefix, "", 1) command = command.replace(config.prefix, "", 1)
cmd = self.commands.get(command) cmd = self.commands.get(command)
if not cmd: if not cmd:
return return
@ -259,7 +253,7 @@ class Fulvia(irc.IRCClient):
funcs += self._hooks funcs += self._hooks
for func in funcs: for func in funcs:
trigger = Trigger(user, channel, message, "PRIVMSG", self.config) trigger = Trigger(user, channel, message, "PRIVMSG")
bot = FulviaWrapper(self, trigger) bot = FulviaWrapper(self, trigger)
if func.rate: if func.rate:
@ -352,8 +346,8 @@ class Fulvia(irc.IRCClient):
def signedOn(self): def signedOn(self):
"""Called when the bot successfully connects to the server.""" """Called when the bot successfully connects to the server."""
if self.config.core.oper_password: if config.oper_password:
self.sendLine("OPER " + self.config.core.nickname + ' ' + self.config.core.oper_password) self.sendLine("OPER " + config.nickname + ' ' + config.oper_password)
print(f"Signed on as {self.nickname}") print(f"Signed on as {self.nickname}")
self.whois(self.nickname) self.whois(self.nickname)
@ -361,7 +355,7 @@ class Fulvia(irc.IRCClient):
line += f"{self.nickname}!{self.username}@{self.host}" line += f"{self.nickname}!{self.username}@{self.host}"
self.log(self.hostname, line) self.log(self.hostname, line)
for channel in self.config.core.channels.split(","): for channel in config.channels:
self.join(channel) self.join(channel)
@ -400,7 +394,7 @@ class Fulvia(irc.IRCClient):
self.channels[channel].users[nick] = user self.channels[channel].users[nick] = user
for func in self._user_joined: for func in self._user_joined:
trigger = Trigger(user, channel, f"{user} has joined", "PRIVMSG", self.config) trigger = Trigger(user, channel, f"{user} has joined", "PRIVMSG")
bot = FulviaWrapper(self, trigger) bot = FulviaWrapper(self, trigger)
t = threading.Thread(target=self.call,args=(func, bot, trigger)) t = threading.Thread(target=self.call,args=(func, bot, trigger))
t.start() t.start()
@ -667,8 +661,4 @@ class FulviaWrapper():
class FulviaFactory(protocol.ReconnectingClientFactory): class FulviaFactory(protocol.ReconnectingClientFactory):
# black magic going on here protocol = Fulvia
protocol = property(lambda s: functools.partial(Fulvia, s.config))
def __init__(self, config):
self.config = config

116
config.py
View File

@ -1,116 +0,0 @@
#!/usr/bin/env python3
"""
For parsing and generating config files.
"""
from configparser import ConfigParser
class Config():
def __init__(self, filename):
"""
The bot's configuration.
The given filename will be associated with the configuration, and is
the file which will be written if write() is called. If load is not
given or True, the configuration object will load the attributes from
the file at filename.
A few default values will be set here if they are not defined in the
config file, or a config file is not loaded. They are documented below.
"""
self.filename = filename
"""The config object's associated file, as noted above."""
self.parser = ConfigParser(allow_no_value=True, interpolation=None)
self.parser.read(self.filename)
@property
def homedir(self):
"""An alias to config.core.homedir"""
# Technically it's the other way around, so we can bootstrap filename
# attributes in the core section, but whatever.
configured = None
if self.parser.has_option('core', 'homedir'):
configured = self.parser.get('core', 'homedir')
if configured:
return configured
else:
return os.path.dirname(self.filename)
def save(self):
"""Save all changes to the config file."""
with open(self.filename, 'w') as cfgfile:
self.parser.write(cfgfile)
def add_section(self, name):
"""
Add a section to the config file.
Returns ``False`` if already exists.
"""
try:
return self.parser.add_section(name)
except ConfigParser.DuplicateSectionError:
return False
def __getattr__(self, name):
"""Allows sections to be called like class attributes."""
if name in self.parser.sections():
items = self.parser.items(name)
section = ConfigSection(name, items, self) # Return a section
setattr(self, name, section)
return section
else:
raise AttributeError("%r object has no attribute %r"
% (type(self).__name__, name))
class ConfigSection(object):
"""
Represents a section of the config file.
Contains all keys in thesection as attributes.
"""
def __init__(self, name, items, parent):
object.__setattr__(self, '_name', name)
object.__setattr__(self, '_parent', parent)
for item in items:
value = item[1].strip()
if not value.lower() == 'none':
if value.lower() == 'false':
value = False
object.__setattr__(self, item[0], value)
def __getattr__(self, name):
return None
def __setattr__(self, name, value):
object.__setattr__(self, name, value)
if type(value) is list:
value = ','.join(value)
self._parent.parser.set(self._name, name, value)
def get_list(self, name):
value = getattr(self, name)
if not value:
return []
if isinstance(value, str):
value = value.split(',')
# Keep the split value, so we don't have to keep doing this
setattr(self, name, value)
return value
def readConfig(filename):
"""
Parses the provided filename and returns the config object.
"""
config = ConfigParser(allow_no_value=True, interpolation=None)
config.read(filename)
return config
def generateConfig(filename):
"""
Generates a blank config file with minimal defaults.
"""
pass

33
config.template.py Executable file
View File

@ -0,0 +1,33 @@
#!/usr/bin/env python3
"""
The bot's config file.
"""
""" Core """
nickname = 'DiceBot9002'
realname = 'DiceBot9002'
username = 'DiceBot9002'
prefix = '.'
server = 'irc.steelbea.me'
port = 6667
use_ssl = False
channels = ['#test', '#SomaIsGay']
db_filename = 'DiceBot9002.db'
owner = 'iou1name!~iou1name@operational.operator'
admins = []
default_time_format = '[%Y-%m-%d %H:%M:%S]'
disabled_modules = ['countdown']
oper_password = 'password'
""" Wolfram """
wolfram_app_id = 'password'
wolfram_units = 'nonmetric'
""" Movie """
tmdb_api_key = 'password'
""" Currency """
exchangerate_api_key = 'password'
""" Crypto """
coinlib_api_key = 'password'

8
db.py
View File

@ -6,13 +6,15 @@ import os
import sqlite3 import sqlite3
import threading import threading
class FulviaDB(object): import config
class FulviaDB:
""" """
Defines a basic interface and some convenience functionsfor the bot's Defines a basic interface and some convenience functionsfor the bot's
database. database.
""" """
def __init__(self, config): def __init__(self):
path = config.core.db_filename path = config.db_filename
self.filename = path self.filename = path
self.db_lock = threading.Lock() self.db_lock = threading.Lock()

View File

@ -14,7 +14,7 @@ def load_module(bot, path):
module = importlib.import_module(path) module = importlib.import_module(path)
if hasattr(module, 'setup'): if hasattr(module, 'setup'):
module.setup(bot) module.setup(bot)
relevant_parts = process_module(module, bot.config) relevant_parts = process_module(module)
for part in relevant_parts: for part in relevant_parts:
bot.register_callable(part) bot.register_callable(part)
@ -34,14 +34,13 @@ def unload_module(bot, name):
del sys.modules[name] del sys.modules[name]
def find_modules(homedir): def find_modules():
""" """
Searches through homedir/modules for python files and returns a dictionary Searches through 'modules/' for python files and returns a dictionary
with the module name as the key and the path as the value. with the module name as the key and the path as the value.
""" """
modules_dir = os.path.join(homedir, "modules")
modules = {} modules = {}
for file in os.listdir(modules_dir): for file in os.listdir('modules'):
if not file.endswith(".py"): if not file.endswith(".py"):
continue continue
name = file.replace(".py", "") name = file.replace(".py", "")
@ -49,7 +48,7 @@ def find_modules(homedir):
return modules return modules
def process_module(module, config): def process_module(module):
""" """
Takes a module object and extracts relevant data objects out of it. Takes a module object and extracts relevant data objects out of it.
Returns all callables(read: functions) and shutdowns(?). Returns all callables(read: functions) and shutdowns(?).
@ -58,7 +57,7 @@ def process_module(module, config):
for key, obj in dict.items(vars(module)): for key, obj in dict.items(vars(module)):
if callable(obj): if callable(obj):
if is_triggerable(obj): if is_triggerable(obj):
process_callable(obj, config) process_callable(obj)
callables.append(obj) callables.append(obj)
return callables return callables
@ -72,12 +71,10 @@ def is_triggerable(obj):
return any(hasattr(obj, attr) for attr in triggerable_attributes) return any(hasattr(obj, attr) for attr in triggerable_attributes)
def process_callable(func, config): def process_callable(func):
""" """
Sets various helper atributes about a given function. Sets various helper atributes about a given function.
""" """
prefix = config.core.prefix
func.thread = getattr(func, "thread", True) func.thread = getattr(func, "thread", True)
func.hook = getattr(func, "hook", False) func.hook = getattr(func, "hook", False)
func.rate = getattr(func, "rate", 0) func.rate = getattr(func, "rate", 0)

View File

@ -15,6 +15,6 @@ def BQstatus(bot, trigger):
status = "\x0304DEAD" status = "\x0304DEAD"
deathdate = "[2017-02-16 00:19:00]" deathdate = "[2017-02-16 00:19:00]"
msg = "Banished Quest status: " + status + "\nTime since death: " msg = "Banished Quest status: " + status + "\nTime since death: "
msg += relativeTime(bot.config, datetime.now(), deathdate) + " ago " msg += relativeTime(datetime.now(), deathdate) + " ago "
msg += deathdate msg += deathdate
bot.msg(msg) bot.msg(msg)

View File

@ -27,6 +27,6 @@ def generic_countdown(bot, trigger):
except: except:
return bot.msg("Please use correct format: .countdown 2012 12 21") return bot.msg("Please use correct format: .countdown 2012 12 21")
msg = relativeTime(bot.config, datetime.now(), date) msg = relativeTime(datetime.now(), date)
msg += " until " + trigger.group(2) msg += " until " + trigger.group(2)
bot.msg(msg) bot.msg(msg)

View File

@ -6,6 +6,7 @@ import re
import requests import requests
import config
from module import commands, example, require_admin from module import commands, example, require_admin
URI = "https://coinlib.io/api/v1" URI = "https://coinlib.io/api/v1"
@ -19,7 +20,7 @@ def crypto(bot, trigger):
Queries coinlib.io for information about various crytocurrencies. Queries coinlib.io for information about various crytocurrencies.
""" """
params = { params = {
"key": bot.config.crypto.api_key, "key": config.coinlib_api_key,
"pref": "USD", "pref": "USD",
} }
symbol = trigger.group(3) symbol = trigger.group(3)

View File

@ -33,7 +33,7 @@ def exchange(bot, trigger):
cur_to = cur_to.upper() cur_to = cur_to.upper()
cur_from = cur_from.upper() cur_from = cur_from.upper()
api_key = bot.config.currency.api_key api_key = config.exchangerate_api_key
url = CUR_URI.format(**{"API_KEY": api_key, "CUR_FROM": cur_from}) url = CUR_URI.format(**{"API_KEY": api_key, "CUR_FROM": cur_from})
res = requests.get(url, verify=True) res = requests.get(url, verify=True)
res.raise_for_status() res.raise_for_status()

View File

@ -11,6 +11,7 @@ from sqlite3 import IntegrityError, OperationalError
import bs4 import bs4
import requests import requests
import config
from module import commands, example, require_admin from module import commands, example, require_admin
def setup(bot): def setup(bot):
@ -50,7 +51,7 @@ def movieInfo(bot, trigger):
return bot.reply("What movie?") return bot.reply("What movie?")
word = word.replace(" ", "+") word = word.replace(" ", "+")
api_key = bot.config.movie.tmdb_api_key api_key = config.tmdb_api_key
uri = "https://api.themoviedb.org/3/search/movie?" + \ uri = "https://api.themoviedb.org/3/search/movie?" + \
f"api_key={api_key}&query={word}" f"api_key={api_key}&query={word}"
data = requests.get(uri, timeout=30, verify=True).json() data = requests.get(uri, timeout=30, verify=True).json()
@ -151,7 +152,7 @@ def pickMovie(bot, trigger):
bot.reply(movie[0]) bot.reply(movie[0])
if trigger.group(2) == "-m": if trigger.group(2) == "-m":
trigger.set_group(f".movie {movie}", bot.config) trigger.set_group(f".movie {movie}")
movieInfo(bot, trigger) movieInfo(bot, trigger)

View File

@ -10,6 +10,7 @@ import datetime
import threading import threading
import collections import collections
import config
from module import commands, example from module import commands, example
class MonitorThread(threading.Thread): class MonitorThread(threading.Thread):
@ -213,7 +214,7 @@ def create_reminder(bot, trigger, duration, message):
if duration >= 60: if duration >= 60:
remind_at = datetime.datetime.fromtimestamp(t) remind_at = datetime.datetime.fromtimestamp(t)
t_format = bot.config.core.default_time_format t_format = config.default_time_format
timef = datetime.datetime.strftime(remind_at, t_format) timef = datetime.datetime.strftime(remind_at, t_format)
bot.reply('Okay, will remind at %s' % timef) bot.reply('Okay, will remind at %s' % timef)

View File

@ -73,7 +73,7 @@ def findandreplace(bot, trigger):
if not group: if not group:
return return
g = (trigger.group(0),) + group.groups() g = (trigger.group(0),) + group.groups()
trigger.set_group(g, bot.config) trigger.set_group(g)
# Correcting other person vs self. # Correcting other person vs self.
rnick = (trigger.group(1) or trigger.nick) rnick = (trigger.group(1) or trigger.nick)

View File

@ -11,6 +11,7 @@ from sqlite3 import OperationalError
from requests.structures import CaseInsensitiveDict from requests.structures import CaseInsensitiveDict
import config
from tools.time import relativeTime from tools.time import relativeTime
from module import commands, example, hook, require_chanmsg, rate from module import commands, example, hook, require_chanmsg, rate
@ -87,9 +88,9 @@ def seen(bot, trigger):
return bot.msg(f"I haven't seen \x0308{args.nick}") return bot.msg(f"I haven't seen \x0308{args.nick}")
timestamp = datetime.fromtimestamp(timestamp) timestamp = datetime.fromtimestamp(timestamp)
t_format = bot.config.core.default_time_format t_format = config.default_time_format
timestamp = datetime.strftime(timestamp, t_format) timestamp = datetime.strftime(timestamp, t_format)
reltime = relativeTime(bot.config, datetime.now(), timestamp) reltime = relativeTime(datetime.now(), timestamp)
if args.first: if args.first:
msg = "First" msg = "First"

View File

@ -9,6 +9,7 @@ import threading
from datetime import datetime from datetime import datetime
from sqlite3 import OperationalError from sqlite3 import OperationalError
import config
from tools.time import relativeTime from tools.time import relativeTime
from module import commands, example, hook from module import commands, example, hook
@ -107,8 +108,8 @@ def tell_hook(bot, trigger):
teller, unixtime, message = tell teller, unixtime, message = tell
telldate = datetime.fromtimestamp(unixtime) telldate = datetime.fromtimestamp(unixtime)
reltime = relativeTime(bot.config, datetime.now(), telldate) reltime = relativeTime(datetime.now(), telldate)
t_format = bot.config.core.default_time_format t_format = config.default_time_format
telldate = datetime.strftime(telldate, t_format) telldate = datetime.strftime(telldate, t_format)
msg = f"{tellee}: \x0310{message}\x03 (\x0308{teller}\x03) {telldate}" \ msg = f"{tellee}: \x0310{message}\x03 (\x0308{teller}\x03) {telldate}" \

View File

@ -4,9 +4,9 @@ Querying Wolfram Alpha.
""" """
import wolframalpha import wolframalpha
import config
from module import commands, example from module import commands, example
@commands('wa', 'wolfram') @commands('wa', 'wolfram')
@example('.wa 2+2', '[W|A] 2+2 = 4') @example('.wa 2+2', '[W|A] 2+2 = 4')
@example(".wa python language release date", @example(".wa python language release date",
@ -17,11 +17,11 @@ def wa_command(bot, trigger):
""" """
if not trigger.group(2): if not trigger.group(2):
return bot.reply("You must provide a query.") return bot.reply("You must provide a query.")
if not bot.config.wolfram.app_id: if not config.wolfram_app_id:
bot.reply("Wolfram|Alpha API app ID not configured.") bot.reply("Wolfram|Alpha API app ID not configured.")
query = trigger.group(2).strip() query = trigger.group(2).strip()
app_id = bot.config.wolfram.app_id app_id = config.wolfram_app_id
units = bot.config.wolfram.units units = config.wolfram_units
res = wa_query(query, app_id, units) res = wa_query(query, app_id, units)

23
run.py
View File

@ -6,26 +6,11 @@ import os
from twisted.internet import reactor from twisted.internet import reactor
import config
from bot import FulviaFactory from bot import FulviaFactory
from config import Config
if __name__ == "__main__": if __name__ == "__main__":
import argparse server = config.server
port = config.port
parser = argparse.ArgumentParser( reactor.connectTCP(server, port, FulviaFactory())
description="Fulvia IRC Bot")
parser.add_argument(
"-c",
"--config",
help="Use a specific config file.")
args = parser.parse_args()
if not args.config:
args.config = "default.cfg"
config = Config(args.config)
server = config.core.server
port = int(config.core.port)
reactor.connectTCP(server, port, FulviaFactory(config))
reactor.run() reactor.run()

View File

@ -6,15 +6,17 @@ from datetime import datetime
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
import config
def relativeTime(config, time_1, time_2):
def relativeTime(time_1, time_2):
""" """
Returns the relative time difference between 'time_1' and 'time_2'. Returns the relative time difference between 'time_1' and 'time_2'.
If either 'time_1' or 'time_2' is a string, it will be converted to a If either 'time_1' or 'time_2' is a string, it will be converted to a
datetime object according to the 'default_time_format' variable in the datetime object according to the 'default_time_format' variable in the
config. config.
""" """
t_format = config.core.default_time_format t_format = config.default_time_format
if type(time_1) == str: if type(time_1) == str:
time_1 = datetime.strptime(time_1, t_format) time_1 = datetime.strptime(time_1, t_format)
if type(time_2) == str: if type(time_2) == str:

View File

@ -4,6 +4,8 @@ The trigger abstraction layer.
""" """
import datetime import datetime
import config
def split_user(user): def split_user(user):
""" """
Splits a user hostmask into <nick>!<ident>@<host> Splits a user hostmask into <nick>!<ident>@<host>
@ -21,14 +23,14 @@ class Group(list):
Custom list class that permits calling it like a function so as to Custom list class that permits calling it like a function so as to
emulate a re.group instance. emulate a re.group instance.
""" """
def __init__(self, message, config): def __init__(self, message):
""" """
Initializes the group class. If 'message' is a string, we split Initializes the group class. If 'message' is a string, we split
it into groups according to the usual trigger.group structure. it into groups according to the usual trigger.group structure.
Otherwise we assume it's already been split appropriately. Otherwise we assume it's already been split appropriately.
""" """
if type(message) == str: if type(message) == str:
message = self.split_group(message, config) message = self.split_group(message)
list.__init__(self, message) list.__init__(self, message)
@ -45,7 +47,7 @@ class Group(list):
return item return item
def split_group(self, message, config): def split_group(self, message):
""" """
Splits the message by spaces. Splits the message by spaces.
group(0) is always the entire message. group(0) is always the entire message.
@ -54,11 +56,10 @@ class Group(list):
group(2) is always the entire message after the first word. group(2) is always the entire message after the first word.
group(3+) is always every individual word after the first word. group(3+) is always every individual word after the first word.
""" """
prefix = config.core.prefix
group = [] group = []
group.append(message) group.append(message)
words = message.split() words = message.split()
group.append(words[0].replace(prefix, "", 1)) group.append(words[0].replace(config.prefix, "", 1))
group.append(" ".join(words[1:])) group.append(" ".join(words[1:]))
group += words[1:] group += words[1:]
@ -66,7 +67,7 @@ class Group(list):
class Trigger(): class Trigger():
def __init__(self, user, channel, message, event, config): def __init__(self, user, channel, message, event):
self.channel = channel self.channel = channel
""" """
The channel from which the message was sent. The channel from which the message was sent.
@ -112,7 +113,7 @@ class Trigger():
message. message.
""" """
self.group = Group(message, config) self.group = Group(message)
"""The ``group`` function of the ``match`` attribute. """The ``group`` function of the ``match`` attribute.
See Python :mod:`re` documentation for details.""" See Python :mod:`re` documentation for details."""
@ -125,14 +126,14 @@ class Trigger():
``('#example', '-m')`` ``('#example', '-m')``
""" """
admins = config.core.admins.split(",") + [config.core.owner] admins = config.admins + [config.owner]
self.admin = any([self.compare_hostmask(admin) for admin in admins]) self.admin = any([self.compare_hostmask(admin) for admin in admins])
""" """
True if the nick which triggered the command is one of the bot's True if the nick which triggered the command is one of the bot's
admins. admins.
""" """
self.owner = self.compare_hostmask(config.core.owner) self.owner = self.compare_hostmask(config.owner)
"""True if the nick which triggered the command is the bot's owner.""" """True if the nick which triggered the command is the bot's owner."""
@ -147,9 +148,9 @@ class Trigger():
return compare_against == "@".join(self.nick, self.host) return compare_against == "@".join(self.nick, self.host)
def set_group(self, line, config): def set_group(self, line):
""" """
Allows a you to easily change the current group to a new Group Allows a you to easily change the current group to a new Group
instance. instance.
""" """
self.group = Group(line, config) self.group = Group(line)