From ed4829d4d7da9d22e83717ef12a88c54a598324e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Thu, 12 Feb 2026 07:03:24 -0800 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=93=9D=20docs:=20fix=20cross-referenc?= =?UTF-8?q?es=20and=20improve=20docstrings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Several convenience functions in __init__.py had wrong Sphinx cross-references pointing to `roaming` instead of `multipath` or `opinion`. The _MacOSDefaults and _UnixDefaults classes referenced a non-existent `platformdirs.xdg` module instead of `platformdirs._xdg`. Also fixes grammar issues (appname, opinion, user_documents_path), clarifies multipath scope, and adds missing docstrings for _pick_get_win_folder and the Android class. --- src/platformdirs/__init__.py | 21 ++++++++++++--------- src/platformdirs/android.py | 8 ++++++-- src/platformdirs/api.py | 26 +++++++++++++++++++++----- src/platformdirs/macos.py | 6 +++--- src/platformdirs/unix.py | 4 ++-- src/platformdirs/windows.py | 1 + 6 files changed, 45 insertions(+), 21 deletions(-) diff --git a/src/platformdirs/__init__.py b/src/platformdirs/__init__.py index e323d885..7896bf67 100644 --- a/src/platformdirs/__init__.py +++ b/src/platformdirs/__init__.py @@ -1,6 +1,9 @@ """ Utilities for determining application-specific dirs. +Provides convenience functions (e.g. :func:`user_data_dir`, :func:`user_config_path`), a :data:`PlatformDirs` class +that auto-detects the current platform, and the :class:`~platformdirs.api.PlatformDirsABC` base class. + See for details and usage. """ @@ -85,7 +88,7 @@ def site_data_dir( :param appname: See `appname `. :param appauthor: See `appauthor `. :param version: See `version `. - :param multipath: See `roaming `. + :param multipath: See `multipath `. :param ensure_exists: See `ensure_exists `. :returns: data directory shared by users """ @@ -133,7 +136,7 @@ def site_config_dir( :param appname: See `appname `. :param appauthor: See `appauthor `. :param version: See `version `. - :param multipath: See `roaming `. + :param multipath: See `multipath `. :param ensure_exists: See `ensure_exists `. :returns: config directory shared by users """ @@ -157,7 +160,7 @@ def user_cache_dir( :param appname: See `appname `. :param appauthor: See `appauthor `. :param version: See `version `. - :param opinion: See `roaming `. + :param opinion: See `opinion `. :param ensure_exists: See `ensure_exists `. :returns: cache directory tied to the user """ @@ -229,7 +232,7 @@ def user_log_dir( :param appname: See `appname `. :param appauthor: See `appauthor `. :param version: See `version `. - :param opinion: See `roaming `. + :param opinion: See `opinion `. :param ensure_exists: See `ensure_exists `. :returns: log directory tied to the user """ @@ -403,7 +406,7 @@ def site_config_path( :param appname: See `appname `. :param appauthor: See `appauthor `. :param version: See `version `. - :param multipath: See `roaming `. + :param multipath: See `multipath `. :param ensure_exists: See `ensure_exists `. :returns: config path shared by users """ @@ -429,7 +432,7 @@ def site_cache_path( :param version: See `version `. :param opinion: See `opinion `. :param ensure_exists: See `ensure_exists `. - :returns: cache directory shared by users + :returns: cache path shared by users """ return PlatformDirs( appname=appname, @@ -451,7 +454,7 @@ def user_cache_path( :param appname: See `appname `. :param appauthor: See `appauthor `. :param version: See `version `. - :param opinion: See `roaming `. + :param opinion: See `opinion `. :param ensure_exists: See `ensure_exists `. :returns: cache path tied to the user """ @@ -499,7 +502,7 @@ def user_log_path( :param appname: See `appname `. :param appauthor: See `appauthor `. :param version: See `version `. - :param opinion: See `roaming `. + :param opinion: See `opinion `. :param ensure_exists: See `ensure_exists `. :returns: log path tied to the user """ @@ -513,7 +516,7 @@ def user_log_path( def user_documents_path() -> Path: - """:returns: documents a path tied to the user""" + """:returns: documents path tied to the user""" return PlatformDirs().user_documents_path diff --git a/src/platformdirs/android.py b/src/platformdirs/android.py index aff790f8..dec1e5eb 100644 --- a/src/platformdirs/android.py +++ b/src/platformdirs/android.py @@ -13,10 +13,14 @@ class Android(PlatformDirsABC): """ - Follows the guidance `from here `_. + Platform directories for Android. + + Follows the guidance `from here `_. Directories are typically located + under the app's private storage (``/data/user///``). Makes use of the `appname `, `version - `, `ensure_exists `. + `, `opinion `, + `ensure_exists `. """ diff --git a/src/platformdirs/api.py b/src/platformdirs/api.py index 7647e60c..1e038d8b 100644 --- a/src/platformdirs/api.py +++ b/src/platformdirs/api.py @@ -13,7 +13,15 @@ class PlatformDirsABC(ABC): # noqa: PLR0904 - """Abstract base class for platform directories.""" + """ + Abstract base class defining all platform directory properties, their :class:`~pathlib.Path` variants, and + iterators. + + Platform-specific subclasses (e.g. :class:`~platformdirs.windows.Windows`, + :class:`~platformdirs.macos.MacOS`, :class:`~platformdirs.unix.Unix`) implement the abstract + properties to return the appropriate paths for each operating system. + + """ def __init__( # noqa: PLR0913, PLR0917 self, @@ -37,7 +45,7 @@ def __init__( # noqa: PLR0913, PLR0917 :param ensure_exists: See `ensure_exists`. """ - self.appname = appname #: The name of application. + self.appname = appname #: The name of the application. self.appauthor = appauthor """ The name of the app author or distributing body for this application. @@ -66,10 +74,18 @@ def __init__( # noqa: PLR0913, PLR0917 """ An optional parameter which indicates that the entire list of data dirs should be returned. - By default, the first item would only be returned. + By default, the first item would only be returned. Only affects ``site_data_dir`` and ``site_config_dir`` on + Unix and macOS. + + """ + self.opinion = opinion + """ + Whether to use opinionated values. + + When enabled, appends an additional subdirectory for certain directories: e.g. ``Cache`` for cache and ``Logs`` + for logs on Windows, ``log`` for logs on Unix. """ - self.opinion = opinion #: A flag to indicating to use opinionated values. self.ensure_exists = ensure_exists """ Optionally create the directory (and any missing parents) upon access if it does not exist. @@ -220,7 +236,7 @@ def user_log_path(self) -> Path: @property def user_documents_path(self) -> Path: - """:return: documents a path tied to the user""" + """:return: documents path tied to the user""" return Path(self.user_documents_dir) @property diff --git a/src/platformdirs/macos.py b/src/platformdirs/macos.py index d4c0f8ad..80a6c734 100644 --- a/src/platformdirs/macos.py +++ b/src/platformdirs/macos.py @@ -15,11 +15,11 @@ class _MacOSDefaults(PlatformDirsABC): """ - Default platform directories for macOS. + Default platform directories for macOS without XDG environment variable overrides. Follows the guidance from - `Apple documentation `_. - The XDG env var handling is in :class:`~platformdirs.xdg.XDGMixin`. + `Apple's File System Programming Guide `_. + The XDG env var handling is in :class:`~platformdirs._xdg.XDGMixin`. """ @property diff --git a/src/platformdirs/unix.py b/src/platformdirs/unix.py index 4f961a78..6a37d25f 100644 --- a/src/platformdirs/unix.py +++ b/src/platformdirs/unix.py @@ -28,7 +28,7 @@ class _UnixDefaults(PlatformDirsABC): """ Default directories for Unix/Linux without XDG environment variable overrides. - The XDG env var handling is in :class:`~platformdirs.xdg.XDGMixin`. + The XDG env var handling is in :class:`~platformdirs._xdg.XDGMixin`. """ @property @@ -59,7 +59,7 @@ def _site_config_dirs(self) -> list[str]: def user_cache_dir(self) -> str: """ :return: cache directory tied to the user, e.g. ``~/.cache/$appname/$version`` or - ``~/$XDG_CACHE_HOME/$appname/$version`` + ``$XDG_CACHE_HOME/$appname/$version`` """ return self._append_app_name_and_version(os.path.expanduser("~/.cache")) # noqa: PTH111 diff --git a/src/platformdirs/windows.py b/src/platformdirs/windows.py index 7e0be381..80054857 100644 --- a/src/platformdirs/windows.py +++ b/src/platformdirs/windows.py @@ -256,6 +256,7 @@ def get_win_folder_via_ctypes(csidl_name: str) -> str: def _pick_get_win_folder() -> Callable[[str], str]: + """Select the best method to resolve Windows folder paths: ctypes, then registry, then environment variables.""" try: import ctypes # noqa: PLC0415 except ImportError: From 61e23663e7b15e495e82485a77d81c27e6083eaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Thu, 12 Feb 2026 07:39:10 -0800 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=93=9D=20docs:=20restructure=20into?= =?UTF-8?q?=20multi-page=20Sphinx=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The README was a monolithic RST file containing the full API showcase for every platform, making it hard to navigate. The Sphinx docs had a single api.rst page and a sparse index. Replaced README.rst with a lean README.md focused on quick start and links to readthedocs. Split Sphinx docs into usage guide (parameters, examples), complete API reference (added missing user_desktop and site_runtime entries), and a platform details page with comparison table. Fixed CONTRIBUTING.md to reference tox instead of hatch, and fixed proselint invocation for its new CLI. --- CONTRIBUTING.md | 9 +- README.md | 53 +++++++ README.rst | 318 ------------------------------------------ docs/api.rst | 12 ++ docs/index.rst | 27 ++-- docs/platforms.rst | 336 +++++++++++++++++++++++++++++++++++++++++++++ docs/usage.rst | 170 +++++++++++++++++++++++ pyproject.toml | 2 +- tox.toml | 2 +- 9 files changed, 597 insertions(+), 332 deletions(-) create mode 100644 README.md delete mode 100644 README.rst create mode 100644 docs/platforms.rst create mode 100644 docs/usage.rst diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 90ba3d83..2f71a036 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,6 @@ -This project uses [hatch](https://hatch.pypa.io) development, therefore consult that documentation for more in-depth how -to. To see a list of available environments use `hatch env show`, for example to run the test suite under Python 3.12 -can type in a shell `hatch run test.py3.12:run`. +This project uses [tox](https://tox.wiki) for development. To see all available environments run `tox list`. To run the +test suite under a specific Python version, e.g. Python 3.14: + +```bash +tox r -e py314 +``` diff --git a/README.md b/README.md new file mode 100644 index 00000000..04779d68 --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +# platformdirs + +[![PyPI version](https://badge.fury.io/py/platformdirs.svg)](https://badge.fury.io/py/platformdirs) +[![Python versions](https://img.shields.io/pypi/pyversions/platformdirs.svg)](https://pypi.python.org/pypi/platformdirs/) +[![CI](https://github.com/tox-dev/platformdirs/actions/workflows/check.yaml/badge.svg)](https://github.com/platformdirs/platformdirs/actions) +[![Downloads](https://static.pepy.tech/badge/platformdirs/month)](https://pepy.tech/project/platformdirs) + +A Python package for determining platform-specific directories (e.g. user data, config, cache, logs). Handles the +differences between macOS, Windows, Linux/Unix, and Android so you don't have to. + +## Quick start + +```python +from platformdirs import PlatformDirs + +dirs = PlatformDirs("MyApp", "MyCompany") +dirs.user_data_dir # e.g. ~/.local/share/MyApp on Linux +dirs.user_config_dir # e.g. ~/.config/MyApp on Linux +dirs.user_cache_dir # e.g. ~/.cache/MyApp on Linux +dirs.user_log_dir # e.g. ~/.local/state/MyApp/log on Linux +``` + +Convenience functions are also available: + +```python +from platformdirs import user_data_dir, user_config_path + +user_data_dir("MyApp", "MyCompany") # returns str +user_config_path("MyApp", "MyCompany") # returns pathlib.Path +``` + +## Documentation + +Full documentation is available at [platformdirs.readthedocs.io](https://platformdirs.readthedocs.io), including: + +- [Usage guide](https://platformdirs.readthedocs.io/en/latest/usage.html) -- parameters, examples, and patterns +- [API reference](https://platformdirs.readthedocs.io/en/latest/api.html) -- all functions and classes +- [Platform details](https://platformdirs.readthedocs.io/en/latest/platforms.html) -- per-platform paths and behavior + +## Why this fork? + +This repository is a friendly fork of the wonderful work started by +[ActiveState](https://github.com/ActiveState/appdirs) who created `appdirs`, this package's ancestor. + +Maintaining an open source project is no easy task, particularly from within an organization, and the Python community +is indebted to `appdirs` (and to Trent Mick and Jeff Rouse in particular) for creating an incredibly useful simple +module, as evidenced by the wide number of users it has attracted over the years. + +Nonetheless, given the number of long-standing open issues and pull requests, and no clear path towards +[ensuring that maintenance of the package would continue or grow](https://github.com/ActiveState/appdirs/issues/79), +this fork was created. + +Contributions are most welcome. diff --git a/README.rst b/README.rst deleted file mode 100644 index b32ddc83..00000000 --- a/README.rst +++ /dev/null @@ -1,318 +0,0 @@ -The problem -=========== - -.. image:: https://badge.fury.io/py/platformdirs.svg - :target: https://badge.fury.io/py/platformdirs -.. image:: https://img.shields.io/pypi/pyversions/platformdirs.svg - :target: https://pypi.python.org/pypi/platformdirs/ -.. image:: https://github.com/tox-dev/platformdirs/actions/workflows/check.yaml/badge.svg - :target: https://github.com/platformdirs/platformdirs/actions -.. image:: https://static.pepy.tech/badge/platformdirs/month - :target: https://pepy.tech/project/platformdirs - -When writing desktop application, finding the right location to store user data -and configuration varies per platform. Even for single-platform apps, there -may by plenty of nuances in figuring out the right location. - -For example, if running on macOS, you should use:: - - ~/Library/Application Support/ - -If on Windows (at least English Win) that should be:: - - C:\Users\\Application Data\Local Settings\\ - -or possibly:: - - C:\Users\\Application Data\\ - -for `roaming profiles `_ but that is another story. - -On Linux (and other Unices), according to the `XDG Basedir Spec`_, it should be:: - - ~/.local/share/ - -.. _XDG Basedir Spec: https://specifications.freedesktop.org/basedir/latest/ - -``platformdirs`` to the rescue -============================== - -This kind of thing is what the ``platformdirs`` package is for. -``platformdirs`` will help you choose an appropriate: - -- user data dir (``user_data_dir``) -- user config dir (``user_config_dir``) -- user cache dir (``user_cache_dir``) -- site data dir (``site_data_dir``) -- site config dir (``site_config_dir``) -- user log dir (``user_log_dir``) -- user documents dir (``user_documents_dir``) -- user downloads dir (``user_downloads_dir``) -- user pictures dir (``user_pictures_dir``) -- user videos dir (``user_videos_dir``) -- user music dir (``user_music_dir``) -- user desktop dir (``user_desktop_dir``) -- user runtime dir (``user_runtime_dir``) - -And also: - -- Is slightly opinionated on the directory names used. Look for "OPINION" in - documentation and code for when an opinion is being applied. - -Example output -============== - -On macOS: - -.. code-block:: pycon - - >>> from platformdirs import * - >>> appname = "SuperApp" - >>> appauthor = "Acme" - >>> user_data_dir(appname, appauthor) - '/Users/trentm/Library/Application Support/SuperApp' - >>> user_config_dir(appname, appauthor) - '/Users/trentm/Library/Application Support/SuperApp' - >>> user_cache_dir(appname, appauthor) - '/Users/trentm/Library/Caches/SuperApp' - >>> site_data_dir(appname, appauthor) - '/Library/Application Support/SuperApp' - >>> site_config_dir(appname, appauthor) - '/Library/Application Support/SuperApp' - >>> user_log_dir(appname, appauthor) - '/Users/trentm/Library/Logs/SuperApp' - >>> user_documents_dir() - '/Users/trentm/Documents' - >>> user_downloads_dir() - '/Users/trentm/Downloads' - >>> user_pictures_dir() - '/Users/trentm/Pictures' - >>> user_videos_dir() - '/Users/trentm/Movies' - >>> user_music_dir() - '/Users/trentm/Music' - >>> user_desktop_dir() - '/Users/trentm/Desktop' - >>> user_runtime_dir(appname, appauthor) - '/Users/trentm/Library/Caches/TemporaryItems/SuperApp' - -Note: On macOS, XDG environment variables (e.g. ``XDG_DATA_HOME``, -``XDG_CONFIG_HOME``, ``XDG_CACHE_HOME``) are also supported and take -precedence over the default macOS directories when set: - -.. code-block:: pycon - - >>> import os - >>> os.environ["XDG_CONFIG_HOME"] = "/Users/trentm/.config" - >>> user_config_dir(appname, appauthor) - '/Users/trentm/.config/SuperApp' - -On Windows: - -.. code-block:: pycon - - >>> from platformdirs import * - >>> appname = "SuperApp" - >>> appauthor = "Acme" - >>> user_data_dir(appname, appauthor) - 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp' - >>> user_data_dir(appname, appauthor, roaming=True) - 'C:\\Users\\trentm\\AppData\\Roaming\\Acme\\SuperApp' - >>> user_config_dir(appname, appauthor) - 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp' - >>> user_cache_dir(appname, appauthor) - 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Cache' - >>> site_data_dir(appname, appauthor) - 'C:\\ProgramData\\Acme\\SuperApp' - >>> site_config_dir(appname, appauthor) - 'C:\\ProgramData\\Acme\\SuperApp' - >>> user_log_dir(appname, appauthor) - 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Logs' - >>> user_documents_dir() - 'C:\\Users\\trentm\\Documents' - >>> user_downloads_dir() - 'C:\\Users\\trentm\\Downloads' - >>> user_pictures_dir() - 'C:\\Users\\trentm\\Pictures' - >>> user_videos_dir() - 'C:\\Users\\trentm\\Videos' - >>> user_music_dir() - 'C:\\Users\\trentm\\Music' - >>> user_desktop_dir() - 'C:\\Users\\trentm\\Desktop' - >>> user_runtime_dir(appname, appauthor) - 'C:\\Users\\trentm\\AppData\\Local\\Temp\\Acme\\SuperApp' - -On Linux: - -.. code-block:: pycon - - >>> from platformdirs import * - >>> appname = "SuperApp" - >>> appauthor = "Acme" - >>> user_data_dir(appname, appauthor) - '/home/trentm/.local/share/SuperApp' - >>> user_config_dir(appname) - '/home/trentm/.config/SuperApp' - >>> user_cache_dir(appname, appauthor) - '/home/trentm/.cache/SuperApp' - >>> site_data_dir(appname, appauthor) - '/usr/local/share/SuperApp' - >>> site_data_dir(appname, appauthor, multipath=True) - '/usr/local/share/SuperApp:/usr/share/SuperApp' - >>> site_config_dir(appname) - '/etc/xdg/SuperApp' - >>> os.environ["XDG_CONFIG_DIRS"] = "/etc:/usr/local/etc" - >>> site_config_dir(appname, multipath=True) - '/etc/SuperApp:/usr/local/etc/SuperApp' - >>> user_log_dir(appname, appauthor) - '/home/trentm/.local/state/SuperApp/log' - >>> user_documents_dir() - '/home/trentm/Documents' - >>> user_downloads_dir() - '/home/trentm/Downloads' - >>> user_pictures_dir() - '/home/trentm/Pictures' - >>> user_videos_dir() - '/home/trentm/Videos' - >>> user_music_dir() - '/home/trentm/Music' - >>> user_desktop_dir() - '/home/trentm/Desktop' - >>> user_runtime_dir(appname, appauthor) - '/run/user/{os.getuid()}/SuperApp' - -On Android:: - - >>> from platformdirs import * - >>> appname = "SuperApp" - >>> appauthor = "Acme" - >>> user_data_dir(appname, appauthor) - '/data/data/com.myApp/files/SuperApp' - >>> user_config_dir(appname) - '/data/data/com.myApp/shared_prefs/SuperApp' - >>> user_cache_dir(appname, appauthor) - '/data/data/com.myApp/cache/SuperApp' - >>> site_data_dir(appname, appauthor) - '/data/data/com.myApp/files/SuperApp' - >>> site_config_dir(appname) - '/data/data/com.myApp/shared_prefs/SuperApp' - >>> user_log_dir(appname, appauthor) - '/data/data/com.myApp/cache/SuperApp/log' - >>> user_documents_dir() - '/storage/emulated/0/Documents' - >>> user_downloads_dir() - '/storage/emulated/0/Downloads' - >>> user_pictures_dir() - '/storage/emulated/0/Pictures' - >>> user_videos_dir() - '/storage/emulated/0/DCIM/Camera' - >>> user_music_dir() - '/storage/emulated/0/Music' - >>> user_desktop_dir() - '/storage/emulated/0/Desktop' - >>> user_runtime_dir(appname, appauthor) - '/data/data/com.myApp/cache/SuperApp/tmp' - -Note: Some android apps like Termux and Pydroid are used as shells. These -apps are used by the end user to emulate Linux environment. Presence of -``SHELL`` environment variable is used by Platformdirs to differentiate -between general android apps and android apps used as shells. Shell android -apps also support ``XDG_*`` environment variables. - - -``PlatformDirs`` for convenience -================================ - -.. code-block:: pycon - - >>> from platformdirs import PlatformDirs - >>> dirs = PlatformDirs("SuperApp", "Acme") - >>> dirs.user_data_dir - '/Users/trentm/Library/Application Support/SuperApp' - >>> dirs.user_config_dir - '/Users/trentm/Library/Application Support/SuperApp' - >>> dirs.user_cache_dir - '/Users/trentm/Library/Caches/SuperApp' - >>> dirs.site_data_dir - '/Library/Application Support/SuperApp' - >>> dirs.site_config_dir - '/Library/Application Support/SuperApp' - >>> dirs.user_cache_dir - '/Users/trentm/Library/Caches/SuperApp' - >>> dirs.user_log_dir - '/Users/trentm/Library/Logs/SuperApp' - >>> dirs.user_documents_dir - '/Users/trentm/Documents' - >>> dirs.user_downloads_dir - '/Users/trentm/Downloads' - >>> dirs.user_pictures_dir - '/Users/trentm/Pictures' - >>> dirs.user_videos_dir - '/Users/trentm/Movies' - >>> dirs.user_music_dir - '/Users/trentm/Music' - >>> dirs.user_desktop_dir - '/Users/trentm/Desktop' - >>> dirs.user_runtime_dir - '/Users/trentm/Library/Caches/TemporaryItems/SuperApp' - -Per-version isolation -===================== - -If you have multiple versions of your app in use that you want to be -able to run side-by-side, then you may want version-isolation for these -dirs:: - - >>> from platformdirs import PlatformDirs - >>> dirs = PlatformDirs("SuperApp", "Acme", version="1.0") - >>> dirs.user_data_dir - '/Users/trentm/Library/Application Support/SuperApp/1.0' - >>> dirs.user_config_dir - '/Users/trentm/Library/Application Support/SuperApp/1.0' - >>> dirs.user_cache_dir - '/Users/trentm/Library/Caches/SuperApp/1.0' - >>> dirs.site_data_dir - '/Library/Application Support/SuperApp/1.0' - >>> dirs.site_config_dir - '/Library/Application Support/SuperApp/1.0' - >>> dirs.user_log_dir - '/Users/trentm/Library/Logs/SuperApp/1.0' - >>> dirs.user_documents_dir - '/Users/trentm/Documents' - >>> dirs.user_downloads_dir - '/Users/trentm/Downloads' - >>> dirs.user_pictures_dir - '/Users/trentm/Pictures' - >>> dirs.user_videos_dir - '/Users/trentm/Movies' - >>> dirs.user_music_dir - '/Users/trentm/Music' - >>> dirs.user_desktop_dir - '/Users/trentm/Desktop' - >>> dirs.user_runtime_dir - '/Users/trentm/Library/Caches/TemporaryItems/SuperApp/1.0' - -Be wary of using this for configuration files though; you'll need to handle -migrating configuration files manually. - -Why this Fork? -============== - -This repository is a friendly fork of the wonderful work started by -`ActiveState `_ who created -``appdirs``, this package's ancestor. - -Maintaining an open source project is no easy task, particularly -from within an organization, and the Python community is indebted -to ``appdirs`` (and to Trent Mick and Jeff Rouse in particular) for -creating an incredibly useful simple module, as evidenced by the wide -number of users it has attracted over the years. - -Nonetheless, given the number of long-standing open issues -and pull requests, and no clear path towards `ensuring -that maintenance of the package would continue or grow -`_, this fork was -created. - -Contributions are most welcome. diff --git a/docs/api.rst b/docs/api.rst index 0e96b9c5..e7160d4b 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -66,6 +66,12 @@ User music directory .. autofunction:: platformdirs.user_music_dir .. autofunction:: platformdirs.user_music_path +User desktop directory +------------------------ + +.. autofunction:: platformdirs.user_desktop_dir +.. autofunction:: platformdirs.user_desktop_path + Runtime directory ------------------- @@ -95,6 +101,12 @@ Shared cache directory .. autofunction:: platformdirs.site_cache_dir .. autofunction:: platformdirs.site_cache_path +Shared runtime directory +------------------------ + +.. autofunction:: platformdirs.site_runtime_dir +.. autofunction:: platformdirs.site_runtime_path + Platforms ~~~~~~~~~ diff --git a/docs/index.rst b/docs/index.rst index a71976e5..19efe3a3 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,21 +1,30 @@ -platformdirs's documentation -============================ +platformdirs +============ -``platformdirs`` is a library to determine platform-specific system directories. -This includes directories where to place cache files, user data, configuration, -etc. +``platformdirs`` is a Python library for determining platform-specific system directories. +Whether you need user data, configuration, cache, or log directories, ``platformdirs`` resolves the +correct location for macOS, Windows, Linux/Unix, and Android. -The source code and issue tracker are both hosted on `GitHub`_. +Features +-------- -.. _GitHub: https://github.com/platformdirs/platformdirs +- **Auto-detects the current platform** -- works on macOS, Windows, Linux, FreeBSD, OpenBSD, and Android +- **Follows platform conventions** -- XDG Base Directory Spec on Linux, ``~/Library`` on macOS, ``AppData`` on Windows +- **XDG environment variable support** -- on both Linux and macOS +- **Returns** :class:`str` **or** :class:`~pathlib.Path` -- every directory has a ``_dir`` (str) and ``_path`` (Path) variant +- **Optional directory creation** -- set ``ensure_exists=True`` to create directories on access +- **Version isolation** -- keep multiple app versions side by side .. toctree:: - :maxdepth: 3 + :maxdepth: 2 + :caption: Contents + usage api + platforms Indices and tables -================== +------------------ * :ref:`genindex` * :ref:`modindex` diff --git a/docs/platforms.rst b/docs/platforms.rst new file mode 100644 index 00000000..046e01a8 --- /dev/null +++ b/docs/platforms.rst @@ -0,0 +1,336 @@ +Platform details +================ + +``platformdirs`` auto-detects the current platform and returns the correct directory paths. +This page describes the default paths for each platform and any platform-specific behavior. + +All examples below assume ``appname="SuperApp"`` and ``appauthor="Acme"`` unless stated otherwise. + +Default paths +------------- + +``user_data_dir`` +~~~~~~~~~~~~~~~~~ + +.. list-table:: + :widths: 20 80 + + * - Linux + - ``~/.local/share/SuperApp`` + * - macOS + - ``~/Library/Application Support/SuperApp`` + * - Windows + - ``C:\Users\\AppData\Local\Acme\SuperApp`` + * - Android + - ``/data/data//files/SuperApp`` + +``user_config_dir`` +~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :widths: 20 80 + + * - Linux + - ``~/.config/SuperApp`` + * - macOS + - ``~/Library/Application Support/SuperApp`` + * - Windows + - ``C:\Users\\AppData\Local\Acme\SuperApp`` + * - Android + - ``/data/data//shared_prefs/SuperApp`` + +``user_cache_dir`` +~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :widths: 20 80 + + * - Linux + - ``~/.cache/SuperApp`` + * - macOS + - ``~/Library/Caches/SuperApp`` + * - Windows + - ``C:\Users\\AppData\Local\Acme\SuperApp\Cache`` + * - Android + - ``/data/data//cache/SuperApp`` + +``user_state_dir`` +~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :widths: 20 80 + + * - Linux + - ``~/.local/state/SuperApp`` + * - macOS + - ``~/Library/Application Support/SuperApp`` + * - Windows + - ``C:\Users\\AppData\Local\Acme\SuperApp`` + * - Android + - ``/data/data//files/SuperApp`` + +``user_log_dir`` +~~~~~~~~~~~~~~~~ + +.. list-table:: + :widths: 20 80 + + * - Linux + - ``~/.local/state/SuperApp/log`` + * - macOS + - ``~/Library/Logs/SuperApp`` + * - Windows + - ``C:\Users\\AppData\Local\Acme\SuperApp\Logs`` + * - Android + - ``/data/data//cache/SuperApp/log`` + +``user_runtime_dir`` +~~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :widths: 20 80 + + * - Linux + - ``/run/user//SuperApp`` + * - macOS + - ``~/Library/Caches/TemporaryItems/SuperApp`` + * - Windows + - ``C:\Users\\AppData\Local\Temp\Acme\SuperApp`` + * - Android + - ``/data/data//cache/SuperApp/tmp`` + +``site_data_dir`` +~~~~~~~~~~~~~~~~~ + +.. list-table:: + :widths: 20 80 + + * - Linux + - ``/usr/local/share/SuperApp`` + * - macOS + - ``/Library/Application Support/SuperApp`` + * - Windows + - ``C:\ProgramData\Acme\SuperApp`` + * - Android + - ``/data/data//files/SuperApp`` + +``site_config_dir`` +~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :widths: 20 80 + + * - Linux + - ``/etc/xdg/SuperApp`` + * - macOS + - ``/Library/Application Support/SuperApp`` + * - Windows + - ``C:\ProgramData\Acme\SuperApp`` + * - Android + - ``/data/data//shared_prefs/SuperApp`` + +``site_cache_dir`` +~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :widths: 20 80 + + * - Linux + - ``/var/cache/SuperApp`` + * - macOS + - ``/Library/Caches/SuperApp`` + * - Windows + - ``C:\ProgramData\Acme\SuperApp\Cache`` + * - Android + - ``/data/data//cache/SuperApp`` + +``site_runtime_dir`` +~~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :widths: 20 80 + + * - Linux + - ``/run/SuperApp`` + * - macOS + - ``~/Library/Caches/TemporaryItems/SuperApp`` + * - Windows + - ``C:\Users\\AppData\Local\Temp\Acme\SuperApp`` + * - Android + - ``/data/data//cache/SuperApp/tmp`` + +``user_documents_dir`` +~~~~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :widths: 20 80 + + * - Linux + - ``~/Documents`` + * - macOS + - ``~/Documents`` + * - Windows + - ``C:\Users\\Documents`` + * - Android + - ``/storage/emulated/0/Documents`` + +``user_downloads_dir`` +~~~~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :widths: 20 80 + + * - Linux + - ``~/Downloads`` + * - macOS + - ``~/Downloads`` + * - Windows + - ``C:\Users\\Downloads`` + * - Android + - ``/storage/emulated/0/Downloads`` + +``user_pictures_dir`` +~~~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :widths: 20 80 + + * - Linux + - ``~/Pictures`` + * - macOS + - ``~/Pictures`` + * - Windows + - ``C:\Users\\Pictures`` + * - Android + - ``/storage/emulated/0/Pictures`` + +``user_videos_dir`` +~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :widths: 20 80 + + * - Linux + - ``~/Videos`` + * - macOS + - ``~/Movies`` + * - Windows + - ``C:\Users\\Videos`` + * - Android + - ``/storage/emulated/0/DCIM/Camera`` + +``user_music_dir`` +~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :widths: 20 80 + + * - Linux + - ``~/Music`` + * - macOS + - ``~/Music`` + * - Windows + - ``C:\Users\\Music`` + * - Android + - ``/storage/emulated/0/Music`` + +``user_desktop_dir`` +~~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :widths: 20 80 + + * - Linux + - ``~/Desktop`` + * - macOS + - ``~/Desktop`` + * - Windows + - ``C:\Users\\Desktop`` + * - Android + - ``/storage/emulated/0/Desktop`` + +macOS +----- + +On macOS, ``platformdirs`` uses the standard Apple ``~/Library`` directories by default. +See `Apple's File System Programming Guide +`_ +for background. + +XDG environment variables (``XDG_DATA_HOME``, ``XDG_CONFIG_HOME``, ``XDG_CACHE_HOME``, etc.) +are also supported and take precedence over the macOS defaults when set. This allows users who +prefer the XDG layout to override the default behavior. + +When `Homebrew `_ is installed, ``site_data_dir`` and ``site_cache_dir`` include +the Homebrew prefix as an additional path when ``multipath=True``. + +.. autoclass:: platformdirs.macos.MacOS + :members: + :show-inheritance: + :no-index: + +Windows +------- + +On Windows, ``platformdirs`` uses the Shell Folder APIs to resolve directories. +See `Microsoft's Known Folder documentation +`_ for background. + +Key behaviors: + +- ``appauthor`` adds a parent directory: ``AppData\Local\\`` +- ``roaming=True`` switches from ``AppData\Local`` to ``AppData\Roaming``, + which syncs across machines in a Windows domain +- **OPINION**: ``user_cache_dir`` appends ``\Cache``, ``user_log_dir`` appends ``\Logs`` + +.. autoclass:: platformdirs.windows.Windows + :members: + :show-inheritance: + :no-index: + +Linux / Unix +------------ + +On Linux and other Unix-like systems, ``platformdirs`` follows the +`XDG Base Directory Specification `_. + +XDG environment variables override the defaults: + +- ``XDG_DATA_HOME`` (default ``~/.local/share``) +- ``XDG_CONFIG_HOME`` (default ``~/.config``) +- ``XDG_CACHE_HOME`` (default ``~/.cache``) +- ``XDG_STATE_HOME`` (default ``~/.local/state``) +- ``XDG_RUNTIME_DIR`` (default ``/run/user/``) +- ``XDG_DATA_DIRS`` (default ``/usr/local/share:/usr/share``) +- ``XDG_CONFIG_DIRS`` (default ``/etc/xdg``) + +When ``multipath=True``, ``site_data_dir`` and ``site_config_dir`` return all paths from +the corresponding ``XDG_*_DIRS`` variable, joined by ``:``. + +**FreeBSD / OpenBSD / NetBSD**: ``user_runtime_dir`` falls back to ``/var/run/user/`` or +``/tmp/runtime-`` when ``/run/user/`` does not exist. + +.. autoclass:: platformdirs.unix.Unix + :members: + :show-inheritance: + :no-index: + +Android +------- + +On Android, ``platformdirs`` uses the app's private storage directories. The app's package +folder (e.g. ``/data/data/com.example.app``) is detected via ``python-for-android`` or +``pyjnius``. + +Media directories (documents, downloads, pictures, videos, music) point to shared external +storage under ``/storage/emulated/0/``. + +**Shell environments**: Android apps like `Termux `_ and Pydroid that +function as Linux shells are detected by the presence of the ``SHELL`` environment variable. +In these environments, ``platformdirs`` uses the Unix/XDG backend instead, including support +for ``XDG_*`` environment variables. + +.. autoclass:: platformdirs.android.Android + :members: + :show-inheritance: + :no-index: diff --git a/docs/usage.rst b/docs/usage.rst new file mode 100644 index 00000000..4dbf440e --- /dev/null +++ b/docs/usage.rst @@ -0,0 +1,170 @@ +Usage guide +=========== + +Getting started +--------------- + +The simplest way to use ``platformdirs`` is through the convenience functions: + +.. code-block:: pycon + + >>> from platformdirs import user_data_dir, user_config_dir, user_cache_dir + >>> user_data_dir("SuperApp", "Acme") + '/Users/trentm/Library/Application Support/SuperApp' + >>> user_config_dir("SuperApp", "Acme") + '/Users/trentm/Library/Application Support/SuperApp' + >>> user_cache_dir("SuperApp", "Acme") + '/Users/trentm/Library/Caches/SuperApp' + +Each function returns a :class:`str`. For a :class:`~pathlib.Path`, use the ``_path`` variant: + +.. code-block:: pycon + + >>> from platformdirs import user_data_path + >>> user_data_path("SuperApp", "Acme") + PosixPath('/Users/trentm/Library/Application Support/SuperApp') + +Using the ``PlatformDirs`` class +-------------------------------- + +When you need multiple directories for the same application, instantiate +:data:`~platformdirs.PlatformDirs` once and access its properties: + +.. code-block:: pycon + + >>> from platformdirs import PlatformDirs + >>> dirs = PlatformDirs("SuperApp", "Acme") + >>> dirs.user_data_dir + '/Users/trentm/Library/Application Support/SuperApp' + >>> dirs.user_cache_dir + '/Users/trentm/Library/Caches/SuperApp' + >>> dirs.user_log_dir + '/Users/trentm/Library/Logs/SuperApp' + +Each :class:`str` property has a corresponding ``_path`` property that returns a :class:`~pathlib.Path`: + +.. code-block:: pycon + + >>> dirs.user_data_path + PosixPath('/Users/trentm/Library/Application Support/SuperApp') + +Parameters +---------- + +``appname`` +~~~~~~~~~~~ + +The name of your application. Used as a subdirectory in all app-specific paths. +When ``None``, the base platform directory is returned without any app-specific subdirectory. + +.. code-block:: pycon + + >>> user_data_dir("SuperApp") + '/Users/trentm/Library/Application Support/SuperApp' + >>> user_data_dir() + '/Users/trentm/Library/Application Support' + +``appauthor`` +~~~~~~~~~~~~~ + +The app author or distributing organization. On Windows, this adds an additional parent directory: + +.. code-block:: pycon + + >>> user_data_dir("SuperApp", "Acme") # on Windows + 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp' + +Set to ``False`` to suppress the author directory even on Windows: + +.. code-block:: pycon + + >>> user_data_dir("SuperApp", False) # on Windows + 'C:\\Users\\trentm\\AppData\\Local\\SuperApp' + +On non-Windows platforms, ``appauthor`` is ignored. + +``version`` +~~~~~~~~~~~ + +Appends a version subdirectory. Useful for running multiple app versions side by side: + +.. code-block:: pycon + + >>> from platformdirs import PlatformDirs + >>> dirs = PlatformDirs("SuperApp", "Acme", version="1.0") + >>> dirs.user_data_dir + '/Users/trentm/Library/Application Support/SuperApp/1.0' + >>> dirs.user_cache_dir + '/Users/trentm/Library/Caches/SuperApp/1.0' + +Be wary of using this for configuration files; you will need to handle migrating configuration +files between versions manually. + +``roaming`` +~~~~~~~~~~~ + +Windows-only. When ``True``, uses the roaming AppData directory (``CSIDL_APPDATA``) instead of +the local one (``CSIDL_LOCAL_APPDATA``). Roaming profiles sync across machines in a Windows domain. + +.. code-block:: pycon + + >>> user_data_dir("SuperApp", "Acme", roaming=True) # on Windows + 'C:\\Users\\trentm\\AppData\\Roaming\\Acme\\SuperApp' + +``multipath`` +~~~~~~~~~~~~~ + +Unix/macOS only. When ``True``, ``site_data_dir`` and ``site_config_dir`` return all directories +from ``XDG_DATA_DIRS`` / ``XDG_CONFIG_DIRS`` joined by ``os.pathsep`` (``:``) instead of just +the first one: + +.. code-block:: pycon + + >>> from platformdirs import site_data_dir + >>> site_data_dir("SuperApp", multipath=True) # on Linux + '/usr/local/share/SuperApp:/usr/share/SuperApp' + +``opinion`` +~~~~~~~~~~~ + +When ``True`` (the default), certain directories get an opinionated subdirectory. For example, on +Windows the cache directory includes a ``Cache`` subdirectory, and the log directory includes ``Logs``. +On Linux, the log directory appends ``/log``. Set to ``False`` to suppress this: + +.. code-block:: pycon + + >>> user_cache_dir("SuperApp", "Acme") # on Windows, opinion=True + 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Cache' + >>> user_cache_dir("SuperApp", "Acme", opinion=False) # on Windows + 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp' + +``ensure_exists`` +~~~~~~~~~~~~~~~~~ + +When ``True``, the directory is created (including parents) when the property is accessed. +Defaults to ``False``. + +.. code-block:: python + + from platformdirs import PlatformDirs + + dirs = PlatformDirs("SuperApp", "Acme", ensure_exists=True) + dirs.user_cache_dir # directory is created if it does not exist + +XDG environment variables +------------------------- + +On Linux, ``platformdirs`` follows the `XDG Base Directory Specification +`_. Environment variables like +``XDG_DATA_HOME``, ``XDG_CONFIG_HOME``, ``XDG_CACHE_HOME``, and ``XDG_STATE_HOME`` override +the default directories when set. + +On macOS, the same XDG environment variables are also supported and take precedence over the +default macOS directories: + +.. code-block:: pycon + + >>> import os + >>> os.environ["XDG_CONFIG_HOME"] = "/Users/trentm/.config" + >>> user_config_dir("SuperApp") + '/Users/trentm/.config/SuperApp' diff --git a/pyproject.toml b/pyproject.toml index 763b3fe6..ae8ef07d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ requires = [ [project] name = "platformdirs" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -readme = "README.rst" +readme = "README.md" keywords = [ "appdirs", "application", diff --git a/tox.toml b/tox.toml index 4e5c5d61..65c1fe83 100644 --- a/tox.toml +++ b/tox.toml @@ -98,7 +98,7 @@ commands = [ [ "python", "-c", - "import glob; import subprocess; subprocess.call(['proselint'] + glob.glob('docs/*.rst'))", + "import glob; import subprocess; subprocess.call(['proselint', 'check'] + glob.glob('docs/*.rst'))", ], [ "sphinx-build", From 2f682961475bfc0c90692acf3fa216bf612502bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Sat, 14 Feb 2026 08:13:07 -0800 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=93=9D=20docs(usage):=20document=20us?= =?UTF-8?q?e=5Fsite=5Ffor=5Froot=20parameter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue #433 reported that the use_site_for_root parameter was missing from the Usage Guide despite being available in the API. This parameter was added in #426 but documentation was not included in the usage guide. Added a new section documenting use_site_for_root alongside the other parameters. This helps users discover the feature when they need to configure system services running as root to use system-wide directories instead of root's home directory. Co-Authored-By: Claude Opus 4.5 --- docs/usage.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/usage.rst b/docs/usage.rst index 8b27b8b9..33c4cd0d 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -151,6 +151,24 @@ Defaults to ``False``. dirs = PlatformDirs("SuperApp", "Acme", ensure_exists=True) dirs.user_cache_dir # directory is created if it does not exist +``use_site_for_root`` +~~~~~~~~~~~~~~~~~~~~~ + +Unix-only. When ``True``, redirects ``user_*_dir`` calls to their ``site_*_dir`` equivalents when +running as root (uid 0). Defaults to ``False`` for backwards compatibility. + +When enabled, XDG user environment variables (e.g., ``XDG_DATA_HOME``) are bypassed for the +redirected directories. This is useful for system services running as root that should use +system-wide directories rather than root's home directory. + +.. code-block:: python + + from platformdirs import PlatformDirs + + dirs = PlatformDirs("SuperApp", use_site_for_root=True) + # When running as root, user_data_dir returns the site_data_dir path + dirs.user_data_dir # Returns site directory instead of /root/.local/share/SuperApp + Directories not covered -----------------------