Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ Shared cache directory
.. autofunction:: platformdirs.site_cache_dir
.. autofunction:: platformdirs.site_cache_path

Shared state directory
----------------------

.. autofunction:: platformdirs.site_state_dir
.. autofunction:: platformdirs.site_state_path

Shared log directory
--------------------

Expand Down
15 changes: 15 additions & 0 deletions docs/platforms.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,21 @@ Default paths
* - Android
- ``/data/data/<pkg>/cache/SuperApp/log``

``site_state_dir``
~~~~~~~~~~~~~~~~~~

.. list-table::
:widths: 20 80

* - Linux
- ``/var/lib/SuperApp``
* - macOS
- ``/Library/Application Support/SuperApp``
* - Windows
- ``C:\ProgramData\Acme\SuperApp``
* - Android
- ``/data/data/<pkg>/files/SuperApp``

``site_log_dir``
~~~~~~~~~~~~~~~~

Expand Down
44 changes: 44 additions & 0 deletions src/platformdirs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,27 @@ def user_state_dir(
).user_state_dir


def site_state_dir(
appname: str | None = None,
appauthor: str | Literal[False] | None = None,
version: str | None = None,
ensure_exists: bool = False, # noqa: FBT001, FBT002
) -> str:
"""
:param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
:returns: state directory shared by users
"""
return PlatformDirs(
appname=appname,
appauthor=appauthor,
version=version,
ensure_exists=ensure_exists,
).site_state_dir


