Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/platformdirs/unix.py: 56%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""Unix."""
3from __future__ import annotations
5import os
6import sys
7from configparser import ConfigParser
8from functools import cached_property
9from pathlib import Path
10from tempfile import gettempdir
11from typing import TYPE_CHECKING, NoReturn
13from ._xdg import XDGMixin
14from .api import PlatformDirsABC
16if TYPE_CHECKING:
17 from collections.abc import Iterator
19if sys.platform == "win32":
21 def getuid() -> NoReturn:
22 msg = "should only be used on Unix"
23 raise RuntimeError(msg)
25else:
26 from os import getuid
29class _UnixDefaults(PlatformDirsABC): # noqa: PLR0904
30 """Default directories for Unix/Linux without XDG environment variable overrides.
32 The XDG env var handling is in :class:`~platformdirs._xdg.XDGMixin`.
34 """
36 @cached_property
37 def _use_site(self) -> bool:
38 return self.use_site_for_root and getuid() == 0
40 @property
41 def user_data_dir(self) -> str:
42 """:returns: data directory tied to the user, e.g. ``~/.local/share/$appname/$version`` or ``$XDG_DATA_HOME/$appname/$version``"""
43 return self._append_app_name_and_version(os.path.expanduser("~/.local/share")) # noqa: PTH111
45 @property
46 def _site_data_dirs(self) -> list[str]:
47 return [self._append_app_name_and_version("/usr/local/share"), self._append_app_name_and_version("/usr/share")]
49 @property
50 def user_config_dir(self) -> str:
51 """:returns: config directory tied to the user, e.g. ``~/.config/$appname/$version`` or ``$XDG_CONFIG_HOME/$appname/$version``"""
52 return self._append_app_name_and_version(os.path.expanduser("~/.config")) # noqa: PTH111
54 @property
55 def _site_config_dirs(self) -> list[str]:
56 return [self._append_app_name_and_version("/etc/xdg")]
58 @property
59 def user_cache_dir(self) -> str:
60 """:returns: cache directory tied to the user, e.g. ``~/.cache/$appname/$version`` or ``$XDG_CACHE_HOME/$appname/$version``"""
61 return self._append_app_name_and_version(os.path.expanduser("~/.cache")) # noqa: PTH111
63 @property
64 def site_cache_dir(self) -> str:
65 """:returns: cache directory shared by users, e.g. ``/var/cache/$appname/$version``"""
66 return self._append_app_name_and_version("/var/cache")
68 @property
69 def user_state_dir(self) -> str:
70 """:returns: state directory tied to the user, e.g. ``~/.local/state/$appname/$version`` or ``$XDG_STATE_HOME/$appname/$version``"""
71 return self._append_app_name_and_version(os.path.expanduser("~/.local/state")) # noqa: PTH111
73 @property
74 def site_state_dir(self) -> str:
75 """:returns: state directory shared by users, e.g. ``/var/lib/$appname/$version``"""
76 return self._append_app_name_and_version("/var/lib")
78 @property
79 def user_log_dir(self) -> str:
80 """:returns: log directory tied to the user, same as `user_state_dir` if not opinionated else ``log`` in it"""
81 path = self.user_state_dir
82 if self.opinion:
83 path = os.path.join(path, "log") # noqa: PTH118
84 self._optionally_create_directory(path)
85 return path
87 @property
88 def site_log_dir(self) -> str:
89 """:returns: log directory shared by users, e.g. ``/var/log/$appname/$version``
91 Unlike `user_log_dir`, ``opinion`` has no effect since ``/var/log`` is inherently a log directory.
93 """
94 return self._append_app_name_and_version("/var/log")
96 @property
97 def user_documents_dir(self) -> str:
98 """:returns: documents directory tied to the user, e.g. ``~/Documents``"""
99 return _get_user_media_dir("XDG_DOCUMENTS_DIR", "~/Documents")
101 @property
102 def user_downloads_dir(self) -> str:
103 """:returns: downloads directory tied to the user, e.g. ``~/Downloads``"""
104 return _get_user_media_dir("XDG_DOWNLOAD_DIR", "~/Downloads")
106 @property
107 def user_pictures_dir(self) -> str:
108 """:returns: pictures directory tied to the user, e.g. ``~/Pictures``"""
109 return _get_user_media_dir("XDG_PICTURES_DIR", "~/Pictures")
111 @property
112 def user_videos_dir(self) -> str:
113 """:returns: videos directory tied to the user, e.g. ``~/Videos``"""
114 return _get_user_media_dir("XDG_VIDEOS_DIR", "~/Videos")
116 @property
117 def user_music_dir(self) -> str:
118 """:returns: music directory tied to the user, e.g. ``~/Music``"""
119 return _get_user_media_dir("XDG_MUSIC_DIR", "~/Music")
121 @property
122 def user_desktop_dir(self) -> str:
123 """:returns: desktop directory tied to the user, e.g. ``~/Desktop``"""
124 return _get_user_media_dir("XDG_DESKTOP_DIR", "~/Desktop")
126 @property
127 def user_projects_dir(self) -> str:
128 """:returns: projects directory tied to the user, e.g. ``~/Projects``"""
129 return _get_user_media_dir("XDG_PROJECTS_DIR", "~/Projects")
131 @property
132 def user_publicshare_dir(self) -> str:
133 """:returns: public share directory tied to the user, e.g. ``~/Public``"""
134 return _get_user_media_dir("XDG_PUBLICSHARE_DIR", "~/Public")
136 @property
137 def user_templates_dir(self) -> str:
138 """:returns: templates directory tied to the user, e.g. ``~/Templates``"""
139 return _get_user_media_dir("XDG_TEMPLATES_DIR", "~/Templates")
141 @property
142 def user_fonts_dir(self) -> str:
143 """:returns: fonts directory tied to the user, e.g. ``~/.local/share/fonts``"""
144 return f"{os.path.expanduser('~/.local/share')}/fonts" # noqa: PTH111 # API returns str, not Path
146 @property
147 def user_preference_dir(self) -> str:
148 """:returns: preference directory tied to the user, same as ``user_config_dir``"""
149 return self.user_config_dir
151 @property
152 def user_bin_dir(self) -> str:
153 """:returns: bin directory tied to the user, e.g. ``~/.local/bin``"""
154 return os.path.expanduser("~/.local/bin") # noqa: PTH111
156 @property
157 def site_bin_dir(self) -> str:
158 """:returns: bin directory shared by users, e.g. ``/usr/local/bin``"""
159 return "/usr/local/bin"
161 @property
162 def user_applications_dir(self) -> str:
163 """:returns: applications directory tied to the user, e.g. ``~/.local/share/applications``"""
164 return os.path.join(os.path.expanduser("~/.local/share"), "applications") # noqa: PTH111, PTH118
166 @property
167 def _site_applications_dirs(self) -> list[str]:
168 return [os.path.join(p, "applications") for p in ["/usr/local/share", "/usr/share"]] # noqa: PTH118
170 @property
171 def site_applications_dir(self) -> str:
172 """:returns: applications directory shared by users, e.g. ``/usr/share/applications``"""
173 dirs = self._site_applications_dirs
174 return os.pathsep.join(dirs) if self.multipath else dirs[0]
176 @property
177 def user_runtime_dir(self) -> str:
178 """:returns: runtime directory tied to the user, e.g. ``$XDG_RUNTIME_DIR/$appname/$version``.
180 If ``$XDG_RUNTIME_DIR`` is unset, tries the platform default (``/tmp/run/user/$(id -u)`` on OpenBSD, ``/var/run/user/$(id -u)`` on FreeBSD/NetBSD, ``/run/user/$(id -u)`` otherwise). If the default is not writable, falls back to a temporary directory.
182 """
183 if sys.platform.startswith("openbsd"):
184 path = f"/tmp/run/user/{getuid()}" # noqa: S108
185 elif sys.platform.startswith(("freebsd", "netbsd")):
186 path = f"/var/run/user/{getuid()}"
187 else:
188 path = f"/run/user/{getuid()}"
189 if not os.access(path, os.W_OK):
190 path = f"{gettempdir()}/runtime-{getuid()}"
191 return self._append_app_name_and_version(path)
193 @property
194 def site_runtime_dir(self) -> str:
195 """:returns: runtime directory shared by users, e.g. ``/run/$appname/$version`` or ``$XDG_RUNTIME_DIR/$appname/$version``.
197 Note that this behaves almost exactly like `user_runtime_dir` if ``$XDG_RUNTIME_DIR`` is set, but will fall back to paths associated to the root user instead of a regular logged-in user if it's not set.
199 If you wish to ensure that a logged-in root user path is returned e.g. ``/run/user/0``, use `user_runtime_dir` instead.
201 For FreeBSD/OpenBSD/NetBSD, it would return ``/var/run/$appname/$version`` if ``$XDG_RUNTIME_DIR`` is not set.
203 """
204 if sys.platform.startswith(("freebsd", "openbsd", "netbsd")):
205 path = "/var/run"
206 else:
207 path = "/run"
208 return self._append_app_name_and_version(path)
210 @property
211 def site_data_path(self) -> Path:
212 """:returns: data path shared by users. Only return the first item, even if ``multipath`` is set to ``True``"""
213 return self._first_item_as_path_if_multipath(self.site_data_dir)
215 @property
216 def site_config_path(self) -> Path:
217 """:returns: config path shared by users, returns the first item, even if ``multipath`` is set to ``True``"""
218 return self._first_item_as_path_if_multipath(self.site_config_dir)
220 @property
221 def site_cache_path(self) -> Path:
222 """:returns: cache path shared by users. Only return the first item, even if ``multipath`` is set to ``True``"""
223 return self._first_item_as_path_if_multipath(self.site_cache_dir)
225 def iter_config_dirs(self) -> Iterator[str]:
226 """:yield: all user and site configuration directories."""
227 if not self._use_site:
228 yield self.user_config_dir
229 yield from self._site_config_dirs
231 def iter_data_dirs(self) -> Iterator[str]:
232 """:yield: all user and site data directories."""
233 if not self._use_site:
234 yield self.user_data_dir
235 yield from self._site_data_dirs
238class Unix(XDGMixin, _UnixDefaults):
239 """On Unix/Linux, we follow the `XDG Basedir Spec <https://specifications.freedesktop.org/basedir/latest/>`_.
241 The spec allows overriding directories with environment variables. The examples shown are the default values,
242 alongside the name of the environment variable that overrides them. Makes use of the `appname
243 <platformdirs.api.PlatformDirsABC.appname>`, `version <platformdirs.api.PlatformDirsABC.version>`, `multipath
244 <platformdirs.api.PlatformDirsABC.multipath>`, `opinion <platformdirs.api.PlatformDirsABC.opinion>`, `ensure_exists
245 <platformdirs.api.PlatformDirsABC.ensure_exists>`.
247 """
249 @property
250 def user_data_dir(self) -> str:
251 """:returns: data directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
252 return self.site_data_dir if self._use_site else super().user_data_dir
254 @property
255 def user_config_dir(self) -> str:
256 """:returns: config directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
257 return self.site_config_dir if self._use_site else super().user_config_dir
259 @property
260 def user_cache_dir(self) -> str:
261 """:returns: cache directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
262 return self.site_cache_dir if self._use_site else super().user_cache_dir
264 @property
265 def user_state_dir(self) -> str:
266 """:returns: state directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
267 return self.site_state_dir if self._use_site else super().user_state_dir
269 @property
270 def user_log_dir(self) -> str:
271 """:returns: log directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
272 return self.site_log_dir if self._use_site else super().user_log_dir
274 @property
275 def user_applications_dir(self) -> str:
276 """:returns: applications directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
277 return self.site_applications_dir if self._use_site else super().user_applications_dir
279 @property
280 def user_runtime_dir(self) -> str:
281 """:returns: runtime directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
282 return self.site_runtime_dir if self._use_site else super().user_runtime_dir
284 @property
285 def user_bin_dir(self) -> str:
286 """:returns: bin directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
287 return self.site_bin_dir if self._use_site else super().user_bin_dir
290def _get_user_media_dir(env_var: str, fallback_tilde_path: str) -> str:
291 if media_dir := _get_user_dirs_folder(env_var):
292 return media_dir
293 return os.path.expanduser(fallback_tilde_path) # noqa: PTH111
296def _get_user_dirs_folder(key: str) -> str | None:
297 """Return directory from user-dirs.dirs config file.
299 See https://freedesktop.org/wiki/Software/xdg-user-dirs/.
301 """
302 config_home = os.environ.get("XDG_CONFIG_HOME", "").strip() or os.path.expanduser("~/.config") # noqa: PTH111
303 user_dirs_config_path = Path(config_home) / "user-dirs.dirs"
304 if user_dirs_config_path.exists():
305 parser = ConfigParser()
307 with user_dirs_config_path.open() as stream:
308 parser.read_string(f"[top]\n{stream.read()}")
310 if key not in parser["top"]:
311 return None
313 path = parser["top"][key].strip('"')
314 return path.replace("$HOME", os.path.expanduser("~")) # noqa: PTH111
316 return None
319__all__ = [
320 "Unix",
321]