Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/platformdirs/unix.py: 41%

113 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 07:11 +0000

1from __future__ import annotations 

2 

3import os 

4import sys 

5from configparser import ConfigParser 

6from pathlib import Path 

7 

8from .api import PlatformDirsABC 

9 

10if sys.platform == "win32": 

11 

12 def getuid() -> int: 

13 raise RuntimeError("should only be used on Unix") 

14 

15else: 

16 from os import getuid 

17 

18 

19class Unix(PlatformDirsABC): 

20 """ 

21 On Unix/Linux, we follow the 

22 `XDG Basedir Spec <https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html>`_. The spec allows 

23 overriding directories with environment variables. The examples show are the default values, alongside the name of 

24 the environment variable that overrides them. Makes use of the 

25 `appname <platformdirs.api.PlatformDirsABC.appname>`, 

26 `version <platformdirs.api.PlatformDirsABC.version>`, 

27 `multipath <platformdirs.api.PlatformDirsABC.multipath>`, 

28 `opinion <platformdirs.api.PlatformDirsABC.opinion>`, 

29 `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`. 

30 """ 

31 

32 @property 

33 def user_data_dir(self) -> str: 

34 """ 

35 :return: data directory tied to the user, e.g. ``~/.local/share/$appname/$version`` or 

36 ``$XDG_DATA_HOME/$appname/$version`` 

37 """ 

38 path = os.environ.get("XDG_DATA_HOME", "") 

39 if not path.strip(): 

40 path = os.path.expanduser("~/.local/share") 

41 return self._append_app_name_and_version(path) 

42 

43 @property 

44 def site_data_dir(self) -> str: 

45 """ 

46 :return: data directories shared by users (if `multipath <platformdirs.api.PlatformDirsABC.multipath>` is 

47 enabled and ``XDG_DATA_DIR`` is set and a multi path the response is also a multi path separated by the OS 

48 path separator), e.g. ``/usr/local/share/$appname/$version`` or ``/usr/share/$appname/$version`` 

49 """ 

50 # XDG default for $XDG_DATA_DIRS; only first, if multipath is False 

51 path = os.environ.get("XDG_DATA_DIRS", "") 

52 if not path.strip(): 

53 path = f"/usr/local/share{os.pathsep}/usr/share" 

54 return self._with_multi_path(path) 

55 

56 def _with_multi_path(self, path: str) -> str: 

57 path_list = path.split(os.pathsep) 

58 if not self.multipath: 

59 path_list = path_list[0:1] 

60 path_list = [self._append_app_name_and_version(os.path.expanduser(p)) for p in path_list] 

61 return os.pathsep.join(path_list) 

62 

63 @property 

64 def user_config_dir(self) -> str: 

65 """ 

66 :return: config directory tied to the user, e.g. ``~/.config/$appname/$version`` or 

67 ``$XDG_CONFIG_HOME/$appname/$version`` 

68 """ 

69 path = os.environ.get("XDG_CONFIG_HOME", "") 

70 if not path.strip(): 

71 path = os.path.expanduser("~/.config") 

72 return self._append_app_name_and_version(path) 

73 

74 @property 

75 def site_config_dir(self) -> str: 

76 """ 

77 :return: config directories shared by users (if `multipath <platformdirs.api.PlatformDirsABC.multipath>` 

78 is enabled and ``XDG_DATA_DIR`` is set and a multi path the response is also a multi path separated by the OS 

79 path separator), e.g. ``/etc/xdg/$appname/$version`` 

80 """ 

81 # XDG default for $XDG_CONFIG_DIRS only first, if multipath is False 

82 path = os.environ.get("XDG_CONFIG_DIRS", "") 

83 if not path.strip(): 

84 path = "/etc/xdg" 

85 return self._with_multi_path(path) 

86 

87 @property 

88 def user_cache_dir(self) -> str: 

89 """ 

90 :return: cache directory tied to the user, e.g. ``~/.cache/$appname/$version`` or 

91 ``~/$XDG_CACHE_HOME/$appname/$version`` 

92 """ 

93 path = os.environ.get("XDG_CACHE_HOME", "") 

94 if not path.strip(): 

95 path = os.path.expanduser("~/.cache") 

96 return self._append_app_name_and_version(path) 

97 

98 @property 

99 def site_cache_dir(self) -> str: 

100 """ 

101 :return: cache directory shared by users, e.g. ``/var/tmp/$appname/$version`` 

102 """ 

103 return self._append_app_name_and_version("/var/tmp") 

104 

105 @property 

106 def user_state_dir(self) -> str: 

