Add convenience methods to `PlatformDirsAPI` that allow iterating over both user and site dirs/paths. (#258)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Bernát Gábor <gaborjbernat@gmail.com>
diff --git a/CHANGES.rst b/CHANGES.rst
index 1f3d70e..3fa20cc 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,6 +1,10 @@
platformdirs Changelog
======================
+platformdirs 4.1.0 (2024-01-XX)
+-------------------------------
+- Add convenience methods ``iter_{config,cache,data,runtime}_{dirs,paths}``.
+
platformdirs 4.0.0 (2023-11-10)
-------------------------------
- UNIX: revert site_cache_dir to use ``/var/cache`` instead of ``/var/tmp``
diff --git a/src/platformdirs/api.py b/src/platformdirs/api.py
index 31a2bd8..031a38a 100644
--- a/src/platformdirs/api.py
+++ b/src/platformdirs/api.py
@@ -8,7 +8,7 @@
from typing import TYPE_CHECKING
if TYPE_CHECKING:
- from typing import Literal
+ from typing import Iterator, Literal
class PlatformDirsABC(ABC):
@@ -237,3 +237,43 @@
def site_runtime_path(self) -> Path:
""":return: runtime path shared by users"""
return Path(self.site_runtime_dir)
+
+ def iter_config_dirs(self) -> Iterator[str]:
+ """:yield: all user and site configuration directories."""
+ yield self.user_config_dir
+ yield self.site_config_dir
+
+ def iter_data_dirs(self) -> Iterator[str]:
+ """:yield: all user and site data directories."""
+ yield self.user_data_dir
+ yield self.site_data_dir
+
+ def iter_cache_dirs(self) -> Iterator[str]:
+ """:yield: all user and site cache directories."""
+ yield self.user_cache_dir
+ yield self.site_cache_dir
+
+ def iter_runtime_dirs(self) -> Iterator[str]:
+ """:yield: all user and site runtime directories."""
+ yield self.user_runtime_dir
+ yield self.site_runtime_dir
+
+ def iter_config_paths(self) -> Iterator[Path]:
+ """:yield: all user and site configuration paths."""
+ for path in self.iter_config_dirs():
+ yield Path(path)
+
+ def iter_data_paths(self) -> Iterator[Path]:
+ """:yield: all user and site data paths."""
+ for path in self.iter_data_dirs():
+ yield Path(path)
+
+ def iter_cache_paths(self) -> Iterator[Path]:
+ """:yield: all user and site cache paths."""
+ for path in self.iter_cache_dirs():
+ yield Path(path)
+
+ def iter_runtime_paths(self) -> Iterator[Path]:
+ """:yield: all user and site runtime paths."""
+ for path in self.iter_runtime_dirs():
+ yield Path(path)
diff --git a/src/platformdirs/unix.py b/src/platformdirs/unix.py
index f23e412..ca4728e 100644
--- a/src/platformdirs/unix.py
+++ b/src/platformdirs/unix.py
@@ -6,6 +6,7 @@
import sys
from configparser import ConfigParser
from pathlib import Path
+from typing import Iterator
from .api import PlatformDirsABC
@@ -44,6 +45,13 @@
return self._append_app_name_and_version(path)
@property
+ def _site_data_dirs(self) -> list[str]:
+ path = os.environ.get("XDG_DATA_DIRS", "")
+ if not path.strip():
+ path = f"/usr/local/share{os.pathsep}/usr/share"
+ return [self._append_app_name_and_version(p) for p in path.split(os.pathsep)]
+
+ @property
def site_data_dir(self) -> str:
"""
:return: data directories shared by users (if `multipath <platformdirs.api.PlatformDirsABC.multipath>` is
@@ -51,17 +59,10 @@
OS path separator), e.g. ``/usr/local/share/$appname/$version`` or ``/usr/share/$appname/$version``
"""
# XDG default for $XDG_DATA_DIRS; only first, if multipath is False
- path = os.environ.get("XDG_DATA_DIRS", "")
- if not path.strip():
- path = f"/usr/local/share{os.pathsep}/usr/share"
- return self._with_multi_path(path)
-
- def _with_multi_path(self, path: str) -> str:
- path_list = path.split(os.pathsep)
+ dirs = self._site_data_dirs
if not self.multipath:
- path_list = path_list[0:1]
- path_list = [self._append_app_name_and_version(os.path.expanduser(p)) for p in path_list] # noqa: PTH111
- return os.pathsep.join(path_list)
+ return dirs[0]
+ return os.pathsep.join(dirs)
@property
def user_config_dir(self) -> str:
@@ -75,6 +76,13 @@
return self._append_app_name_and_version(path)
@property
+ def _site_config_dirs(self) -> list[str]:
+ path = os.environ.get("XDG_CONFIG_DIRS", "")
+ if not path.strip():
+ path = "/etc/xdg"
+ return [self._append_app_name_and_version(p) for p in path.split(os.pathsep)]
+
+ @property
def site_config_dir(self) -> str:
"""
:return: config directories shared by users (if `multipath <platformdirs.api.PlatformDirsABC.multipath>`
@@ -82,10 +90,10 @@
the OS path separator), e.g. ``/etc/xdg/$appname/$version``
"""
# XDG default for $XDG_CONFIG_DIRS only first, if multipath is False
- path = os.environ.get("XDG_CONFIG_DIRS", "")
- if not path.strip():
- path = "/etc/xdg"
- return self._with_multi_path(path)
+ dirs = self._site_config_dirs
+ if not self.multipath:
+ return dirs[0]
+ return os.pathsep.join(dirs)
@property
def user_cache_dir(self) -> str:
@@ -216,6 +224,16 @@
directory = directory.split(os.pathsep)[0]
return Path(directory)
+ def iter_config_dirs(self) -> Iterator[str]:
+ """:yield: all user and site configuration directories."""
+ yield self.user_config_dir
+ yield from self._site_config_dirs
+
+ def iter_data_dirs(self) -> Iterator[str]:
+ """:yield: all user and site data directories."""
+ yield self.user_data_dir
+ yield from self._site_data_dirs
+
def _get_user_media_dir(env_var: str, fallback_tilde_path: str) -> str:
media_dir = _get_user_dirs_folder(env_var)