Changelog

Unreleased (2026-10-03)

4.12.3 (2026-10-03)

  • Place files from place_config_file and place_data_file in the first site directory for root on Unix with use_site_for_root=True and multipath=True, where find_config_file and find_data_file look for them. PR #607

4.12.2 (2026-09-29)

  • Keep os.pathsep in site_applications_path under multipath=True on platforms with one applications directory. PR #604

4.12.1 (2026-09-28)

  • Avoid PytestAssertRewriteWarning when importing platformdirs before invoking pytest. PR #601

4.12.0 (2026-09-26)

  • Add place_*_file methods that return a file path under a user directory and create its missing parents with mode 0o700. PR #585

  • Add find_<kind>_file and find_<kind>_files to look up an existing file across the user and site directories of each kind that has an iter_<kind>_paths method. PR #586

  • Add platformdirs.testing.isolated_dirs() and the platformdirs_isolated pytest fixture to resolve every directory under one test root. PR #590

  • Emit RuntimeDirWarning when the Unix user_runtime_dir() falls back from XDG_RUNTIME_DIR. PR #599

  • Read user_templates_dir, user_publicshare_dir and user_bin_dir on Windows from their known folders. PR #587

  • Create missing user app directories and their parents with mode 0700 under ensure_exists on POSIX platforms. PR #588

  • Raise RuntimeError for a Unix or macOS directory under the home when no home resolves, and read the password database for an empty HOME. PR #589

  • Skip an XDG_RUNTIME_DIR or /run/user/<uid> that is not a private directory of the user, and reject a symlink or file as the runtime-<uid> fallback. PR #599

  • Use the app container layout on iOS, such as ~/Library/Application Support for data. PR #600

  • Document that a Homebrew Python puts the Homebrew prefix first in the macOS shared directories, with or without multipath. PR #591

  • Document that the macOS media directories honor the XDG_*_DIR variables. PR #592

  • Document the WIN_PD_OVERRIDE_COMMON_PROGRAMS variable. PR #593

  • Document /usr/local/share/applications as the Linux site_applications_dir default. PR #594

  • Correct the BSD user_runtime_dir defaults and describe the temporary directory fallback. PR #595

  • Describe how platformdirs detects Android, finds the app folder and places the shared folders. PR #596

  • Document that Microsoft Store Python redirects only new files and folders under AppData. PR #597

  • Show how to load a font on Windows after copying it into user_fonts_dir. PR #598

4.11.15 (2026-09-26)

  • Fix the pyjnius lookup of the Android app folder and media directories, which always failed. PR #580

  • Detect Android from sys.getandroidapilevel when ANDROID_DATA and ANDROID_ROOT are unset. PR #581

  • Put Android shared-storage directories under the current user’s /storage/emulated/<user id>, not user 0’s. PR #582

  • Move Android videos to Movies and the five non-standard media folders, such as Desktop, into Documents. PR #583

4.11.14 (2026-09-25)

  • With ensure_exists, create a media directory such as user_documents_dir only when the user set it through an XDG_*_DIR variable or user-dirs.dirs, and return a dangling symlink there instead of raising FileExistsError. 4.11.13 also created the platform defaults, which filled headless home directories with folders such as ~/Templates and made a literal ~ directory when HOME was unset. PR #561

  • Ignore $XDG_RUNTIME_DIR in user_runtime_dir when use_site_for_root redirects root. PR #562

  • Return /storage/emulated/0/Download from the Android user_downloads_dir() fallback. PR #563

  • Ignore WIN_PD_OVERRIDE_* values that lack a drive or a root. PR #564

  • Find the Android app folder for package names that start with files. PR #565

  • Reject an appname, appauthor or version that leaves the base directory when set after construction. PR #566

  • Apply a changed use_site_for_root on the next read. PR #567

  • Stop raising UnicodeDecodeError on user-dirs.dirs bytes the locale encoding cannot decode. PR #568

  • Drop a trailing # comment from unquoted user-dirs.dirs values. PR #569

  • Treat empty Windows folder variables, such as PUBLIC or LOCALAPPDATA, as unset. PR #571

  • Accept roaming in user_log_dir() and user_log_path(). PR #572

  • Detect Homebrew Python on macOS by its opt/python*/Frameworks layout. PR #573

  • Keep colons in the Unix site_cache_path under multipath. PR #574

  • Return long Windows folder paths in place of 8.3 short names. PR #575

  • Create the Unix runtime-<uid> temporary fallback with mode 0700 and reject one another user owns. PR #576

  • Raise RuntimeError in place of creating a literal ~ directory when ensure_exists finds no home. PR #578

  • Fix the Windows user_preference_dir path in the platform docs. PR #577

  • Document that the macOS user_state_dir and site_state_dir ignore the XDG_DATA_* variables. PR #579

