Coverage for lintro / ai / availability.py: 54%
46 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
1"""Graceful degradation for AI dependencies.
3Checks whether the required AI provider packages are installed and
4provides clear error messages when they are not.
5"""
7from __future__ import annotations
9from typing import TYPE_CHECKING
11import click
13if TYPE_CHECKING:
14 from lintro.ai.registry import AIProvider
16_AI_AVAILABLE: bool | None = None
19def is_ai_available() -> bool:
20 """Check if at least one AI provider package is installed.
22 Returns:
23 bool: True if anthropic or openai is importable.
24 """
25 global _AI_AVAILABLE
27 if _AI_AVAILABLE is not None:
28 return _AI_AVAILABLE
30 try:
31 import anthropic # noqa: F401 -- import-only availability check
33 _AI_AVAILABLE = True
34 return True
35 except ImportError:
36 pass
38 try:
39 import openai # noqa: F401 -- import-only availability check
41 _AI_AVAILABLE = True
42 return True
43 except ImportError:
44 pass
46 _AI_AVAILABLE = False
47 return False
50def is_provider_available(provider: AIProvider | str) -> bool:
51 """Check if a specific provider package is installed.
53 Args:
54 provider: Provider name ("anthropic" or "openai").
56 Returns:
57 bool: True if the provider's package is importable.
58 """
59 from lintro.ai.registry import AIProvider
61 if isinstance(provider, AIProvider):
62 provider_value = provider.value
63 else:
64 provider_value = str(provider).lower()
66 if provider_value not in {p.value for p in AIProvider}:
67 from loguru import logger
69 supported = ", ".join(p.value for p in AIProvider)
70 logger.warning(
71 "Unknown AI provider {!r}; supported providers: {}",
72 provider_value,
73 supported,
74 )
75 return False
77 try:
78 if provider_value == AIProvider.ANTHROPIC.value:
79 import anthropic # noqa: F401 -- import-only availability check
81 return True
82 if provider_value == AIProvider.OPENAI.value:
83 import openai # noqa: F401 -- import-only availability check
85 return True
86 except ImportError:
87 pass
88 return False
91def require_ai() -> None:
92 """Ensure AI dependencies are installed.
94 Raises:
95 click.UsageError: If no AI provider packages are installed,
96 with installation instructions.
97 """
98 if not is_ai_available():
99 raise click.UsageError(
100 "AI features require lintro[ai]. "
101 "Install with: uv pip install 'lintro[ai]'",
102 )
105def reset_availability_cache() -> None:
106 """Reset the cached availability check.
108 Useful for testing when mocking imports.
109 """
110 global _AI_AVAILABLE
111 _AI_AVAILABLE = None