コード例 #1
0
 def __init__(self,
              config: ConfigurationManager,
              *,
              base=BasePlugin,
              factory=None):
     self.base = base
     self.config = config
     self.failed = {}
     self._seen_classes = set()
     self._plugins = {}
     self._activated_plugins = set()
     self._deactivated_plugins = set()
     self._resolved = False
     self._overrides = set()
     self._override_cache = set()
     self._packet_parser = PacketParser(self.config)
     self._factory = factory
     self.logger = logging.getLogger("starrypy.plugin_manager")
コード例 #2
0
 def __init__(self, config: ConfigurationManager, *, base=BasePlugin,
              factory=None):
     self.base = base
     self.config = config
     self.failed = {}
     self._seen_classes = set()
     self._plugins = {}
     self._activated_plugins = set()
     self._deactivated_plugins = set()
     self._resolved = False
     self._overrides = set()
     self._override_cache = set()
     self._packet_parser = PacketParser(self.config)
     self._factory = factory
     self.logger = logging.getLogger("starrypy.plugin_manager")
コード例 #3
0
class PluginManager:
    def __init__(self, config: ConfigurationManager, *, base=BasePlugin,
                 factory=None):
        self.base = base
        self.config = config
        self.failed = {}
        self._seen_classes = set()
        self._plugins = {}
        self._activated_plugins = set()
        self._deactivated_plugins = set()
        self._resolved = False
        self._overrides = set()
        self._override_cache = set()
        self._packet_parser = PacketParser(self.config)
        self._factory = factory
        self.logger = logging.getLogger("starrypy.plugin_manager")

    def list_plugins(self):
        return self._plugins

    @asyncio.coroutine
    def do(self, protocol, action: str, packet: dict):
        """
        Calls an action on all loaded plugins
        """
        try:
            if ("on_%s" % action) in self._overrides:
                packet = yield from self._packet_parser.parse(packet)
                send_flag = True
                for plugin in self._plugins.values():
                    p = getattr(plugin, "on_%s" % action)
                    if not (yield from p(packet, protocol)):
                        send_flag = False
                return send_flag
            else:
                return True
        except:
            self.logger.exception("Exception encountered in plugin on action: "
                                  "%s", action, exc_info=True)
            return True

    def load_from_path(self, plugin_path: pathlib.Path):
        blacklist = ["__init__", "__pycache__"]
        loaded = set()
        for file in plugin_path.iterdir():
            if file.stem in blacklist:
                continue
            if (file.suffix == ".py" or file.is_dir()) and str(
                    file) not in loaded:
                try:
                    loaded.add(str(file))
                    self.load_plugin(file)
                except (SyntaxError, ImportError) as e:
                    self.failed[file.stem] = str(e)
                    print(e)
                except FileNotFoundError:
                    self.logger.warning("File not found in plugin loader.")

    @staticmethod
    def _load_module(file_path: pathlib.Path):
        """
        Attempts to load a module, either from a straight python file or from
        a python package, by appending __init__.py to the end of the path if it
        is a directory.
        """
        if file_path.is_dir():
            file_path /= '__init__.py'
        if not file_path.exists():
            raise FileNotFoundError("{0} doesn't exist.".format(file_path))
        name = "plugins.%s" % file_path.stem
        loader = importlib.machinery.SourceFileLoader(name, str(file_path))
        module = loader.load_module(name)
        return module

    def load_plugin(self, plugin_path: pathlib.Path):
        module = self._load_module(plugin_path)
        classes = self.get_classes(module)
        for candidate in classes:
            candidate.factory = self._factory
            self._seen_classes.add(candidate)
        self.config.save_config()

    def get_classes(self, module: ModuleType):
        """
        Uses the inspect module to find all classes in a given module that
        are subclassed from `self.base`, but are not actually `self.base`.
        """
        class_list = []
        for _, obj in inspect.getmembers(module):
            if inspect.isclass(obj):
                if issubclass(obj, self.base) and obj is not self.base:
                    obj.config = self.config
                    obj.logger = logging.getLogger("starrypy.plugin.%s" %
                                                   obj.name)
                    class_list.append(obj)

        return class_list

    def load_plugins(self, plugins: list):
        for plugin in plugins:
            self.load_plugin(plugin)

    def resolve_dependencies(self):
        """
        Resolves dependencies from self._seen_classes through a very simple
        topological sort. Raises ImportError if there is an unresolvable
        dependency, otherwise it instantiates the class and puts it in
        self._plugins.
        """
        deps = {x.name: set(x.depends) for x in self._seen_classes}
        classes = {x.name: x for x in self._seen_classes}
        while len(deps) > 0:
            ready = [x for x, d in deps.items() if len(d) == 0]
            for name in ready:
                p = classes[name]()
                self._plugins[name] = p
                del deps[name]
            for name, depends in deps.items():
                to_load = depends & set(self._plugins.keys())
                deps[name] = deps[name].difference(set(self._plugins.keys()))
                for plugin in to_load:
                    classes[name].plugins[plugin] = self._plugins[plugin]
            if len(ready) == 0:
                raise ImportError("Unresolved dependencies found.")
        self._resolved = True

    @asyncio.coroutine
    def get_overrides(self):
        if self._override_cache is self._activated_plugins:
            return self._overrides
        else:
            overrides = set()
            for plugin in self._activated_plugins:
                override = yield from detect_overrides(BasePlugin, plugin)
                overrides.update({x for x in override})
            self._overrides = overrides
            self._override_cache = self._activated_plugins
            return overrides

    def activate_all(self):
        self.logger.info("Activating plugins:")
        for plugin in self._plugins.values():
            self.logger.info(plugin.name)
            plugin.activate()
            self._activated_plugins.add(plugin)

    def deactivate_all(self):
        for plugin in self._plugins.values():
            self.logger.info("Deactivating %s", plugin.name)
            plugin.deactivate()
