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-03 06:10 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-03 06:10 +0000
1from __future__ import annotations
3import os
4import sys
5from configparser import ConfigParser
6from pathlib import Path
8from .api import PlatformDirsABC
10if sys.platform == "win32":
12 def getuid() -> int:
13 raise RuntimeError("should only be used on Unix")
15else:
16 from os import getuid
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 """
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)
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)
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)
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)
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)
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)
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")
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)
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
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")
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")
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")
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")
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)
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)
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)
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)
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)
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)
194 return media_dir
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()
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()}")
207 if key not in parser["top"]:
208 return None
210 path = parser["top"][key].strip('"')
211 # Handle relative home paths
212 path = path.replace("$HOME", os.path.expanduser("~"))
213 return path
215 return None
218__all__ = [
219 "Unix",
220]