Coverage for src / ezpl / cli / utils / env_manager.py: 71.90%

93 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-13 19:35 +0000

1# /////////////////////////////////////////////////////////////// 

2# EZPL - Environment Variable Manager 

3# Project: ezpl 

4# /////////////////////////////////////////////////////////////// 

5 

6""" 

7Environment variable manager for CLI operations. 

8 

9This module provides functionality to manage user environment variables 

10for Ezpl configuration. 

11""" 

12 

13from __future__ import annotations 

14 

15# /////////////////////////////////////////////////////////////// 

16# IMPORTS 

17# /////////////////////////////////////////////////////////////// 

18# Standard library imports 

19import os 

20import sys 

21from pathlib import Path 

22 

23# /////////////////////////////////////////////////////////////// 

24# CLASSES 

25# /////////////////////////////////////////////////////////////// 

26 

27 

28class UserEnvManager: 

29 """ 

30 Manager for user environment variables. 

31 

32 Manages environment variables in user profile for Ezpl configuration. 

33 """ 

34 

35 # Mapping of configuration keys to environment variable names 

36 CONFIG_TO_ENV = { 

37 "log-level": "EZPL_LOG_LEVEL", 

38 "log-file": "EZPL_LOG_FILE", 

39 "log-dir": "EZPL_LOG_DIR", 

40 "printer-level": "EZPL_PRINTER_LEVEL", 

41 "indent-step": "EZPL_INDENT_STEP", 

42 "indent-symbol": "EZPL_INDENT_SYMBOL", 

43 "base-indent-symbol": "EZPL_BASE_INDENT_SYMBOL", 

44 "file-logger-level": "EZPL_FILE_LOGGER_LEVEL", 

45 "log-format": "EZPL_LOG_FORMAT", 

46 "log-rotation": "EZPL_LOG_ROTATION", 

47 "log-retention": "EZPL_LOG_RETENTION", 

48 "log-compression": "EZPL_LOG_COMPRESSION", 

49 } 

50 

51 # /////////////////////////////////////////////////////////////// 

52 # INIT 

53 # /////////////////////////////////////////////////////////////// 

54 

55 def __init__(self) -> None: 

56 """Initialize the environment variable manager.""" 

57 self.env_file = self._get_env_file_path() 

58 self._tracked_vars: list[str] = [] 

59 

60 # ------------------------------------------------ 

61 # PRIVATE HELPER METHODS 

62 # ------------------------------------------------ 

63 

64 def _get_env_file_path(self) -> Path: 

65 """ 

66 Get the path to the user environment file. 

67 

68 Returns: 

69 Path to .env file in user's Ezpl directory 

70 """ 

71 if sys.platform == "win32": 71 ↛ 73line 71 didn't jump to line 73 because the condition on line 71 was never true

72 # Windows: %USERPROFILE%\.ezpl\.env 

73 user_profile = os.getenv("USERPROFILE", str(Path.home())) 

74 return Path(user_profile) / ".ezpl" / ".env" 

75 else: 

76 # Linux/macOS: ~/.ezpl/.env 

77 return Path.home() / ".ezpl" / ".env" 

78 

79 def _load_env_file(self) -> dict[str, str]: 

80 """ 

81 Load environment variables from .env file. 

82 

83 Returns: 

84 Dictionary of environment variables 

85 """ 

86 env_vars = {} 

87 if self.env_file.exists(): 

88 try: 

89 with open(self.env_file, encoding="utf-8") as f: 

90 for line in f: 

91 line = line.strip() 

92 if line and not line.startswith("#") and "=" in line: 

93 key, value = line.split("=", 1) 

94 env_vars[key.strip()] = value.strip() 

95 except (OSError, ValueError): 

96 pass 

97 return env_vars 

98 

99 def _save_env_file(self, env_vars: dict[str, str]) -> None: 

100 """ 

101 Save environment variables to .env file. 

102 

103 Args: 

104 env_vars: Dictionary of environment variables to save 

105 """ 

106 self.env_file.parent.mkdir(parents=True, exist_ok=True) 

107 

108 # Keep only managed variables to ensure removals are persisted 

109 managed_vars = { 

110 key: value for key, value in env_vars.items() if key.startswith("EZPL_") 

111 } 

112 

113 # Write back 

114 try: 

115 with open(self.env_file, "w", encoding="utf-8") as f: 

116 f.write("# Ezpl User Environment Variables\n") 

117 f.write("# Generated by: ezpl config set --env\n") 

118 f.write("# DO NOT EDIT MANUALLY - Use 'ezpl config set --env'\n\n") 