def user_log_dir(
appname: str | None = None,
appauthor: str | Literal[False] | None = None,
Expand Down Expand Up @@ -515,6 +536,27 @@ def user_state_path(
).user_state_path


def site_state_path(
appname: str | None = None,
appauthor: str | Literal[False] | None = None,
version: str | None = None,
ensure_exists: bool = False, # noqa: FBT001, FBT002
) -> Path:
"""
:param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
:returns: state path shared by users
"""
return PlatformDirs(
appname=appname,
appauthor=appauthor,
version=version,
ensure_exists=ensure_exists,
).site_state_path


def user_log_path(
appname: str | None = None,
appauthor: str | Literal[False] | None = None,
Expand Down Expand Up @@ -657,6 +699,8 @@ def site_runtime_path(
"site_log_path",
"site_runtime_dir",
"site_runtime_path",
"site_state_dir",
"site_state_path",
"user_cache_dir",
"user_cache_path",
"user_config_dir",
Expand Down
1 change: 1 addition & 0 deletions src/platformdirs/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"site_data_dir",
"site_config_dir",
"site_cache_dir",
"site_state_dir",
"site_log_dir",
"site_runtime_dir",
)
Expand Down
5 changes: 5 additions & 0 deletions src/platformdirs/android.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ def user_state_dir(self) -> str:
""":return: state directory tied to the user, same as `user_data_dir`"""
return self.user_data_dir

@property
def site_state_dir(self) -> str:
""":return: state directory shared by users, same as `user_state_dir`"""
return self.user_state_dir

@property
def user_log_dir(self) -> str:
"""
Expand Down
20 changes: 20 additions & 0 deletions src/platformdirs/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ def site_cache_dir(self) -> str:
def user_state_dir(self) -> str:
""":return: state directory tied to the user"""

@property
@abstractmethod
def site_state_dir(self) -> str:
""":return: state directory shared by users"""

@property
@abstractmethod
def user_log_dir(self) -> str:
Expand Down Expand Up @@ -234,6 +239,11 @@ def user_state_path(self) -> Path:
""":return: state path tied to the user"""
return Path(self.user_state_dir)

@property
def site_state_path(self) -> Path:
""":return: state path shared by users"""
return Path(self.site_state_dir)

@property
def user_log_path(self) -> Path:
""":return: log path tied to the user"""
Expand Down Expand Up @@ -299,6 +309,11 @@ def iter_cache_dirs(self) -> Iterator[str]:
yield self.user_cache_dir
yield self.site_cache_dir

def iter_state_dirs(self) -> Iterator[str]:
""":yield: all user and site state directories."""
yield self.user_state_dir
yield self.site_state_dir

def iter_log_dirs(self) -> Iterator[str]:
""":yield: all user and site log directories."""
yield self.user_log_dir
Expand All @@ -324,6 +339,11 @@ def iter_cache_paths(self) -> Iterator[Path]:
for path in self.iter_cache_dirs():
yield Path(path)

def iter_state_paths(self) -> Iterator[Path]:
""":yield: all user and site state paths."""
for path in self.iter_state_dirs():
yield Path(path)

def iter_log_paths(self) -> Iterator[Path]:
""":yield: all user and site log paths."""
for path in self.iter_log_dirs():
Expand Down
5 changes: 5 additions & 0 deletions src/platformdirs/macos.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ def user_state_dir(self) -> str:
""":return: state directory tied to the user, same as `user_data_dir`"""
return self.user_data_dir

@property
def site_state_dir(self) -> str:
""":return: state directory shared by users, same as `site_data_dir`"""
return self.site_data_dir

@property
def user_log_dir(self) -> str:
""":return: log directory tied to the user, e.g. ``~/Library/Logs/$appname/$version``"""
Expand Down
7 changes: 6 additions & 1 deletion src/platformdirs/unix.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def getuid() -> NoReturn:
from os import getuid


class _UnixDefaults(PlatformDirsABC):
class _UnixDefaults(PlatformDirsABC): # noqa: PLR0904
"""
Default directories for Unix/Linux without XDG environment variable overrides.

Expand Down Expand Up @@ -77,6 +77,11 @@ def user_state_dir(self) -> str:
"""
return self._append_app_name_and_version(os.path.expanduser("~/.local/state")) # noqa: PTH111

@property
def site_state_dir(self) -> str:
""":return: state directory shared by users, e.g. ``/var/lib/$appname/$version``"""
return self._append_app_name_and_version("/var/lib")

@property
def user_log_dir(self) -> str:
""":return: log directory tied to the user, same as `user_state_dir` if not opinionated else ``log`` in it"""
Expand Down
5 changes: 5 additions & 0 deletions src/platformdirs/windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ def user_state_dir(self) -> str:
""":return: state directory tied to the user, same as `user_data_dir`"""
return self.user_data_dir

@property
def site_state_dir(self) -> str:
""":return: state directory shared by users, same as `site_data_dir`"""
return self.site_data_dir

@property
def user_log_dir(self) -> str:
""":return: log directory tied to the user, same as `user_data_dir` if not opinionated else ``Logs`` in it"""
Expand Down
1 change: 1 addition & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"site_data_dir",
"site_config_dir",
"site_cache_dir",
"site_state_dir",
"site_log_dir",
"site_runtime_dir",
)
Expand Down
1 change: 1 addition & 0 deletions tests/test_android.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def test_android(mocker: MockerFixture, params: dict[str, Any], func: str) -> No
"user_cache_dir": f"/data/data/com.example/cache{suffix}",
"site_cache_dir": f"/data/data/com.example/cache{suffix}",
"user_state_dir": f"/data/data/com.example/files{suffix}",
"site_state_dir": f"/data/data/com.example/files{suffix}",
"user_log_dir": f"/data/data/com.example/cache{suffix}{'' if params.get('opinion', True) is False else '/log'}",
"site_log_dir": f"/data/data/com.example/cache{suffix}{'' if params.get('opinion', True) is False else '/log'}",
"user_documents_dir": "/storage/emulated/0/Documents",
Expand Down
1 change: 1 addition & 0 deletions tests/test_macos.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def test_macos(mocker: MockerFixture, params: dict[str, Any], func: str) -> None
"user_cache_dir": f"{home}/Library/Caches{suffix}",
"site_cache_dir": f"/Library/Caches{suffix}",
"user_state_dir": f"{home}/Library/Application Support{suffix}",
"site_state_dir": f"/Library/Application Support{suffix}",
"user_log_dir": f"{home}/Library/Logs{suffix}",
"site_log_dir": f"/Library/Logs{suffix}",
"user_documents_dir": f"{home}/Documents",
Expand Down
6 changes: 6 additions & 0 deletions tests/test_unix.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ def _func_to_path(func: str) -> XDGVariable | None:
"user_log_dir": XDGVariable("XDG_STATE_HOME", "~/.local/state"),
"user_runtime_dir": XDGVariable("XDG_RUNTIME_DIR", f"{gettempdir()}/runtime-1234"),
"site_log_dir": None,
"site_state_dir": None,
"site_runtime_dir": XDGVariable("XDG_RUNTIME_DIR", "/run"),
}
return mapping.get(func)
Expand Down Expand Up @@ -160,6 +161,11 @@ def test_site_log_dir_fixed_path(opinion: bool) -> None:
assert result == os.path.join("/var/log", "foo") # noqa: PTH118


def test_site_state_dir_fixed_path() -> None:
result = Unix(appname="foo").site_state_dir
assert result == os.path.join("/var/lib", "foo") # noqa: PTH118


@pytest.mark.usefixtures("_getuid")
@pytest.mark.parametrize("platform", ["freebsd", "openbsd", "netbsd"])
def test_platform_on_bsd(monkeypatch: pytest.MonkeyPatch, mocker: MockerFixture, platform: str) -> None:
Expand Down
1 change: 1 addition & 0 deletions tests/test_windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ def test_windows(params: dict[str, Any], func: str) -> None:
"user_cache_dir": cache_local,
"site_cache_dir": cache_common,
"user_state_dir": local,
"site_state_dir": common,
"user_log_dir": log,
"site_log_dir": log_common,
"user_documents_dir": os.path.normpath(_WIN_FOLDERS["CSIDL_PERSONAL"]),
Expand Down