4.11.13 (2026-09-25)

  • With ensure_exists, the media directories such as user_documents_dir are created on Unix, and on macOS when an XDG variable sets them - by @ekanshul. PR #560

4.11.12 (2026-09-22)

  • Ignore relative paths in the XDG user directory environment variables, so XDG_DOCUMENTS_DIR=Documents no longer makes user_documents_dir() and the other media directories return a path relative to the working directory. They now fall back to the platform default like the XDG Base Directory variables, and like the same keys read from user-dirs.dirs - by @darrenhuai. PR #554

  • Copy nested directories in the versioned data migration recipe. PR #553

  • Exclude sphinx-llm 1.1.0 from documentation dependencies because its Markdown builder emits unknown-node warnings. PR #556

4.11.11 (2026-09-19)

  • Reject appname, appauthor and version values that leave the platform base directory (a .. segment, a leading separator, a drive or a UNC share) with ValueError, so ensure_exists cannot create directories outside it - by @Pitchfork-and-Torch. PR #552

4.11.10 (2026-09-18)

  • With ensure_exists, the site_*_dir and site_*_path properties and the iter_*_dirs iterators only create the site directories they return or yield, instead of every entry in the site list - by @darrenhuai. PR #550

4.11.9 (2026-09-16)

  • Accept multipath in site_cache_dir() and site_cache_path(). Without it, the function API could not return the Homebrew cache prefix that site_cache_dir adds under multipath - by @darrenhuai. PR #544

  • Parse Unix user-dirs.dirs line by line like xdg-user-dir. The INI parser raised on a repeated key or a line without =, and returned trailing comments and backslash escapes inside user_documents_dir() and the other media directories. The last valid assignment now wins, and platformdirs unescapes the quoted value and ignores text after the closing quote - by @darrenhuai. PR #545

  • Read PUBLIC before the home directory in user_publicshare_dir() on Windows, so it no longer raises RuntimeError when PUBLIC is set and the home directory cannot be determined - by @emme1t. PR #546

  • Raise RuntimeError from Android directories when the app folder cannot be found, instead of TypeError: expected str, bytes or os.PathLike object, not NoneType - by @Str0k. PR #547

4.11.8 (2026-09-08)

  • Make user_data_path(), user_config_path(), user_preference_path() and user_applications_path() return the first site entry when root is redirected by use_site_for_root under multipath, matching their site_*_path twins. They passed the whole joined list to Path, giving one unusable path such as /xdg/a/foo:/xdg/b/foo - by @darrenhuai. PR #538

  • Ignore relative paths in XDG Base Directory environment variables and use the existing platform fallback. Relative entries in $XDG_DATA_DIRS and $XDG_CONFIG_DIRS are skipped. PR #540

  • Preserve literal percent signs in Unix user-dirs.dirs paths, including 100% complete, 100%% and %(XDG_DESKTOP_DIR)s. Continue to expand $HOME. PR #542

  • Use the base Python installation to locate Homebrew site directories on macOS, preserving shared data, config, cache and state paths inside virtual environments. PR #543

4.11.7 (2026-09-01)

4.11.6 (2026-09-01)

4.11.5 (2026-08-27)

  • Give user_preference_dir() and user_preference_path() the same arguments as user_config_dir(). Added without arguments in PR #491, they could only return the unscoped base directory even though the property they wrap appends the app name and version. PR #531

  • Make site_applications_path() return the first entry when multipath=True, matching site_data_path(). On Unix and macOS it passed the whole $XDG_DATA_DIRS list to Path, giving one unusable path such as /first/applications:/second/applications. PR #532

  • Give user_applications_dir(), user_applications_path(), site_applications_dir() and site_applications_path() the app arguments. Android scopes both applications directories to the app, so without them the functions could only return the unscoped base directory there. On the two site functions they are keyword-only, keeping multipath first positional as it has been since 4.9.0; the two user functions take their boolean options keyword-only. PR #534

  • Correct the ordering note on the iterator methods. use_site_for_root drops the user directory entirely, so the iterators are documented as yielding the most specific directory first rather than always yielding the user one. PR #533

4.11.4 (2026-08-24)

  • Stop the iter_*_dirs methods yielding the same directory twice when a site directory resolves to its user equivalent - PR #520 covered only Unix with use_site_for_root. It also hit iter_runtime_dirs() on Unix with $XDG_RUNTIME_DIR set, on Windows and macOS, and all six iterators on Android. PR #524

  • Fix the config merging example in the how-to guide. iter_config_paths yields the user directory first, so the config.update loop let the site defaults override the user’s config instead of the other way round. PR #529

