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

119 statements  

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

1"""Unix.""" 

2from __future__ import annotations 

3 

4import os 

5import sys 

6from configparser import ConfigParser 

7from pathlib import Path 

8 

9from .api import PlatformDirsABC 

10 

11if sys.platform == "win32": 

12 

13 def getuid() -> int: 

14 msg = "should only be used on Unix" 

15 raise RuntimeError(msg) 

16 

17else: 

18 from os import getuid 

19 

20 

21class Unix(PlatformDirsABC): 

22 """ 

23 On Unix/Linux, we follow the 

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

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

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

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

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

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

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

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

32 """ 

33 

34 @property 

35 def user_data_dir(self) -> str: 

36 """ 

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

38 ``$XDG_DATA_HOME/$appname/$version`` 

39 """ 

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

41 if not path.strip(): 

42 path = os.path.expanduser("~/.local/share") # noqa: PTH111 

43 return self._append_app_name_and_version(path) 

44 

45 @property 

46 def site_data_dir(self) -> str: 

47 """ 

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

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

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

51 """ 

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

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

54 if not path.strip(): 

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

56 return self._with_multi_path(path) 

57 

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

59 path_list = path.split(os.pathsep) 

60 if not self.multipath: 

61 path_list = path_list[0:1] 

62 path_list = [self._append_app_name_and_version(os.path.expanduser(p)) for p in path_list] # noqa: PTH111 

63 return os.pathsep.join(path_list) 

64 

65 @property 

66 def user_config_dir(self) -> str: 

67 """ 

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

69 ``$XDG_CONFIG_HOME/$appname/$version`` 

70 """ 

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

72 if not path.strip(): 

73 path = os.path.expanduser("~/.config") # noqa: PTH111 

74 return self._append_app_name_and_version(path) 

75 

76 @property 

77 def site_config_dir(self) -> str: 

78 """ 

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

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

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

82 """ 

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

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

85 if not path.strip(): 

86 path = "/etc/xdg" 

87 return self._with_multi_path(path) 

88 

89 @property 

90 def user_cache_dir(self) -> str: 

91 """ 

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

93 ``~/$XDG_CACHE_HOME/$appname/$version`` 

94 """ 

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

96 if not path.strip(): 

97 path = os.path.expanduser("~/.cache") # noqa: PTH111 

98 return self._append_app_name_and_version(path) 

99 

100 @property 

101 def site_cache_dir(self) -> str: 

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

103 return self._append_app_name_and_version("/var/tmp") # noqa: S108 

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") # noqa: PTH111 

114 return self._append_app_name_and_version(path) 

115 

116 @property 

117 def user_log_dir(self) -> str: 

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

119 path = self.user_state_dir 

120 if self.opinion: 

121 path = os.path.join(path, "log") # noqa: PTH118 

122 return path 

123 

124 @property 

125 def user_documents_dir(self) -> str: 

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

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

128 

129 @property 

130 def user_downloads_dir(self) -> str: 

131 """:return: downloads directory tied to the user, e.g. ``~/Downloads``""" 

132 return _get_user_media_dir("XDG_DOWNLOAD_DIR", "~/Downloads") 

133 

134 @property 

135 def user_pictures_dir(self) -> str: 

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

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

138 

139 @property 

140 def user_videos_dir(self) -> str: 

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

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

143 

144 @property 

145 def user_music_dir(self) -> str: 

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

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

148 

149 @property 

150 def user_runtime_dir(self) -> str: 

151 """ 

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

153 ``$XDG_RUNTIME_DIR/$appname/$version``. 

154 

155 For FreeBSD/OpenBSD/NetBSD, it would return ``/var/run/user/$(id -u)/$appname/$version`` if 

156 ``$XDG_RUNTIME_DIR`` is not set. 

157 """ 

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

159 if not path.strip(): 

160 if sys.platform.startswith(("freebsd", "openbsd", "netbsd")): 

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

162 else: 

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

164 return self._append_app_name_and_version(path) 

165 

166 @property 

167 def site_data_path(self) -> Path: 

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

169 return self._first_item_as_path_if_multipath(self.site_data_dir) 

170 

171 @property 

172 def site_config_path(self) -> Path: 

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

174 return self._first_item_as_path_if_multipath(self.site_config_dir) 

175 

176 @property 

177 def site_cache_path(self) -> Path: 

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

179 return self._first_item_as_path_if_multipath(self.site_cache_dir) 

180 

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

182 if self.multipath: 

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

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

185 return Path(directory) 

186 

187 

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

189 media_dir = _get_user_dirs_folder(env_var) 

190 if media_dir is None: 

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

192 if not media_dir: 

193 media_dir = os.path.expanduser(fallback_tilde_path) # noqa: PTH111 

194 

195 return media_dir 

196 

197 

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

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

200 user_dirs_config_path = Path(Unix().user_config_dir) / "user-dirs.dirs" 

201 if user_dirs_config_path.exists(): 

202 parser = ConfigParser() 

203 

204 with user_dirs_config_path.open() as stream: 

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

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

207 

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

209 return None 

210 

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

212 # Handle relative home paths 

213 path = path.replace("$HOME", os.path.expanduser("~")) # noqa: PTH111 

214 return path 

215 

216 return None 

217 

218 

219__all__ = [ 

220 "Unix", 

221]