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

1 import os

2 import warnings

3 from pathlib import Path

4 from typing import Optional

5

6# the path where the environment variables are going

7 DOTENV = Path(".env")

8 DOTENV.touch(exist_ok=True)

9

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

11

12

13 def 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

50 def 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

97 def 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