Pass along ConfigParsers instead of file names

This commit is contained in:
Joscha 2019-04-14 16:07:37 +00:00
parent 2f7502723b
commit 86472afb3f
4 changed files with 109 additions and 27 deletions

View file

@ -2,6 +2,9 @@
## Next version ## Next version
- change how config files are passed along
- change module system to support config file changes
# 1.0.0 (2019-04-13) # 1.0.0 (2019-04-13)
- add fancy argument parsing - add fancy argument parsing

View file

@ -1,6 +1,7 @@
import asyncio import asyncio
import configparser
import logging import logging
from typing import Callable from typing import Callable, Dict
from .bot import * from .bot import *
from .client import * from .client import *
@ -48,12 +49,33 @@ def enable_logging(name: str = "yaboli", level: int = logging.INFO) -> None:
logger.addHandler(handler) logger.addHandler(handler)
def run( def run(
client: Callable[[str], Client], bot_constructor: BotConstructor,
config_file: str = "bot.conf" config_file: str = "bot.conf",
) -> None: ) -> None:
# Load the config file
config = configparser.ConfigParser(allow_no_value=True)
config.read(config_file)
async def _run() -> None: async def _run() -> None:
while True: while True:
client_ = client(config_file) bot = bot_constructor(config, config_file)
await client_.run() await bot.run()
asyncio.run(_run())
def run_modulebot(
modulebot_constructor: ModuleBotConstructor,
module_constructors: Dict[str, ModuleConstructor],
config_file: str = "bot.conf",
) -> None:
# Load the config file
config = configparser.ConfigParser(allow_no_value=True)
config.read(config_file)
async def _run() -> None:
while True:
modulebot = modulebot_constructor(config, config_file,
module_constructors)
await modulebot.run()
asyncio.run(_run()) asyncio.run(_run())

View file

