You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
85 lines
2.6 KiB
85 lines
2.6 KiB
#!/usr/bin/env python3
|
|
|
|
from contextlib import suppress
|
|
import importlib
|
|
|
|
|
|
class Hook():
|
|
def __init__(self):
|
|
self.attached_functions = []
|
|
|
|
def attach(self, new_func):
|
|
if not callable(new_func):
|
|
raise TypeError("Argument to Hook.attach must be callable")
|
|
self.attached_functions.append(new_func)
|
|
|
|
def __call__(self, *args, **kwargs):
|
|
for func in self.attached_functions:
|
|
func(*args, **kwargs)
|
|
|
|
|
|
class Module():
|
|
def __init__(self, config, core_interface):
|
|
self.config = config
|
|
self.shepherd = core_interface
|
|
#self.shepherd.scheduler
|
|
|
|
self.interface = Interface(self)
|
|
self.modules = {}
|
|
# dummy interface in case module doesn't want one
|
|
|
|
def init_other_interfaces(self, interfaces):
|
|
if not isinstance(self.interface, Interface):
|
|
raise TypeError("shepherd.module.Module interface attribute must "
|
|
"be subclass of type shepherd.module.Interface")
|
|
self.modules = interfaces
|
|
|
|
|
|
# Look at providing a run() function or similar, which is a thread started
|
|
# post_modules_setup
|
|
class SimpleModule(Module):
|
|
def __init__(self, config, core_interface):
|
|
super().__init__(config, core_interface)
|
|
self.setup()
|
|
|
|
def init_other_interfaces(self, interfaces):
|
|
super().init_other_interfaces(interfaces)
|
|
self.setup_other_modules()
|
|
|
|
# Users override this, self.shepherd and self.config are available now.
|
|
# User still needs to define self.interface if it is used.
|
|
def setup(self):
|
|
pass
|
|
|
|
def setup_other_modules(self):
|
|
pass
|
|
|
|
|
|
"""
|
|
An interface to a Shepherd module, accessible by other modules.
|
|
All public methods in a module interface need to be threadsafe, as they will
|
|
be called by other modules (which generally run in a seperate thread)
|
|
"""
|
|
class Interface():
|
|
def __init__(self, module):
|
|
self._module = module
|
|
|
|
|
|
def find_modules(module_names):
|
|
module_classes = {}
|
|
for module_name in module_names:
|
|
mod = importlib.import_module("shepherd.modules." + module_name)
|
|
attrs = [getattr(mod, name) for name in dir(mod)]
|
|
|
|
for attr in attrs:
|
|
with suppress(TypeError):
|
|
if issubclass(attr, Module):
|
|
module_classes[module_name] = attr
|
|
break
|
|
else:
|
|
raise Exception("Imported shepherd modules must contain a "
|
|
"subclass of shepherd.module.Module, such as"
|
|
"shepherd.module.SimpleModule")
|
|
|
|
return module_classes
|