Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add API calls that return pathlib.Path instead of str objects #27

Merged
merged 14 commits into from
Jul 23, 2021
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
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ platformdirs 2.1.0
:class:`PlatformDirsABC <platformdirs.api.PlatformDirsABC>` and it's implementations:
:class:`Android <platformdirs.android.Android>`, :class:`MacOS <platformdirs.macos.MacOS>`,
:class:`Unix <platformdirs.unix.Unix>` and :class:`Windows <platformdirs.windows.Windows>`
- Add ``*_path`` API, returning :class:`pathlib.Path <pathlib.Path>` objects instead of :class:`str`
(``user_data_path``, ``user_config_path``, ``user_cache_path``, ``user_state_path``, ``user_log_path``,
``site_data_path``, ``site_config_path``) - by `@papr <https://github.com/papr/>`_

platformdirs 2.0.2
------------------
Expand Down
7 changes: 7 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,31 @@ User data directory
-------------------

.. autofunction:: platformdirs.user_data_dir
.. autofunction:: platformdirs.user_data_path

User config directory
---------------------

.. autofunction:: platformdirs.user_config_dir
.. autofunction:: platformdirs.user_config_path

Cache directory
-------------------

.. autofunction:: platformdirs.user_cache_dir
.. autofunction:: platformdirs.user_cache_path

State directory
-------------------

.. autofunction:: platformdirs.user_state_dir
.. autofunction:: platformdirs.user_state_path

Logs directory
-------------------

.. autofunction:: platformdirs.user_log_dir
.. autofunction:: platformdirs.user_log_path

Shared directories
~~~~~~~~~~~~~~~~~~
Expand All @@ -40,11 +45,13 @@ Shared data directory
---------------------

.. autofunction:: platformdirs.site_data_dir
.. autofunction:: platformdirs.site_data_path

Shared config directory
-----------------------

.. autofunction:: platformdirs.site_config_dir
.. autofunction:: platformdirs.site_config_path

Platforms
~~~~~~~~~
Expand Down
120 changes: 120 additions & 0 deletions src/platformdirs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import importlib
import os
import sys
from pathlib import Path
from typing import TYPE_CHECKING, Optional, Type, Union