コード例 #4
0
class PluginManager:
    def __init__(self,
                 config: ConfigurationManager,
                 *,
                 base=BasePlugin,
                 factory=None):
        self.base = base
        self.config = config
        self.failed = {}
        self._seen_classes = set()
        self._plugins = {}
        self._activated_plugins = set()
        self._deactivated_plugins = set()
        self._resolved = False
        self._overrides = set()
        self._override_cache = set()
        self._packet_parser = PacketParser(self.config)
        self._factory = factory
        self.logger = logging.getLogger("starrypy.plugin_manager")

    def list_plugins(self):
        return self._plugins

    @asyncio.coroutine
    def do(self, protocol, action: str, packet: dict):
        """
        Calls an action on all loaded plugins
        """
        try:
            if ("on_%s" % action) in self._overrides:
                packet = yield from self._packet_parser.parse(packet)
                send_flag = True
                for plugin in self._plugins.values():
                    p = getattr(plugin, "on_%s" % action)
                    if not (yield from p(packet, protocol)):
                        send_flag = False
                return send_flag
            else:
                return True
        except:
            self.logger.exception(
                "Exception encountered in plugin on action: "
                "%s",
                action,
                exc_info=True)
            return True

    def load_from_path(self, plugin_path: pathlib.Path):
        blacklist = ["__init__", "__pycache__"]
        loaded = set()
        for file in plugin_path.iterdir():
            if file.stem in blacklist:
                continue
            if (file.suffix == ".py"
                    or file.is_dir()) and str(file) not in loaded:
                try:
                    loaded.add(str(file))
                    self.load_plugin(file)
                except (SyntaxError, ImportError) as e:
                    self.failed[file.stem] = str(e)
                    print(e)
                except FileNotFoundError:
                    self.logger.warning("File not found in plugin loader.")

    @staticmethod
    def _load_module(file_path: pathlib.Path):
        """
        Attempts to load a module, either from a straight python file or from
        a python package, by appending __init__.py to the end of the path if it
        is a directory.
        """
        if file_path.is_dir():
            file_path /= '__init__.py'
        if not file_path.exists():
            raise FileNotFoundError("{0} doesn't exist.".format(
                str(file_path)))
        name = "plugins.%s" % file_path.stem
        loader = importlib.machinery.SourceFileLoader(name, str(file_path))
        module = loader.load_module(name)
        return module

    def load_plugin(self, plugin_path: pathlib.Path):
        module = self._load_module(plugin_path)
        classes = self.get_classes(module)
        for candidate in classes:
            candidate.factory = self._factory
            self._seen_classes.add(candidate)

    def get_classes(self, module: ModuleType):
        """
        Uses the inspect module to find all classes in a given module that
        are subclassed from `self.base`, but are not actually `self.base`.
        """
        class_list = []
        for _, obj in inspect.getmembers(module):
            if inspect.isclass(obj):
                if issubclass(obj, self.base) and obj is not self.base:
                    obj.config = self.config
                    obj.logger = logging.getLogger("starrypy.plugin.%s" %
                                                   obj.name)
                    class_list.append(obj)

        return class_list

    def load_plugins(self, plugins: list):
        for plugin in plugins:
            self.load_plugin(plugin)

    def resolve_dependencies(self):
        """
        Resolves dependencies from self._seen_classes through a very simple
        topological sort. Raises ImportError if there is an unresolvable
        dependency, otherwise it instantiates the class and puts it in
        self._plugins.
        """
        deps = {x.name: set(x.depends) for x in self._seen_classes}
        classes = {x.name: x for x in self._seen_classes}
        while len(deps) > 0:
            ready = [x for x, d in deps.items() if len(d) == 0]
            for name in ready:
                self._plugins[name] = classes[name]()
                del deps[name]
            for name, depends in deps.items():
                to_load = depends & set(self._plugins.keys())
                deps[name] = deps[name].difference(set(self._plugins.keys()))
                for plugin in to_load:
                    classes[name].plugins[plugin] = self._plugins[plugin]
            if len(ready) == 0:
                raise ImportError("Unresolved dependencies found.")
        self._resolved = True

    @asyncio.coroutine
    def get_overrides(self):
        if self._override_cache is self._activated_plugins:
            return self._overrides
        else:
            overrides = set()
            for plugin in self._activated_plugins:
                override = yield from detect_overrides(BasePlugin, plugin)
                overrides.update({x for x in override})
            self._overrides = overrides
            self._override_cache = self._activated_plugins
            return overrides

    def activate_all(self):
        self.logger.info("Activating plugins:")
        for plugin in self._plugins.values():
            self.logger.info(plugin.name)
            plugin.activate()
            self._activated_plugins.add(plugin)

    def deactivate_all(self):
        for plugin in self._plugins.values():
            self.logger.info("Deactivating %s", plugin.name)
            plugin.deactivate()