omg it's the future (#15)
* Add Database.UserChannelSettings.find_all_by_setting * Turns out we didn't need find_all_by_setting * Actually, we do need find_all_by_setting * Table name typo * Add Utils.bold and Utils.underline * Added functionality to load, unload and reload modules from a command!
This commit is contained in:
parent
7db9a8ea2b
commit
ba065ad646
3 changed files with 80 additions and 23 deletions
|
@ -179,7 +179,7 @@ class EventHook(object):
|
||||||
returns.append(hook.call(event))
|
returns.append(hook.call(event))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
self.bot.log.error("failed to call event \"%s", [
|
self.bot.log.error("failed to call event \"%s\"", [
|
||||||
event_path], exc_info=True)
|
event_path], exc_info=True)
|
||||||
called += 1
|
called += 1
|
||||||
|
|
||||||
|
@ -202,11 +202,9 @@ class EventHook(object):
|
||||||
child_name_lower = child_name.lower()
|
child_name_lower = child_name.lower()
|
||||||
if child_name_lower in self._children:
|
if child_name_lower in self._children:
|
||||||
del self._children[child_name_lower]
|
del self._children[child_name_lower]
|
||||||
def get_children(self):
|
|
||||||
return self._children.keys()
|
|
||||||
|
|
||||||
def check_purge(self):
|
def check_purge(self):
|
||||||
if len(self.get_hooks()) == 0 and len(self._children
|
if len(self.get_hooks()) == 0 and len(self.get_children()
|
||||||
) == 0 and not self.parent == None:
|
) == 0 and not self.parent == None:
|
||||||
self.parent.remove_child(self.name)
|
self.parent.remove_child(self.name)
|
||||||
self.parent.check_purge()
|
self.parent.check_purge()
|
||||||
|
@ -218,9 +216,16 @@ class EventHook(object):
|
||||||
def purge_context(self, context):
|
def purge_context(self, context):
|
||||||
if self.has_context(context):
|
if self.has_context(context):
|
||||||
self.remove_context(context)
|
self.remove_context(context)
|
||||||
for child in self.get_children():
|
for child_name in self.get_children()[:]:
|
||||||
|
child = self.get_child(child_name)
|
||||||
child.purge_context(context)
|
child.purge_context(context)
|
||||||
|
if child.is_empty():
|
||||||
|
self.remove_child(child_name)
|
||||||
|
|
||||||
def get_hooks(self):
|
def get_hooks(self):
|
||||||
return sorted(self._hooks + list(itertools.chain.from_iterable(
|
return sorted(self._hooks + list(itertools.chain.from_iterable(
|
||||||
self._context_hooks.values())), key=lambda e: e.priority)
|
self._context_hooks.values())), key=lambda e: e.priority)
|
||||||
|
def get_children(self):
|
||||||
|
return list(self._children.keys())
|
||||||
|
def is_empty(self):
|
||||||
|
return len(self.get_hooks() + self.get_children()) == 0
|
||||||
|
|
|
@ -10,13 +10,15 @@ class ModuleManager(object):
|
||||||
def list_modules(self):
|
def list_modules(self):
|
||||||
return sorted(glob.glob(os.path.join(self.directory, "*.py")))
|
return sorted(glob.glob(os.path.join(self.directory, "*.py")))
|
||||||
|
|
||||||
def module_name(self, filename):
|
def _module_name(self, path):
|
||||||
return os.path.basename(filename).rsplit(".py", 1)[0].lower()
|
return os.path.basename(path).rsplit(".py", 1)[0].lower()
|
||||||
|
def _module_path(self, name):
|
||||||
|
return os.path.join(self.directory, "%s.py" % name)
|
||||||
|
|
||||||
def _load_module(self, filename):
|
def _load_module(self, name):
|
||||||
name = self.module_name(filename)
|
path = self._module_path(name)
|
||||||
|
|
||||||
with open(filename) as module_file:
|
with open(path) as module_file:
|
||||||
while True:
|
while True:
|
||||||
line = module_file.readline().strip()
|
line = module_file.readline().strip()
|
||||||
line_split = line.split(" ")
|
line_split = line.split(" ")
|
||||||
|
@ -36,11 +38,11 @@ class ModuleManager(object):
|
||||||
if not "bitbot_%s" % line_split[1].lower() in sys.modules:
|
if not "bitbot_%s" % line_split[1].lower() in sys.modules:
|
||||||
if not line_split[1].lower() in self.waiting_requirement:
|
if not line_split[1].lower() in self.waiting_requirement:
|
||||||
self.waiting_requirement[line_split[1].lower()] = set([])
|
self.waiting_requirement[line_split[1].lower()] = set([])
|
||||||
self.waiting_requirement[line_split[1].lower()].add(filename)
|
self.waiting_requirement[line_split[1].lower()].add(path)
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
module = imp.load_source(name, filename)
|
module = imp.load_source(name, path)
|
||||||
|
|
||||||
if not hasattr(module, "Module"):
|
if not hasattr(module, "Module"):
|
||||||
raise ImportError("module '%s' doesn't have a Module class.")
|
raise ImportError("module '%s' doesn't have a Module class.")
|
||||||
|
@ -60,23 +62,34 @@ class ModuleManager(object):
|
||||||
"module name '%s' attempted to be used twice.")
|
"module name '%s' attempted to be used twice.")
|
||||||
return module_object
|
return module_object
|
||||||
|
|
||||||
def load_module(self, filename):
|
def load_module(self, name):
|
||||||
name = self.module_name(filename)
|
|
||||||
try:
|
try:
|
||||||
module = self._load_module(filename)
|
module = self._load_module(name)
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
sys.stderr.write("module '%s' not loaded: Could not resolve import.\n" % filename)
|
self.bot.log.error("failed to load module \"%s\": %s",
|
||||||
|
[name, e.msg])
|
||||||
return
|
return
|
||||||
if module:
|
if module:
|
||||||
self.modules[module._import_name] = module
|
self.modules[module._import_name] = module
|
||||||
if name in self.waiting_requirement:
|
if name in self.waiting_requirement:
|
||||||
for filename in self.waiting_requirement:
|
for requirement_name in self.waiting_requirement:
|
||||||
self.load_module(filename)
|
self.load_module(requirement_name)
|
||||||
sys.stderr.write("module '%s' loaded.\n" % filename)
|
self.bot.log.info("Module '%s' loaded", [name])
|
||||||
else:
|
else:
|
||||||
sys.stderr.write("module '%s' not loaded.\n" % filename)
|
self.bot.log.error("Module '%s' not loaded", [name])
|
||||||
|
|
||||||
def load_modules(self, whitelist=None):
|
def load_modules(self, whitelist=None):
|
||||||
for filename in self.list_modules():
|
for path in self.list_modules():
|
||||||
if whitelist == None or filename in whitelist:
|
name = self._module_name(path)
|
||||||
self.load_module(filename)
|
if whitelist == None or name in whitelist:
|
||||||
|
self.load_module(name)
|
||||||
|
|
||||||
|
def unload_module(self, name):
|
||||||
|
module = self.modules[name]
|
||||||
|
del self.modules[name]
|
||||||
|
|
||||||
|
event_context = module._event_context
|
||||||
|
self.events.purge_context(event_context)
|
||||||
|
|
||||||
|
del sys.modules[name]
|
||||||
|
del module
|
||||||
|
|
39
modules/modules.py
Normal file
39
modules/modules.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
|
||||||
|
|
||||||
|
class Module(object):
|
||||||
|
def __init__(self, bot, events):
|
||||||
|
self.bot = bot
|
||||||
|
events.on("received.command.loadmodule").hook(self.load,
|
||||||
|
min_args=1, permission="load-module", help="Load a module",
|
||||||
|
usage="<module-name>")
|
||||||
|
events.on("received.command.unloadmodule").hook(self.unload,
|
||||||
|
min_args=1, permission="unload-module", help="Unload a module",
|
||||||
|
usage="<module-name>")
|
||||||
|
events.on("received.command.reloadmodule").hook(self.reload,
|
||||||
|
min_args=1, permission="reload-module", help="Reload a module",
|
||||||
|
usage="<module-name>")
|
||||||
|
|
||||||
|
def load(self, event):
|
||||||
|
name = event["args_split"][0].lower()
|
||||||
|
if name in self.bot.modules.modules:
|
||||||
|
event["stderr"].write("Module '%s' is already loaded" % name)
|
||||||
|
return
|
||||||
|
self.bot.modules.load_module(name)
|
||||||
|
event["stdout"].write("Loaded '%s'" % name)
|
||||||
|
|
||||||
|
def unload(self, event):
|
||||||
|
name = event["args_split"][0].lower()
|
||||||
|
if not name in self.bot.modules.modules:
|
||||||
|
event["stderr"].write("Module '%s' isn't loaded" % name)
|
||||||
|
return
|
||||||
|
self.bot.modules.unload_module(name)
|
||||||
|
event["stdout"].write("Unloaded '%s'" % name)
|
||||||
|
|
||||||
|
def reload(self, event):
|
||||||
|
name = event["args_split"][0].lower()
|
||||||
|
if not name in self.bot.modules.modules:
|
||||||
|
event["stderr"].write("Module '%s' isn't loaded" % name)
|
||||||
|
return
|
||||||
|
self.bot.modules.unload_module(name)
|
||||||
|
self.bot.modules.load_module(name)
|
||||||
|
event["stdout"].write("Reloaded '%s'" % name)
|
Loading…
Reference in a new issue