specdirs is a composable, correct, [fully] compliant, and modern library for standard directories on Windows, macOS, and POSIX.
What do I mean by these attributes, especially "composable"?
WIP!
Composable:
Say, you need a platform-abstracted version of specdirs' xdg.state_dir() function. You can easily do that with specdirs:
from specdirs import dir_on, xdg
from specdirs.platforms import windows
state_dir = dir_on(
windows=windows.app_data_local_dir, # your ad hoc choice
posix=xdg.state_dir,
)So this "composability" is used via the dir_on() function but this function in and of itself wouldn't been so useful if all you could do is choose different combinations of directory functions provided by the library (this alone is already not possible with other libraries). But that is not the case.
Each [supported] platform is implemented fully and in a "native" way (instead of forcing them all into a single, rigid API).
Meaning you could retrieve any standard/known/base/user directory. Of course the "how" differs between platforms, hence the "native" part.
- specdirs has the platform-agnostic
xdgmodule (yes, works on Windows too, not that you should). - For Windows, specdirs exposes the
known_folder()function andGUIDclass. - For macOS, (it is trivial but just for completeness sake) use specdirs'
home_dir()function to construct whatever (home_dir() / "Library" / "...").
Of course, all the base and user directories of each platform are already provided in their respective specdirs.platforms.* modules. And the full XDG specification in the specdirs.xdg module.
In essence, you can use specdirs for cross-platform as well as single-platform development.
Correct:
xdg.runtime_dir()returnsNoneif $XDG_RUNTIME_DIR is unset because returning any platform-conforming directory would be incorrect since the specification requires transience, specific ownership & permissions, amongst other things - not a default value.- specdirs provides a platform-native
home_dir()function, as a correct alternative to the stdlib'sos.path.expanduser("~"),pathlib.Path.home(), etc.- On Windows, it returns FOLDERID_Profile instead of using environment variables.
- On POSIX (including macOS), it is effectively a dictionary lookup and does not need to perform any string operations.
- XDG's disabled user directories are not filtered out. Because they are 'disabled' for the
xdg-user-dirs-updatetool, not for the applications reading theuser-dirs.dirsconfig file.
Compliant:
This is the boring and contentious part. Every library will claim it is compliant.
First the boring part:
- Known Folders API on Windows
- Standard Directories on macOS
- XDG Base Directory Specification and
user-dirs.dirsconfig file on POSIX [and others]
Modern:
- Known Folders API and not the deprecated CSIDL is used on Windows.
pathlib.Pathis returned throughout (I know you saw this coming).
Tip
Use macos_asposix=True to return POSIX directory on macOS.
| Function | POSIX | macOS | Windows |
|---|---|---|---|
cache_dir() |
$XDG_CACHE_HOME (default: ~/.cache) | ~/Library/Caches | FOLDERID_LocalAppData |
cache_dir(system=True) |
/var/cache | /Library/Caches | FOLDERID_ProgramData |
config_dir() |
$XDG_CONFIG_HOME (default: ~/.config) | ~/Library/Application Support | FOLDERID_RoamingAppData |
config_dir(system=True) |
/etc | /Library/Application Support | FOLDERID_ProgramData |
config_dir(system=True, posix_local=True) |
/usr/local/etc | ||
data_dir() |
$XDG_DATA_HOME (default: ~/.local/share) | ~/Library/Application Support | FOLDERID_RoamingAppData |
data_dir(windows_roaming=False) |
FOLDERID_LocalAppData | ||
data_dir(system=True) |
/usr/share | /Library/Application Support | FOLDERID_ProgramData |
data_dir(system=True, posix_local=True) |
/usr/local/share | ||
log_dir() |
$XDG_STATE_HOME (default: ~/.local/state) | ~/Library/Logs | FOLDERID_LocalAppData |
log_dir(system=True) |
/var/log | /Library/Logs | FOLDERID_ProgramData |
system_config_dirs() |
[/usr/local/etc, /etc] | [/Library/Application Support] | [FOLDERID_ProgramData] |
system_config_dirs(posix_xdg=True) |
$XDG_CONFIG_DIRS (default: [/etc/xdg]) | ||
system_data_dirs() |
[/usr/local/share, /usr/share] | [/Library/Application Support] | [FOLDERID_ProgramData] |
system_data_dirs(posix_xdg=True) |
$XDG_DATA_DIRS (default: [/usr/local/share, /usr/share]) |
| Function | POSIX | macOS | Windows |
|---|---|---|---|
home_dir() |
$HOME (fallback: pw_dir) |
FOLDERID_Profile | |
desktop_dir() |
$XDG_DESKTOP_DIR | ~/Desktop | FOLDERID_Desktop |
documents_dir() |
$XDG_DOCUMENTS_DIR | ~/Documents | FOLDERID_Documents |
downloads_dir() |
$XDG_DOWNLOAD_DIR | ~/Downloads | FOLDERID_Downloads |
music_dir() |
$XDG_MUSIC_DIR | ~/Music | FOLDERID_Music |
pictures_dir() |
$XDG_PICTURES_DIR | ~/Pictures | FOLDERID_Pictures |
public_dir() |
$XDG_PUBLICSHARE_DIR | ~/Public | FOLDERID_Public |
videos_dir() |
$XDG_VIDEOS_DIR | ~/Movies | FOLDERID_Videos |
Note
The fallback for unset $XDG_*_DIR is chosen to be the home directory. Adapted from disabled user directories.
| Method | POSIX | macOS | Windows |
|---|---|---|---|
self.cache_dir(...) |
cache_dir(...)/self.app_name |
cache_dir(...)/self.app_name/Caches |
|
self.config_dir(...) |
config_dir(...)/self.app_name |
config_dir(...)/self.app_name/Settings |
|
self.data_dir(...) |
data_dir(...)/self.app_name |
||
self.log_dir(...) |
log_dir(...)/self.app_name |
log_dir(...)/self.app_name/Logs |
|
self.system_config_dirs(...) |
system_config_dirs(...)/self.app_name |
system_config_dirs(...)/self.app_name/Settings |
|
self.system_data_dirs(...) |
system_data_dirs(...)/self.app_name |
||
pip install specdirs