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.
shepherd-agent/shepherd/module.py

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