#!/usr/bin/env python3 """ Methods for loading modules. """ import os import sys import importlib def load_module(bot, path): """ Loads a module from the provided path, cleans it up and registers it with the bot's internal callable list. """ module = importlib.import_module(path) if hasattr(module, 'setup'): module.setup(bot) relevant_parts = process_module(module, bot.config) bot.register_callable(relevant_parts) def unload_module(bot, name): """ Unloads a module and deletes references to it from the bot's memory. """ old_module = sys.modules[name] # delete references to the module functions from the bot's memory for obj_name, obj in vars(old_module).items(): bot.unregister_callable(obj) del old_module del sys.modules[name] def find_modules(homedir): """ Searches through homedir/modules for python files and returns a dictionary with the module name as the key and the path as the value. """ modules_dir = os.path.join(homedir, "modules") modules = {} for file in os.listdir(modules_dir): if not file.endswith(".py"): continue name = file.replace(".py", "") modules[name] = "modules" + "." + name return modules def process_module(module, config): """ Takes a module object and extracts relevant data objects out of it. Returns all callables(read: functions) and shutdowns(?). """ callables = [] for key, obj in dict.items(vars(module)): if callable(obj): if is_triggerable(obj): process_callable(obj, config) callables.append(obj) return callables def is_triggerable(obj): """ Checks if the given function object is triggerable by Fulvia, eg. has any of a few particular attributes or declarators defined. """ triggerable_attributes = ("commands", "hook", "url_callback") return any(hasattr(obj, attr) for attr in triggerable_attributes) def process_callable(func, config): """ Sets various helper atributes about a given function. """ prefix = config.core.prefix doc = func.__doc__ if doc: doc = doc.strip() doc = doc.replace("\t", "") doc = doc.replace("\n\n", "\x00") doc = doc.replace("\n", " ") doc = doc.replace("\x00", "\n") func._docs = {} func.example = getattr(func, "example", [(None, None)]) func.thread = getattr(func, "thread", True) func.hook = getattr(func, "hook", False) func.rate = getattr(func, "rate", 0) func.channel_rate = getattr(func, "channel_rate", 0) func.global_rate = getattr(func, "global_rate", 0) func.priv = getattr(func, "priv", 0) if hasattr(func, 'commands'): if len(func.commands) > 1: func.aliases = func.commands[1:] else: func.aliases = [] if hasattr(func, 'example'): for n, example in enumerate(func.example): ex_input = example[0] if not ex_input: continue if ex_input[0] != prefix: ex_input = prefix + ex_input func.example[n] = (ex_input, example[1]) if doc: func._docs = (doc, func.example)