Coverage for src/edwh_restic_plugin/env.py: 16%

64 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-02-28 16:28 +0100

1import os 

2import warnings 

3from pathlib import Path 

4from typing import Optional 

5 

6# the path where the environment variables are going 

7DOTENV = Path(".env") 

8DOTENV.touch(exist_ok=True) 

9 

10_dotenv_settings: dict[Path, dict[str, str]] = {} 

11 

12 

13def read_dotenv(path: Optional[Path] = None) -> dict[str, str]: 

14 """Reads a .env file at the specified path and returns a dictionary of key - value pairs. 

15 

16 If the specified key is not found in the.env file, the function prompts the user to enter a value for the key, 

17 with a default value provided.The key-value pair is then appended to the.env file. 

18 

19 Args: 

20 path(Path): The path to the .env file. 

21 

22 Returns: 

23 dict: A dictionary containing the key - value pairs in the .env file.""" 

24 path = path or DOTENV 

25 

26 if existing := _dotenv_settings.get(path): 

27 # 'cache' 

28 return existing 

29 

30 items = {} 

31 with path.open(mode="r") as env_file: 

32 for line in env_file: 

33 # remove comments and redundant whitespace 

34 line = line.split("#", 1)[0].strip() 

35 if not line or "=" not in line: 

36 # just a comment, skip 

37 # or key without value? invalid, prevent crash: 

38 continue 

39 

40 # convert to tuples 

41 k, v = line.split("=", 1) 

42 

43 # clean the tuples and add to dict 

44 items[k.strip()] = v.strip() 

45 

46 _dotenv_settings[path] = items 

47 return items 

48 

49 

50def set_env_value(path: Path, target: str, value: str) -> None: 

51 """ 

52 update/set environment variables in the .env file, keeping comments intact 

53 

54 set_env_value(Path('.env'), 'SCHEMA_VERSION', schemaversion) 

55 

56 Args: 

57 path: pathlib.Path designating the .env file 

58 target: key to write, probably best to use UPPERCASE 

59 value: string value to write, or anything that converts to a string using str() 

60 """ 

61 with path.open(mode="r") as env_file: 

62 # open the .env file and read every line in the inlines 

63 inlines = env_file.read().split("\n") 

64 

65 outlines = [] # lines for output 

66 geschreven = False 

67 for line in inlines: 

68 if line.strip().startswith("#"): 

69 # ignore comments 

70 outlines.append(line) 

71 continue 

72 # remove redundant whitespace 

73 line = line.strip() 

74 if not line: 

75 # remove empty lines 

76 continue 

77 # convert to tuples 

78 key, oldvalue = line.split("=", 1) 

79 # clean the key and value 

80 key = key.strip() 

81 if key == target: 

82 # add the new tuple to the lines 

83 outlines.append(f"{key}={value}") 

84 geschreven = True 

85 else: 

86 # or leave it as it is 

87 outlines.append(line) 

88 if not geschreven: 

89 # if target in .env file 

90 outlines.append(f"{target.strip().upper()}={value.strip()}") 

91 with path.open(mode="w") as env_file: 

92 # write outlines to .env file 

93 env_file.write("\n".join(outlines)) 

94 env_file.write("\n") 

95 

96 

97def check_env( 

98 key: str, 

99 default: str | None, 

100 comment: str, 

101 prefix: str = None, 

102 suffix: str = None, 

103 postfix: str = None, 

104 path: Path = None, 

105): 

106 """ 

107 Test if key is in .env file path, appends prompted or default value if missing. 

108 """ 

109 path = path or DOTENV 

110 

111 if postfix: 

112 warnings.warn("`postfix` option passed. Please use `suffix` instead!", category=DeprecationWarning) 

113 

114 suffix = suffix or postfix 

115 

116 env = read_dotenv(path) 

117 if key in env: 

118 return env[key] 

119 

120 # get response value from prompt/input 

121 # if response_value is empty make value default else value is response_value 

122 value = input(f"Enter value for {key} ({comment})\n default=`{default}`: ").strip() or default or "" 

123 if value.startswith("~/") and Path(value).expanduser().exists(): 

124 value = str(Path(value).expanduser()) 

125 if prefix: 

126 value = prefix + value 

127 if suffix: 

128 value += suffix 

129 

130 with path.open(mode="r+") as env_file: 

131 env_file.seek(0, 2) 

132 # write key and value to .env file 

133 env_file.write(f"\n{key.upper()}={value}") 

134 

135 # update in memory too: 

136 os.environ[key] = env[key] = value 

137 return value