mirror of
https://github.com/checktheroads/hyperglass
synced 2024-05-11 05:55:08 +00:00
120 lines
3.4 KiB
Python
120 lines
3.4 KiB
Python
"""Base Plugin Definition."""
|
|
|
|
# Standard Library
|
|
import typing as t
|
|
from abc import ABC
|
|
from inspect import Signature
|
|
|
|
# Third Party
|
|
from pydantic import BaseModel, PrivateAttr
|
|
|
|
# Project
|
|
from hyperglass.log import log as _logger
|
|
|
|
if t.TYPE_CHECKING:
|
|
# Third Party
|
|
from loguru import Logger
|
|
|
|
PluginType = t.Union[t.Literal["output"], t.Literal["input"]]
|
|
SupportedMethod = t.TypeVar("SupportedMethod")
|
|
|
|
|
|
class HyperglassPlugin(BaseModel, ABC):
|
|
"""Plugin to interact with device command output."""
|
|
|
|
__hyperglass_builtin__: bool = PrivateAttr(False)
|
|
_type: t.ClassVar[str]
|
|
name: str
|
|
common: bool = False
|
|
ref: t.Optional[str] = None
|
|
log: t.ClassVar["Logger"] = _logger
|
|
|
|
@property
|
|
def _signature(self) -> Signature:
|
|
"""Get this instance's class signature."""
|
|
return self.__class__.__signature__
|
|
|
|
def __eq__(self, other: "HyperglassPlugin") -> bool:
|
|
"""Other plugin is equal to this plugin."""
|
|
if hasattr(other, "_signature"):
|
|
return other and self._signature == other._signature
|
|
return False
|
|
|
|
def __ne__(self, other: "HyperglassPlugin") -> bool:
|
|
"""Other plugin is not equal to this plugin."""
|
|
return not self.__eq__(other)
|
|
|
|
def __hash__(self) -> int:
|
|
"""Create a hashed representation of this plugin's name."""
|
|
return hash(self._signature)
|
|
|
|
def __str__(self) -> str:
|
|
"""Represent plugin by its name."""
|
|
return self.name
|
|
|
|
@classmethod
|
|
def __init_subclass__(cls, **kwargs: t.Any) -> None:
|
|
"""Initialize plugin object."""
|
|
name = kwargs.pop("name", None) or cls.__name__
|
|
cls.name = name
|
|
super().__init_subclass__()
|
|
|
|
def __init__(self, **kwargs: t.Any) -> None:
|
|
"""Initialize plugin instance."""
|
|
name = kwargs.pop("name", None) or self.__class__.__name__
|
|
super().__init__(name=name, **kwargs)
|
|
|
|
def __rich_console__(self, *_, **__):
|
|
"""Create a rich representation of this plugin for the hyperglass CLI."""
|
|
|
|
# Third Party
|
|
from rich.text import Text
|
|
from rich.panel import Panel
|
|
from rich.table import Table
|
|
from rich.pretty import Pretty
|
|
|
|
table = Table.grid(padding=(0, 1), expand=False)
|
|
table.add_column(justify="right")
|
|
|
|
data = {"builtin": True if self.__hyperglass_builtin__ else False}
|
|
data.update(
|
|
{
|
|
attr: getattr(self, attr)
|
|
for attr in ("name", "common", "directives", "platforms")
|
|
if hasattr(self, attr)
|
|
}
|
|
)
|
|
data = {k: data[k] for k in sorted(data.keys())}
|
|
for key, value in data.items():
|
|
table.add_row(
|
|
Text.assemble((key, "inspect.attr"), (" =", "inspect.equals")), Pretty(value)
|
|
)
|
|
|
|
yield Panel(
|
|
table,
|
|
expand=False,
|
|
title=f"[bold magenta]{self.name}",
|
|
title_align="left",
|
|
subtitle=f"[bold cornflower_blue]{self._type.capitalize()} Plugin",
|
|
subtitle_align="right",
|
|
padding=(1, 3),
|
|
)
|
|
|
|
|
|
class DirectivePlugin(BaseModel):
|
|
"""Plugin associated with directives.
|
|
|
|
Should always be subclassed with `HyperglassPlugin`.
|
|
"""
|
|
|
|
directives: t.Sequence[str] = ()
|
|
|
|
|
|
class PlatformPlugin(BaseModel):
|
|
"""Plugin associated with specific device platform.
|
|
|
|
Should always be subclassed with `HyperglassPlugin`.
|
|
"""
|
|
|
|
platforms: t.Sequence[str] = ()
|