Source code for doitoml.entry_points
"""Loads entry points."""
import sys
from typing import TYPE_CHECKING, Any, Dict, Tuple, Union
from doitoml.errors import EntryPointError, MissingDependencyError
from .constants import ENTRY_POINTS
if sys.version_info < (3, 10): # pragma: no cover
from importlib_metadata import entry_points
else: # pragma: no cover
from importlib.metadata import entry_points
if TYPE_CHECKING:
from .actors._actor import Actor
from .doitoml import DoiTOML
from .dsl import DSL
from .skippers._skipper import Skipper
from .sources._config import ConfigParser
from .sources._source import Parser
from .templaters._templater import Templater
from .updaters._updater import Updater
[docs]
class EntryPoints:
"""A collection of named ``entry_points``."""
doitoml: "DoiTOML"
dsl: Dict[str, "DSL"]
parsers: Dict[str, "Parser"]
config_parsers: Dict[str, "ConfigParser"]
actors: Dict[str, "Actor"]
templaters: Dict[str, "Templater"]
updaters: Dict[str, "Updater"]
skippers: Dict[str, "Skipper"]
def __init__(self, doitoml: "DoiTOML") -> None:
"""Create a new collection of loaded ``entry_points``."""
self.doitoml = doitoml
[docs]
def initialize(self) -> None:
"""Load all ``entry_points``."""
# load the parsers
self.config_parsers = self.load_entry_point_group(ENTRY_POINTS.CONFIG)
self.parsers = self.load_entry_point_group(ENTRY_POINTS.PARSER)
# load DSL, which might reference parsers
self.dsl = self.load_entry_point_group(ENTRY_POINTS.DSL)
self.actors = self.load_entry_point_group(ENTRY_POINTS.ACTOR)
self.templaters = self.load_entry_point_group(ENTRY_POINTS.TEMPLATER)
self.updaters = self.load_entry_point_group(ENTRY_POINTS.UPDATER)
self.skippers = self.load_entry_point_group(ENTRY_POINTS.SKIPPER)
[docs]
def load_entry_point_group(self, group: str) -> Dict[str, Any]:
"""Find and load ``entry_points`` from installed packages."""
eps = {}
for entry_point in entry_points(group=group):
try:
eps[entry_point.name] = entry_point.load()(self.doitoml)
except MissingDependencyError as err:
self.doitoml.log.info(
"%s %s is missing a dependency: %s",
group,
entry_point.name,
err,
)
except Exception as err: # pragma: no cover
message = (
f"{group} {entry_point.name} unexpectedly failed to load {err}"
)
raise EntryPointError(message) from err
return dict(sorted(eps.items(), key=self.rank_key))
[docs]
def rank_key(self, key_ep: Tuple[str, Any]) -> Tuple[Union[int, float], str]:
"""Return a sort key based on the ``entry_point``'s ``rank`` and key."""
key, ep = key_ep
return (getattr(ep, "rank", 100), key.lower())