Source code for errbot.plugin_info
import inspect
import sys
from configparser import ConfigParser
from configparser import Error as ConfigParserError
from dataclasses import dataclass
from importlib._bootstrap import module_from_spec
from importlib._bootstrap_external import spec_from_file_location
from pathlib import Path
from typing import List, Tuple, Type
from errbot.utils import version2tuple
VersionType = Tuple[int, int, int]
[docs]
@dataclass
class PluginInfo:
name: str
module: str
doc: str
core: bool
python_version: VersionType
errbot_minversion: VersionType
errbot_maxversion: VersionType
dependencies: List[str]
location: Path = None
[docs]
@staticmethod
def load(plugfile_path: Path) -> "PluginInfo":
with plugfile_path.open(encoding="utf-8") as plugfile:
return PluginInfo.load_file(plugfile, plugfile_path)
[docs]
@staticmethod
def load_file(plugfile, location: Path) -> "PluginInfo":
cp = ConfigParser()
cp.read_file(plugfile)
pi = PluginInfo.parse(cp)
pi.location = location
return pi
[docs]
@staticmethod
def parse(config: ConfigParser) -> "PluginInfo":
"""
Throws ConfigParserError with a meaningful message if the ConfigParser doesn't contain the minimal
information required.
"""
name = config.get("Core", "Name")
module = config.get("Core", "Module")
core = config.get("Core", "Core", fallback="false").lower() == "true"
doc = config.get("Documentation", "Description", fallback=None)
python_version = config.get("Python", "Version", fallback=None)
# Old format backward compatibility
if python_version:
if python_version in ("2+", "3"):
python_version = (3, 0, 0)
elif python_version == "2":
python_version = (2, 0, 0)
else:
try:
python_version = tuple(
version2tuple(python_version)[0:3]
) # We can ignore the alpha/beta part.
except ValueError as ve:
raise ConfigParserError(
f"Invalid Python Version format: {python_version} ({ve})"
)
min_version = config.get("Errbot", "Min", fallback=None)
max_version = config.get("Errbot", "Max", fallback=None)
try:
if min_version:
min_version = version2tuple(min_version)
except ValueError as ve:
raise ConfigParserError(
f"Invalid Errbot min version format: {min_version} ({ve})"
)
try:
if max_version:
max_version = version2tuple(max_version)
except ValueError as ve:
raise ConfigParserError(
f"Invalid Errbot max version format: {max_version} ({ve})"
)
depends_on = config.get("Core", "DependsOn", fallback=None)
deps = [name.strip() for name in depends_on.split(",")] if depends_on else []
return PluginInfo(
name, module, doc, core, python_version, min_version, max_version, deps
)
[docs]
def load_plugin_classes(self, base_module_name: str, baseclass: Type):
# load the module
module_name = base_module_name + "." + self.module
spec = spec_from_file_location(
module_name, self.location.parent / (self.module + ".py")
)
modu1e = module_from_spec(spec)
spec.loader.exec_module(modu1e)
sys.modules[module_name] = modu1e
# introspect the modules to find plugin classes
def is_plugin(member):
return (
inspect.isclass(member)
and issubclass(member, baseclass)
and member != baseclass
)
plugin_classes = inspect.getmembers(modu1e, is_plugin)
return plugin_classes