Coverage for src / lexigram / admin / integrations / features.py: 68%
40 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-13 22:14 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-13 22:14 +0800
1"""Features integration — gates UI elements behind feature flags."""
3from __future__ import annotations
5from typing import TYPE_CHECKING, Any
7if TYPE_CHECKING:
8 from lexigram.contracts.core.di import (
9 ContainerRegistrarProtocol,
10 ContainerResolverProtocol,
11 )
14class _NoOpFeatures:
15 def is_enabled(self, flag: str, context: Any = None) -> bool:
16 return True
19class FeaturesIntegration:
20 """Adapter that checks feature flags for admin UI gating.
22 Gracefully no-ops (all flags pass) when ``lexigram-features`` is not
23 installed or the integration is disabled.
24 """
26 def __init__(self, config: Any) -> None:
27 self._config = config
28 self._flags: Any = None
29 self._enabled = False
31 def register(self, container: ContainerRegistrarProtocol) -> None:
32 from lexigram.admin.config import FeaturesIntegrationConfig
33 from lexigram.admin.integrations._optional import is_installed
35 cfg = self._config
36 if not isinstance(cfg, FeaturesIntegrationConfig):
37 cfg = FeaturesIntegrationConfig()
38 if not cfg.enabled:
39 self._flags = _NoOpFeatures()
40 return
41 if not is_installed("lexigram.features"):
42 self._flags = _NoOpFeatures()
43 return
44 self._enabled = True
46 async def boot(self, container: ContainerResolverProtocol) -> None:
47 if not self._enabled:
48 return
49 try:
50 from lexigram.contracts.feature_flags import FlagManagerProtocol
52 self._flags = await container.resolve(FlagManagerProtocol)
53 except Exception: # noqa: BLE001
54 self._flags = _NoOpFeatures()
56 async def shutdown(self) -> None:
57 pass
59 async def health_check(self) -> dict[str, Any]:
60 return {
61 "status": "healthy"
62 if not isinstance(self._flags, _NoOpFeatures)
63 else "noop"
64 }
66 def is_enabled(self, flag: str, context: Any = None) -> bool:
67 return (
68 self._flags.is_enabled(flag, context)
69 if hasattr(self._flags, "is_enabled")
70 else True
71 )
73 async def is_enabled_async(self, flag: str, context: Any = None) -> bool:
74 return (
75 self._flags.is_enabled(flag, context)
76 if hasattr(self._flags, "is_enabled")
77 else True
78 )
81__all__ = ["FeaturesIntegration"]