From 614fedf72c30c83de189b447b07d799363a167c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Tue, 29 Sep 2026 09:57:51 -0700 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor(api):=20share=20u?= =?UTF-8?q?se=5Fsite=20iteration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unix overrode all six _iter_*_dirs only to skip the user dir as root with use_site_for_root, while #604 moved the rest of the iteration into the base class. The base iterators now carry that skip behind _use_site, which returns False outside Unix, so the overrides go. Results do not change on any platform. --- src/platformdirs/api.py | 25 +++++++++++++++++++------ src/platformdirs/unix.py | 37 +------------------------------------ 2 files changed, 20 insertions(+), 42 deletions(-) diff --git a/src/platformdirs/api.py b/src/platformdirs/api.py index 632a6738..96782366 100644 --- a/src/platformdirs/api.py +++ b/src/platformdirs/api.py @@ -468,7 +468,8 @@ def iter_config_dirs(self) -> Iterator[str]: yield from _unique(self._iter_config_dirs()) def _iter_config_dirs(self) -> Iterator[str]: - yield self.user_config_dir + if not self._use_site: + yield self.user_config_dir yield from self._create_as_yielded(self._site_config_dirs) def iter_data_dirs(self) -> Iterator[str]: @@ -476,7 +477,8 @@ def iter_data_dirs(self) -> Iterator[str]: yield from _unique(self._iter_data_dirs()) def _iter_data_dirs(self) -> Iterator[str]: - yield self.user_data_dir + if not self._use_site: + yield self.user_data_dir yield from self._create_as_yielded(self._site_data_dirs) def iter_cache_dirs(self) -> Iterator[str]: @@ -484,7 +486,8 @@ def iter_cache_dirs(self) -> Iterator[str]: yield from _unique(self._iter_cache_dirs()) def _iter_cache_dirs(self) -> Iterator[str]: - yield self.user_cache_dir + if not self._use_site: + yield self.user_cache_dir yield from self._create_as_yielded(self._site_cache_dirs) def iter_state_dirs(self) -> Iterator[str]: @@ -492,7 +495,8 @@ def iter_state_dirs(self) -> Iterator[str]: yield from _unique(self._iter_state_dirs()) def _iter_state_dirs(self) -> Iterator[str]: - yield self.user_state_dir + if not self._use_site: + yield self.user_state_dir yield self.site_state_dir def iter_log_dirs(self) -> Iterator[str]: @@ -500,7 +504,8 @@ def iter_log_dirs(self) -> Iterator[str]: yield from _unique(self._iter_log_dirs()) def _iter_log_dirs(self) -> Iterator[str]: - yield self.user_log_dir + if not self._use_site: + yield self.user_log_dir yield self.site_log_dir def iter_runtime_dirs(self) -> Iterator[str]: @@ -509,7 +514,15 @@ def iter_runtime_dirs(self) -> Iterator[str]: def _iter_runtime_dirs(self) -> Iterator[str]: yield self.user_runtime_dir - yield self.site_runtime_dir + # Root's user runtime dir is already the site one; site_runtime_dir reads the invoking user's XDG_RUNTIME_DIR. + if not self._use_site: + yield self.site_runtime_dir + + @property + def _use_site(self) -> bool: + # Only Unix redirects root's user dirs to the site ones. The iterators then skip the user dir, since under + # multipath it is the joined site string that _unique cannot match against any single entry. + return False def iter_config_paths(self) -> Iterator[Path]: """:yield: all user and site configuration paths.""" diff --git a/src/platformdirs/unix.py b/src/platformdirs/unix.py index e7e78b2a..9df05d2c 100644 --- a/src/platformdirs/unix.py +++ b/src/platformdirs/unix.py @@ -10,14 +10,11 @@ from contextlib import suppress from pathlib import Path from tempfile import gettempdir -from typing import TYPE_CHECKING, Final, NoReturn +from typing import Final, NoReturn from ._xdg import XDGMixin, _expand_user, _xdg_dir from .api import PlatformDirsABC, RuntimeDirWarning -if TYPE_CHECKING: - from collections.abc import Iterator - if sys.platform == "win32": def getuid() -> NoReturn: @@ -216,38 +213,6 @@ def site_runtime_dir(self) -> str: path = "/run" return self._append_app_name_and_version(path, private=False) - def _iter_config_dirs(self) -> Iterator[str]: - # Under multipath the user dir is an os.pathsep-joined string that no single site entry matches, so the - # dedupe in iter_config_dirs cannot drop it. Skip it here instead. - if not self._use_site: - yield self.user_config_dir - yield from self._create_as_yielded(self._site_config_dirs) - - def _iter_data_dirs(self) -> Iterator[str]: - if not self._use_site: - yield self.user_data_dir - yield from self._create_as_yielded(self._site_data_dirs) - - def _iter_cache_dirs(self) -> Iterator[str]: - if not self._use_site: - yield self.user_cache_dir - yield self.site_cache_dir - - def _iter_state_dirs(self) -> Iterator[str]: - if not self._use_site: - yield self.user_state_dir - yield self.site_state_dir - - def _iter_log_dirs(self) -> Iterator[str]: - if not self._use_site: - yield self.user_log_dir - yield self.site_log_dir - - def _iter_runtime_dirs(self) -> Iterator[str]: - yield self.user_runtime_dir - if not self._use_site: - yield self.site_runtime_dir - class Unix(XDGMixin, _UnixDefaults): """On Unix/Linux, we follow the `XDG Basedir Spec `_.