Coverage for / home / runner / work / bijux-cli / bijux-cli / src / bijux_cli / plugins / contracts.py: 100%
27 statements
« prev ^ index » next coverage.py v7.13.2, created at 2026-01-26 17:59 +0000
« prev ^ index » next coverage.py v7.13.2, created at 2026-01-26 17:59 +0000
1# SPDX-License-Identifier: Apache-2.0
2# Copyright © 2025 Bijan Mousavi
4"""Plugin-level protocol contracts."""
6from __future__ import annotations
8from dataclasses import dataclass
9from enum import Enum
10from typing import Any, Protocol, TypeVar, runtime_checkable
12T = TypeVar("T")
15@runtime_checkable
16class RegistryProtocol(Protocol):
17 """Contract for plugin registry management."""
19 def register(
20 self,
21 name: str,
22 plugin: object,
23 *,
24 alias: str | None,
25 version: str | None,
26 ) -> None:
27 """Register a plugin."""
28 ...
30 def deregister(self, name: str) -> None:
31 """Remove a plugin."""
32 ...
34 def get(self, name: str) -> object:
35 """Retrieve a plugin by name or alias."""
36 ...
38 def has(self, name: str) -> bool:
39 """Check if a plugin exists."""
40 ...
42 def names(self) -> list[str]:
43 """List registered plugin names."""
44 ...
46 def meta(self, name: str) -> dict[str, str]:
47 """Return plugin metadata."""
48 ...
50 def state(self, name: str) -> PluginState | None:
51 """Return plugin lifecycle state."""
52 ...
54 def transition(self, name: str, state: PluginState) -> None:
55 """Move a plugin to a lifecycle state."""
56 ...
58 async def call_hook(self, hook: str, *args: Any, **kwargs: Any) -> Any:
59 """Invoke a hook on all plugins."""
60 ...
63@dataclass(frozen=True)
64class PluginConfig:
65 """Configuration for plugin discovery and activation."""
67 enabled: bool
68 allow_entrypoints: bool
71__all__ = ["PluginConfig", "PluginState", "RegistryProtocol"]
74class PluginState(str, Enum):
75 """Lifecycle states for plugins."""
77 DISCOVERED = "discovered"
78 INSTALLED = "installed"
79 ACTIVE = "active"
80 INACTIVE = "inactive"
81 REMOVED = "removed"