@ -1,7 +1,7 @@
import configparser import configparser
import datetime import datetime
import logging import logging
from typing import List, Optional from typing import Callable, List, Optional
from .client import Client from .client import Client
from .command import * from .command import *
@ -11,7 +11,7 @@ from .util import *
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
__all__ = ["Bot"] __all__ = ["Bot", "BotConstructor"]
class Bot(Client): class Bot(Client):
ALIASES: List[str] = [] ALIASES: List[str] = []
@ -25,12 +25,13 @@ class Bot(Client):
GENERAL_SECTION = "general" GENERAL_SECTION = "general"
ROOMS_SECTION = "rooms" ROOMS_SECTION = "rooms"
def __init__(self, config_file: str) -> None: def __init__(self,
config: configparser.ConfigParser,
config_file: str,
) -> None:
self.config = config
self.config_file = config_file self.config_file = config_file
self.config = configparser.ConfigParser(allow_no_value=True)
self.config.read(self.config_file)
nick = self.config[self.GENERAL_SECTION].get("nick") nick = self.config[self.GENERAL_SECTION].get("nick")
if nick is None: if nick is None:
logger.warn(("'nick' not set in config file. Defaulting to empty" logger.warn(("'nick' not set in config file. Defaulting to empty"
@ -188,3 +189,5 @@ class Bot(Client):
logger.info(f"Restarted in &{room.name} by {message.sender.atmention}") logger.info(f"Restarted in &{room.name} by {message.sender.atmention}")
await message.reply(self.RESTART_REPLY) await message.reply(self.RESTART_REPLY)
await self.stop() await self.stop()
BotConstructor = Callable[[configparser.ConfigParser, str], Bot]

View file

@ -1,5 +1,6 @@
import configparser
import logging import logging
from typing import Dict, List, Optional from typing import Callable, Dict, List, Optional
from .bot import Bot from .bot import Bot
from .command import * from .command import *
@ -10,49 +11,77 @@ from .util import *
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
__all__ = ["Module", "ModuleBot"] __all__ = ["Module", "ModuleConstructor", "ModuleBot", "ModuleBotConstructor"]
class Module(Bot): class Module(Bot):
DESCRIPTION: Optional[str] = None DESCRIPTION: Optional[str] = None
def __init__(self, config_file: str, standalone: bool) -> None: def __init__(self,
super().__init__(config_file) config: configparser.ConfigParser,
config_file: str,
standalone: bool = True,
) -> None:
super().__init__(config, config_file)
self.standalone = standalone self.standalone = standalone
ModuleConstructor = Callable[[configparser.ConfigParser, str, bool], Module]
class ModuleBot(Bot): class ModuleBot(Bot):
HELP_PRE: Optional[List[str]] = [ HELP_PRE: Optional[List[str]] = [
"This bot contains the following modules:" "This bot contains the following modules:"
] ]
HELP_POST: Optional[List[str]] = [ HELP_POST: Optional[List[str]] = [
"" "",
"Use \"!help {atmention} <module>\" to get more information on a" "For module-specific help, try \"!help {atmention} <module>\".",
" specific module."
] ]
MODULE_HELP_LIMIT = 5 MODULE_HELP_LIMIT = 5
def __init__(self, config_file: str) -> None: MODULES_SECTION = "modules"
super().__init__(config_file)
def __init__(self,
config: configparser.ConfigParser,
config_file: str,
module_constructors: Dict[str, ModuleConstructor],
) -> None:
super().__init__(config, config_file)
self.module_constructors = module_constructors
self.modules: Dict[str, Module] = {} self.modules: Dict[str, Module] = {}
self.register_botrulez(help_=False) # Load initial modules
self.register_general("help", self.cmd_help_general, args=False) for module_name in self.config[self.MODULES_SECTION]:
self.register_specific("help", self.cmd_help_specific, args=True) module_constructor = self.module_constructors.get(module_name)
if module_constructor is None:
logger.warn(f"Module {module_name} not found")
continue
# standalone is set to False
module = module_constructor(self.config, self.config_file, False)
self.load_module(module_name, module)
def register_module(self, name: str, module: Module) -> None: def load_module(self, name: str, module: Module) -> None:
if name in self.modules: if name in self.modules:
logger.warn(f"Module {name!r} is already registered, overwriting...") logger.warn(f"Module {name!r} is already registered, overwriting...")
self.modules[name] = module self.modules[name] = module
def unload_module(self, name: str) -> None:
if name in self.modules:
del self.modules[name]
# Better help messages
def compile_module_overview(self) -> List[str]: def compile_module_overview(self) -> List[str]:
lines = [] lines = []
if self.HELP_PRE is not None: if self.HELP_PRE is not None:
lines.extend(self.HELP_PRE) lines.extend(self.HELP_PRE)
any_modules = False
modules_without_desc: List[str] = [] modules_without_desc: List[str] = []
for module_name in sorted(self.modules): for module_name in sorted(self.modules):
any_modules = True
module = self.modules[module_name] module = self.modules[module_name]
if module.DESCRIPTION is None: if module.DESCRIPTION is None:
@ -62,7 +91,10 @@ class ModuleBot(Bot):
lines.append(line) lines.append(line)
if modules_without_desc: if modules_without_desc:
lines.append(", ".join(modules_without_desc)) lines.append("\t" + ", ".join(modules_without_desc))
if not any_modules:
lines.append("No modules loaded.")
if self.HELP_POST is not None: if self.HELP_POST is not None:
lines.extend(self.HELP_POST) lines.extend(self.HELP_POST)
@ -79,8 +111,7 @@ class ModuleBot(Bot):
return module.HELP_SPECIFIC return module.HELP_SPECIFIC
# Overwriting the botrulez help function async def cmd_modules_help(self,
async def cmd_help_specific(self,
room: Room, room: Room,
message: LiveMessage, message: LiveMessage,
args: SpecificArgumentData args: SpecificArgumentData
@ -100,6 +131,12 @@ class ModuleBot(Bot):
# Sending along all kinds of events # Sending along all kinds of events
async def on_connected(self, room: Room) -> None:
await super().on_connected(room)
for module in self.modules.values():
await module.on_connected(room)
async def on_snapshot(self, room: Room, messages: List[LiveMessage]) -> None: async def on_snapshot(self, room: Room, messages: List[LiveMessage]) -> None:
await super().on_snapshot(room, messages) await super().on_snapshot(room, messages)
@ -141,6 +178,18 @@ class ModuleBot(Bot):
for module in self.modules.values(): for module in self.modules.values():
await module.on_edit(room, message) await module.on_edit(room, message)
async def on_login(self, room: Room, account_id: str) -> None:
await super().on_login(room, account_id)
for module in self.modules.values():
await module.on_login(room, account_id)
async def on_logout(self, room: Room) -> None:
await super().on_logout(room)
for module in self.modules.values():
await module.on_logout(room)
async def on_pm(self, async def on_pm(self,
room: Room, room: Room,
from_id: str, from_id: str,
@ -158,3 +207,8 @@ class ModuleBot(Bot):
for module in self.modules.values(): for module in self.modules.values():
await module.on_disconnect(room, reason) await module.on_disconnect(room, reason)
ModuleBotConstructor = Callable[
[configparser.ConfigParser, str, Dict[str, ModuleConstructor]],
Bot
]