4.11.3 (2026-08-13)

4.11.2 (2026-08-10)

  • Stop iter_cache_dirs(), iter_state_dirs(), iter_log_dirs() and iter_runtime_dirs() yielding the same directory twice on Unix when use_site_for_root is active - PR #469 fixed this for the config and data iterators only. On macOS, iter_cache_dirs() now yields the Homebrew and /Library/Caches entries separately rather than one os.pathsep-joined string when multipath is set. PR #520

4.11.1 (2026-08-07)

  • Fix user_desktop_dir() on Windows builds without ctypes. CSIDL_DESKTOPDIRECTORY appeared only in the ctypes lookup table, so the registry and environment variable resolvers raised ValueError for it. PR #519

4.11.0 (2026-07-21)

  • Declare support for Python 3.15 and run the test suite against it, currently in beta. PR #512

4.10.1 (2026-07-18)

  • Stop leaking memory on repeated Windows folder lookups. get_win_folder_via_ctypes defined a fresh ctypes structure on every call, and each one registered a pointer type that was never released; the resolver is now built once and reused. PR #507

4.10.0 (2026-05-28)

4.9.6 (2026-04-09)

4.9.4 (2026-03-05)

4.9.2 (2026-02-16)

  • No user-facing changes

4.9.1 (2026-02-14)

  • No user-facing changes

4.9.0 (2026-02-14)

4.8.0 (2026-02-14)

4.7.1 (2026-02-13)

4.7.0 (2026-02-12)

  • Fall back to a temp directory when the Unix runtime dir is not writable PR #369 - by @lengau

  • Use SHGetKnownFolderPath instead of the deprecated SHGetFolderPathW on Windows PR #380 - by @moi15moi

4.6.0 (2026-02-12)

4.5.1 (2025-12-05)

4.5.0 (2025-10-08)

4.4.0 (2025-08-26)

4.3.8 (2025-05-07)

4.3.7 (2025-03-19)

4.3.6 (2024-09-17)

  • No user-facing changes

4.3.5 (2024-09-17)

  • No user-facing changes

4.3.4 (2024-09-17)

  • No user-facing changes

4.3.3 (2024-09-13)

  • No user-facing changes

4.3.2 (2024-09-08)

4.3.1 (2024-09-07)

  • No user-facing changes

4.3.0 (2024-09-07)

4.2.2 (2024-05-15)

4.2.1 (2024-04-23)

4.2.0 (2024-01-31)

4.1.0 (2023-12-04)

4.0.0 (2023-11-10)

3.11.0 (2023-10-02)

3.10.0 (2023-07-29)

3.9.1 (2023-07-15)

3.9.0 (2023-07-15)

3.8.1 (2023-07-06)

3.8.0 (2023-06-22)

  • No user-facing changes

3.7.0 (2023-06-20)

3.6.0 (2023-06-18)

3.5.3 (2023-06-09)

  • Add support for Python 3.12

3.5.2 (2023-06-09)

  • No user-facing changes

3.5.1 (2023-05-11)

3.5.0 (2023-04-27)

3.4.0 (2023-04-26)

3.3.0 (2023-04-25)

3.2.0 (2023-03-25)

  • Add the ensure_exists option to create directories when they are missing PR #155 - by @smsearcy

3.1.1 (2023-03-10)

3.1.0 (2023-03-03)

3.0.0 (2023-02-06)

2.6.2 (2022-12-28)

  • Add typing-extensions as a dependency on Python < 3.8 PR #123 - by @amacf

2.6.1 (2022-12-29)

2.6.0 (2022-12-06)

2.5.4 (2022-11-12)

  • No user-facing changes

2.5.3 (2022-11-06)

2.5.2 (2022-04-18)

  • Treat Android shells as Unix PR #72

2.5.1 (2022-02-19)

  • Work out of the box under Nuitka standalone builds PR #68

2.5.0 (2022-02-09)

2.4.1 (2021-12-26)

  • BREAKING Drop Python 3.6 support PR #52

2.4.0 (2021-09-25)

2.3.0 (2021-08-30)

2.2.0 (2021-07-29)

  • Unix: fall back to the default when the $XDG_* environment variable is empty PR #30 - by @papr

2.1.0 (2021-07-25)

2.0.2 (2021-07-13)

  • No user-facing changes

2.0.0 (2021-07-12)

  • BREAKING Rename appdirs to platformdirs as part of the friendly fork

  • BREAKING Remove support for end-of-life Pythons 2.6, 3.2, and 3.3

  • BREAKING Correct the config directory on macOS

  • Add support for Python 3.7, 3.8, and 3.9