if TYPE_CHECKING:
Expand Down Expand Up @@ -143,6 +144,118 @@ def user_log_dir(
return PlatformDirs(appname=appname, appauthor=appauthor, version=version, opinion=opinion).user_log_dir


def user_data_path(
appname: Optional[str] = None,
appauthor: Union[str, None, "Literal[False]"] = None,
version: Optional[str] = None,
roaming: bool = False,
) -> 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 roaming: See `roaming <platformdirs.api.PlatformDirsABC.version>`.
:returns: data path tied to the user
"""
return PlatformDirs(appname=appname, appauthor=appauthor, version=version, roaming=roaming).user_data_path


def site_data_path(
appname: Optional[str] = None,
appauthor: Union[str, None, "Literal[False]"] = None,
version: Optional[str] = None,
multipath: bool = False,
) -> 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 multipath: See `multipath <platformdirs.api.PlatformDirsABC.multipath>`.
:returns: data path shared by users
"""
return PlatformDirs(appname=appname, appauthor=appauthor, version=version, multipath=multipath).site_data_path


def user_config_path(
appname: Optional[str] = None,
appauthor: Union[str, None, "Literal[False]"] = None,
version: Optional[str] = None,
roaming: bool = False,
) -> 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 roaming: See `roaming <platformdirs.api.PlatformDirsABC.version>`.
:returns: config path tied to the user
"""
return PlatformDirs(appname=appname, appauthor=appauthor, version=version, roaming=roaming).user_config_path

papr marked this conversation as resolved.
Show resolved Hide resolved

def site_config_path(
appname: Optional[str] = None,
appauthor: Union[str, None, "Literal[False]"] = None,
version: Optional[str] = None,
multipath: bool = False,
) -> 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 multipath: See `roaming <platformdirs.api.PlatformDirsABC.multipath>`.
:returns: config path shared by the users
"""
return PlatformDirs(appname=appname, appauthor=appauthor, version=version, multipath=multipath).site_config_path


def user_cache_path(
appname: Optional[str] = None,
appauthor: Union[str, None, "Literal[False]"] = None,
version: Optional[str] = None,
opinion: bool = True,
) -> 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 opinion: See `roaming <platformdirs.api.PlatformDirsABC.opinion>`.
:returns: cache path tied to the user
"""
return PlatformDirs(appname=appname, appauthor=appauthor, version=version, opinion=opinion).user_cache_path


def user_state_path(
appname: Optional[str] = None,
appauthor: Union[str, None, "Literal[False]"] = None,
version: Optional[str] = None,
roaming: bool = False,
) -> 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 roaming: See `roaming <platformdirs.api.PlatformDirsABC.version>`.
:returns: state path tied to the user
"""
return PlatformDirs(appname=appname, appauthor=appauthor, version=version, roaming=roaming).user_state_path


def user_log_path(
appname: Optional[str] = None,
appauthor: Union[str, None, "Literal[False]"] = None,
version: Optional[str] = None,
opinion: bool = True,
) -> 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 opinion: See `roaming <platformdirs.api.PlatformDirsABC.opinion>`.
:returns: log path tied to the user
"""
return PlatformDirs(appname=appname, appauthor=appauthor, version=version, opinion=opinion).user_log_path
papr marked this conversation as resolved.
Show resolved Hide resolved


__all__ = [
"__version__",
"__version_info__",
Expand All @@ -156,4 +269,11 @@ def user_log_dir(
"user_log_dir",
"site_data_dir",
"site_config_dir",
"user_data_path",
"user_config_path",
"user_cache_path",
"user_state_path",
"user_log_path",
"site_data_path",
"site_config_path",
]
36 changes: 36 additions & 0 deletions src/platformdirs/api.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import sys
from abc import ABC, abstractmethod
from pathlib import Path
from typing import Optional, Union

if sys.version_info >= (3, 8): # pragma: no branch
Expand Down Expand Up @@ -97,3 +98,38 @@ def user_state_dir(self) -> str:
@abstractmethod
def user_log_dir(self) -> str:
""":return: log directory tied to the user"""

@property
def user_data_path(self) -> Path:
""":return: data path tied to the user"""
return Path(self.user_data_dir)

@property
def site_data_path(self) -> Path:
""":return: data path shared by users"""
return Path(self.site_data_dir)

@property
def user_config_path(self) -> Path:
""":return: config path tied to the user"""
return Path(self.user_config_dir)

@property
def site_config_path(self) -> Path:
papr marked this conversation as resolved.
Show resolved Hide resolved
""":return: config path shared by the users"""
return Path(self.site_config_dir)

@property
def user_cache_path(self) -> Path:
""":return: cache path tied to the user"""
return Path(self.user_cache_dir)

@property
def user_state_path(self) -> Path:
""":return: state path tied to the user"""
return Path(self.user_state_dir)

@property
def user_log_path(self) -> Path:
""":return: log path tied to the user"""
return Path(self.user_log_dir)
18 changes: 17 additions & 1 deletion src/platformdirs/unix.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
from pathlib import Path

from .api import PlatformDirsABC

Expand Down Expand Up @@ -66,7 +67,6 @@ def site_config_dir(self) -> str:
:return: config directories shared by users (if `multipath <platformdirs.api.PlatformDirsABC.multipath>`
is enabled and ``XDG_DATA_DIR`` is set and a multi path the response is also a multi path separated by the OS
path separator), e.g. ``/etc/xdg/$appname/$version``
:return:
"""
# XDG default for $XDG_CONFIG_DIRS only first, if multipath is False
if "XDG_CONFIG_DIRS" in os.environ:
Expand Down Expand Up @@ -109,6 +109,22 @@ def user_log_dir(self) -> str:
path = os.path.join(path, "log")
return path

@property
def site_data_path(self) -> Path:
""":return: data path shared by users. Only return first item, even if ``multipath`` is set to ``True``"""
return self._first_item_as_path_if_multipath(self.site_data_dir)

@property
def site_config_path(self) -> Path:
""":return: config path shared by the users. Only return first item, even if ``multipath`` is set to ``True``"""
return self._first_item_as_path_if_multipath(self.site_config_dir)

def _first_item_as_path_if_multipath(self, directory: str) -> Path:
if self.multipath:
# If multipath is True, the first path is returned.
directory = directory.split(os.pathsep)[0]
return Path(directory)


__all__ = [
"Unix",
Expand Down
7 changes: 7 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ def func(request: SubRequest) -> str:
return cast(str, request.param)


@pytest.fixture(params=PROPS)
def func_path(request: SubRequest) -> str:
prop = cast(str, request.param)
prop = prop.replace("_dir", "_path")
return prop


@pytest.fixture()
papr marked this conversation as resolved.
Show resolved Hide resolved
def props() -> Tuple[str, ...]:
return PROPS
24 changes: 24 additions & 0 deletions tests/test_api.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import inspect
from pathlib import Path
from typing import Optional

import pytest
Expand All @@ -24,6 +26,28 @@ def test_property_result_is_str(func: str) -> None:
assert isinstance(result, str)


def test_method_result_is_path(func_path: str) -> None:
method = getattr(platformdirs, func_path)
result = method("MyApp", "MyCompany")
assert isinstance(result, Path)


def test_property_result_is_path(func_path: str) -> None:
dirs = platformdirs.PlatformDirs("MyApp", "MyCompany", version="1.0")
result = getattr(dirs, func_path)
assert isinstance(result, Path)


def test_function_interface_is_in_sync(func: str) -> None:
function_dir = getattr(platformdirs, func)
function_path = getattr(platformdirs, func.replace("_dir", "_path"))
assert inspect.isfunction(function_dir)
assert inspect.isfunction(function_path)
function_dir_signature = inspect.Signature.from_callable(function_dir)
function_path_signature = inspect.Signature.from_callable(function_path)
assert function_dir_signature.parameters == function_path_signature.parameters
gaborbernat marked this conversation as resolved.
Show resolved Hide resolved


@pytest.mark.parametrize("root", ["A", "/system", None])
@pytest.mark.parametrize("data", ["D", "/data", None])
def test_android_active(monkeypatch: MonkeyPatch, root: Optional[str], data: Optional[str]) -> None:
Expand Down
2 changes: 2 additions & 0 deletions whitelist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ highbit
HKEY
impl
intersphinx
isfunction
jnius
kernel32
lru
Expand All @@ -23,6 +24,7 @@ normpath
ord
param
params
pathlib
pathsep
platformdirs
pyjnius
Expand Down