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

1"""Pip/uv install strategy.""" 

2 

3from __future__ import annotations 

4 

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 

10 

11 

12class PipStrategy(InstallStrategy): 

13 """Install strategy for pip/uv-managed Python packages.""" 

14 

15 def install_type(self) -> str: 

16 """Return ``'pip'``.""" 

17 return "pip" 

18 

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 ) 

26 

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. 

33 

34 Args: 

35 env: The current install environment. 

36 tool_name: Canonical tool name. 

37 

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" 

46 

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. 

56 

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. 

63 

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}'" 

81 

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. 

91 

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. 

98 

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}'" 

116 

117 

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" 

121 

122 

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 ) 

129 

130 

131register_strategy(PipStrategy())