107 """ 

108 :return: state directory tied to the user, e.g. ``~/.local/state/$appname/$version`` or 

109 ``$XDG_STATE_HOME/$appname/$version`` 

110 """ 

111 path = os.environ.get("XDG_STATE_HOME", "") 

112 if not path.strip(): 

113 path = os.path.expanduser("~/.local/state") 

114 return self._append_app_name_and_version(path) 

115 

116 @property 

117 def user_log_dir(self) -> str: 

118 """ 

119 :return: log directory tied to the user, same as `user_state_dir` if not opinionated else ``log`` in it 

120 """ 

121 path = self.user_state_dir 

122 if self.opinion: 

123 path = os.path.join(path, "log") 

124 return path 

125 

126 @property 

127 def user_documents_dir(self) -> str: 

128 """ 

129 :return: documents directory tied to the user, e.g. ``~/Documents`` 

130 """ 

131 return _get_user_media_dir("XDG_DOCUMENTS_DIR", "~/Documents") 

132 

133 @property 

134 def user_pictures_dir(self) -> str: 

135 """ 

136 :return: pictures directory tied to the user, e.g. ``~/Pictures`` 

137 """ 

138 return _get_user_media_dir("XDG_PICTURES_DIR", "~/Pictures") 

139 

140 @property 

141 def user_videos_dir(self) -> str: 

142 """ 

143 :return: videos directory tied to the user, e.g. ``~/Videos`` 

144 """ 

145 return _get_user_media_dir("XDG_VIDEOS_DIR", "~/Videos") 

146 

147 @property 

148 def user_music_dir(self) -> str: 

149 """ 

150 :return: music directory tied to the user, e.g. ``~/Music`` 

151 """ 

152 return _get_user_media_dir("XDG_MUSIC_DIR", "~/Music") 

153 

154 @property 

155 def user_runtime_dir(self) -> str: 

156 """ 

157 :return: runtime directory tied to the user, e.g. ``/run/user/$(id -u)/$appname/$version`` or 

158 ``$XDG_RUNTIME_DIR/$appname/$version`` 

159 """ 

160 path = os.environ.get("XDG_RUNTIME_DIR", "") 

161 if not path.strip(): 

162 path = f"/run/user/{getuid()}" 

163 return self._append_app_name_and_version(path) 

164 

165 @property 

166 def site_data_path(self) -> Path: 

167 """:return: data path shared by users. Only return first item, even if ``multipath`` is set to ``True``""" 

168 return self._first_item_as_path_if_multipath(self.site_data_dir) 

169 

170 @property 

171 def site_config_path(self) -> Path: 

172 """:return: config path shared by the users. Only return first item, even if ``multipath`` is set to ``True``""" 

173 return self._first_item_as_path_if_multipath(self.site_config_dir) 

174 

175 @property 

176 def site_cache_path(self) -> Path: 

177 """:return: cache path shared by users. Only return first item, even if ``multipath`` is set to ``True``""" 

178 return self._first_item_as_path_if_multipath(self.site_cache_dir) 

179 

180 def _first_item_as_path_if_multipath(self, directory: str) -> Path: 

181 if self.multipath: 

182 # If multipath is True, the first path is returned. 

183 directory = directory.split(os.pathsep)[0] 

184 return Path(directory) 

185 

186 

187def _get_user_media_dir(env_var: str, fallback_tilde_path: str) -> str: 

188 media_dir = _get_user_dirs_folder(env_var) 

189 if media_dir is None: 

190 media_dir = os.environ.get(env_var, "").strip() 

191 if not media_dir: 

192 media_dir = os.path.expanduser(fallback_tilde_path) 

193 

194 return media_dir 

195 

196 

197def _get_user_dirs_folder(key: str) -> str | None: 

198 """Return directory from user-dirs.dirs config file. See https://freedesktop.org/wiki/Software/xdg-user-dirs/""" 

199 user_dirs_config_path = os.path.join(Unix().user_config_dir, "user-dirs.dirs") 

200 if os.path.exists(user_dirs_config_path): 

201 parser = ConfigParser() 

202 

203 with open(user_dirs_config_path) as stream: 

204 # Add fake section header, so ConfigParser doesn't complain 

205 parser.read_string(f"[top]\n{stream.read()}") 

206 

207 if key not in parser["top"]: 

208 return None 

209 

210 path = parser["top"][key].strip('"') 

211 # Handle relative home paths 

212 path = path.replace("$HOME", os.path.expanduser("~")) 

213 return path 

214 

215 return None 

216 

217 

218__all__ = [ 

219 "Unix", 

220]