119 for key, value in sorted(managed_vars.items()): 

120 f.write(f"{key}={value}\n") 

121 except OSError: 

122 pass 

123 

124 def _get_tracked_vars(self) -> list[str]: 

125 """ 

126 Get list of tracked environment variables. 

127 

128 Returns: 

129 List of environment variable names that Ezpl manages 

130 """ 

131 if not self._tracked_vars: 

132 # Load from file if exists 

133 env_vars = self._load_env_file() 

134 self._tracked_vars = [key for key in env_vars if key.startswith("EZPL_")] 

135 return self._tracked_vars 

136 

137 # /////////////////////////////////////////////////////////////// 

138 # PUBLIC METHODS 

139 # /////////////////////////////////////////////////////////////// 

140 

141 def set_user_env(self, config_key: str, value: str) -> bool: 

142 """ 

143 Set a user environment variable from a config key. 

144 

145 Args: 

146 config_key: Configuration key (e.g., "log-level") 

147 value: Value to set 

148 

149 Returns: 

150 True if successful, False otherwise 

151 """ 

152 env_var = self.CONFIG_TO_ENV.get(config_key) 

153 if not env_var: 153 ↛ 154line 153 didn't jump to line 154 because the condition on line 153 was never true

154 return False 

155 

156 try: 

157 env_vars = self._load_env_file() 

158 env_vars[env_var] = value 

159 self._save_env_file(env_vars) 

160 

161 # Track this variable 

162 if env_var not in self._tracked_vars: 162 ↛ 165line 162 didn't jump to line 165 because the condition on line 162 was always true

163 self._tracked_vars.append(env_var) 

164 

165 return True 

166 except (OSError, ValueError): 

167 return False 

168 

169 def get_user_env(self, config_key: str) -> str | None: 

170 """ 

171 Get a user environment variable value from a config key. 

172 

173 Args: 

174 config_key: Configuration key (e.g., "log-level") 

175 

176 Returns: 

177 Environment variable value or None 

178 """ 

179 env_var = self.CONFIG_TO_ENV.get(config_key) 

180 if not env_var: 180 ↛ 181line 180 didn't jump to line 181 because the condition on line 180 was never true

181 return None 

182 

183 env_vars = self._load_env_file() 

184 return env_vars.get(env_var) 

185 

186 def remove_user_env(self, config_key: str) -> bool: 

187 """ 

188 Remove a user environment variable. 

189 

190 Args: 

191 config_key: Configuration key (e.g., "log-level") 

192 

193 Returns: 

194 True if successful, False otherwise 

195 """ 

196 env_var = self.CONFIG_TO_ENV.get(config_key) 

197 if not env_var: 197 ↛ 198line 197 didn't jump to line 198 because the condition on line 197 was never true

198 return False 

199 

200 try: 

201 env_vars = self._load_env_file() 

202 if env_var in env_vars: 202 ↛ 207line 202 didn't jump to line 207 because the condition on line 202 was always true

203 del env_vars[env_var] 

204 self._save_env_file(env_vars) 

205 

206 # Remove from tracked vars 

207 if env_var in self._tracked_vars: 207 ↛ 210line 207 didn't jump to line 210 because the condition on line 207 was always true

208 self._tracked_vars.remove(env_var) 

209 

210 return True 

211 except (OSError, ValueError): 

212 return False 

213 

214 def remove_all_user_env(self) -> bool: 

215 """ 

216 Remove all Ezpl user environment variables. 

217 

218 Returns: 

219 True if successful, False otherwise 

220 """ 

221 try: 

222 env_vars = self._load_env_file() 

223 ezpl_vars = {k: v for k, v in env_vars.items() if k.startswith("EZPL_")} 

224 

225 if not ezpl_vars: 225 ↛ 229line 225 didn't jump to line 229 because the condition on line 225 was always true

226 return True 

227 

228 # Remove all EZPL_ vars 

229 for key in list(ezpl_vars.keys()): 

230 del env_vars[key] 

231 

232 self._save_env_file(env_vars) 

233 self._tracked_vars = [] 

234 

235 return True 

236 except (OSError, ValueError): 

237 return False 

238 

239 def list_user_env(self) -> dict[str, str]: 

240 """ 

241 List all user environment variables managed by Ezpl. 

242 

243 Returns: 

244 Dictionary mapping environment variable names to values 

245 """ 

246 env_vars = self._load_env_file() 

247 return {k: v for k, v in env_vars.items() if k.startswith("EZPL_")}