Coverage for lintro / tools / core / install_strategies / pip_strategy.py: 95%
38 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"""Pip/uv install strategy."""
3from __future__ import annotations
5from lintro.enums.install_context import InstallContext, PackageManager
6from lintro.tools.core.install_strategies.base import InstallStrategy
7from lintro.tools.core.install_strategies.brew_names import BREW_FORMULA_NAMES
8from lintro.tools.core.install_strategies.environment import InstallEnvironment
9from lintro.tools.core.install_strategies.registry import register_strategy
12class PipStrategy(InstallStrategy):
13 """Install strategy for pip/uv-managed Python packages."""
15 def install_type(self) -> str:
16 """Return ``'pip'``."""
17 return "pip"
19 def is_available(self, env: InstallEnvironment) -> bool:
20 """Available if uv, pip, or brew (for formula-mapped tools) exists."""
21 return (
22 env.has(PackageManager.UV)
23 or env.has(PackageManager.PIP)
24 or env.has(PackageManager.BREW)
25 )
27 def check_prerequisites(
28 self,
29 env: InstallEnvironment,
30 tool_name: str,
31 ) -> str | None:
32 """Return skip reason if neither uv nor pip is available.
34 Args:
35 env: The current install environment.
36 tool_name: Canonical tool name.
38 Returns:
39 Skip reason or None.
40 """
41 if env.has(PackageManager.UV) or env.has(PackageManager.PIP):
42 return None
43 if env.has(PackageManager.BREW) and tool_name in BREW_FORMULA_NAMES:
44 return None
45 return "uv/pip not available"
47 def install_hint(
48 self,
49 env: InstallEnvironment,
50 tool_name: str,
51 tool_version: str,
52 install_package: str | None,
53 install_component: str | None,
54 ) -> str:
55 """Generate pip install hint.
57 Args:
58 env: The current install environment.
59 tool_name: Canonical tool name.
60 tool_version: Expected version.
61 install_package: Package name override.
62 install_component: Unused for pip.
64 Returns:
65 Shell command string.
66 """
67 pkg = install_package or tool_name
68 brew_pkg = BREW_FORMULA_NAMES.get(tool_name)
69 if (
70 brew_pkg
71 and env.has(PackageManager.BREW)
72 and (
73 _is_homebrew_context(env)
74 or not (env.has(PackageManager.UV) or env.has(PackageManager.PIP))
75 )
76 ):
77 return f"brew install {brew_pkg}"
78 if not (env.has(PackageManager.UV) or env.has(PackageManager.PIP)):
79 return f"Install {tool_name} via pip/uv (neither found in PATH)"
80 return f"{_pip_cmd(env)} '{pkg}>={tool_version}'"
82 def upgrade_hint(
83 self,
84 env: InstallEnvironment,
85 tool_name: str,
86 tool_version: str,
87 install_package: str | None,
88 install_component: str | None,
89 ) -> str:
90 """Generate pip upgrade hint.
92 Args:
93 env: The current install environment.
94 tool_name: Canonical tool name.
95 tool_version: Expected version.
96 install_package: Package name override.
97 install_component: Unused for pip.
99 Returns:
100 Shell command string.
101 """
102 pkg = install_package or tool_name
103 brew_pkg = BREW_FORMULA_NAMES.get(tool_name)
104 if (
105 brew_pkg
106 and env.has(PackageManager.BREW)
107 and (
108 _is_homebrew_context(env)
109 or not (env.has(PackageManager.UV) or env.has(PackageManager.PIP))
110 )
111 ):
112 return f"brew upgrade {brew_pkg}"
113 if not (env.has(PackageManager.UV) or env.has(PackageManager.PIP)):
114 return f"Upgrade {tool_name} via pip/uv (neither found in PATH)"
115 return f"{_pip_cmd(env)} --upgrade '{pkg}>={tool_version}'"
118def _pip_cmd(env: InstallEnvironment) -> str:
119 """Return the preferred pip install command prefix."""
120 return "uv pip install" if env.has(PackageManager.UV) else "pip install"
123def _is_homebrew_context(env: InstallEnvironment) -> bool:
124 """Check if the environment is a Homebrew install with brew available."""
125 return env.has(PackageManager.BREW) and env.install_context in (
126 InstallContext.HOMEBREW_FULL,
127 InstallContext.HOMEBREW_BIN,
128 )
131register_strategy(PipStrategy())