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

1# SPDX-License-Identifier: Apache-2.0 

2# Copyright © 2025 Bijan Mousavi 

3 

4"""Plugin-level protocol contracts.""" 

5 

6from __future__ import annotations 

7 

8from dataclasses import dataclass 

9from enum import Enum 

10from typing import Any, Protocol, TypeVar, runtime_checkable 

11 

12T = TypeVar("T") 

13 

14 

15@runtime_checkable 

16class RegistryProtocol(Protocol): 

17 """Contract for plugin registry management.""" 

18 

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 ... 

29 

30 def deregister(self, name: str) -> None: 

31 """Remove a plugin.""" 

32 ... 

33 

34 def get(self, name: str) -> object: 

35 """Retrieve a plugin by name or alias.""" 

36 ... 

37 

38 def has(self, name: str) -> bool: 

39 """Check if a plugin exists.""" 

40 ... 

41 

42 def names(self) -> list[str]: 

43 """List registered plugin names.""" 

44 ... 

45 

46 def meta(self, name: str) -> dict[str, str]: 

47 """Return plugin metadata.""" 

48 ... 

49 

50 def state(self, name: str) -> PluginState | None: 

51 """Return plugin lifecycle state.""" 

52 ... 

53 

54 def transition(self, name: str, state: PluginState) -> None: 

55 """Move a plugin to a lifecycle state.""" 

56 ... 

57 

58 async def call_hook(self, hook: str, *args: Any, **kwargs: Any) -> Any: 

59 """Invoke a hook on all plugins.""" 

60 ... 

61 

62 

63@dataclass(frozen=True) 

64class PluginConfig: 

65 """Configuration for plugin discovery and activation.""" 

66 

67 enabled: bool 

68 allow_entrypoints: bool 

69 

70 

71__all__ = ["PluginConfig", "PluginState", "RegistryProtocol"] 

72 

73 

74class PluginState(str, Enum): 

75 """Lifecycle states for plugins.""" 

76 

77 DISCOVERED = "discovered" 

78 INSTALLED = "installed" 

79 ACTIVE = "active" 

80 INACTIVE = "inactive" 

81 REMOVED = "removed"