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
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "properpath"
version = "0.2.12"
version = "0.2.13"
authors = [{ name = "Alexander Haller, Mahadi Xion", email = "elabftw@uni-heidelberg.de" }]
maintainers = [{ name = "Mahadi Xion", email = "mahadi.xion@urz.uni-heidelberg.de" }]
readme = "README.md"
Expand Down
95 changes: 92 additions & 3 deletions src/properpath/properpath.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import itertools
import logging
import sys
from copy import deepcopy
Expand All @@ -6,6 +7,7 @@
from typing import Any, Iterable, Literal, Optional, Self, Union

from .platformdirs_ import ProperPlatformDirs, ProperUnix
from .utils import PlatformNames

try:
# noinspection PyUnusedImports
Expand Down Expand Up @@ -81,6 +83,29 @@ class ProperPath(Path):
"""

default_err_logger: logging.Logger = logging.getLogger()
metadata_file_by_platforms: dict[str, set[str]] = {
PlatformNames.darwin.value: {
".DS_Store",
"._.DS_Store",
"Icon\r",
".localized",
".TemporaryItems", # dir
".Trashes",
".Spotlight-V100", # dir
".fseventsd", # dir
"__MACOSX", # dir
},
PlatformNames.win32.value: {
"Thumbs.db",
"ehthumbs.db",
"desktop.ini",
},
PlatformNames.linux.value: {
".Trash-1000", # dir
".directory",
".nomedia",
},
}

def __init__(
self,
Expand Down Expand Up @@ -181,7 +206,7 @@ def platformdirs(

dirs: ProperPlatformDirs | ProperUnix
if follow_unix is True:
if sys.platform == "darwin":
if sys.platform == PlatformNames.darwin:
dirs = ProperUnix(
appname,
appauthor,
Expand Down Expand Up @@ -657,9 +682,9 @@ def get_text(
Args:
encoding: The same meaning as the `encoding` argument for method
[`open`](https://docs.python.org/3.13/library/functions.html#open).
errors: The same meaning as the `encoding` argument for method
errors: The same meaning as the `errors` argument for method
[`open`](https://docs.python.org/3.13/library/functions.html#open).
newline: The same meaning as the `encoding` argument for method
newline: The same meaning as the `newline` argument for method
[`open`](https://docs.python.org/3.13/library/functions.html#open).
`newline` is only supported in Python 3.13 and above.
default:
Expand Down Expand Up @@ -701,5 +726,69 @@ def get_bytes(self, default: Optional[bytes] = None) -> Optional[bytes]:
except FileNotFoundError:
return default

def remove_platform_metadata(
self,
verbose: bool = True,
*,
all_platforms: bool = False,
errors: Literal["strict", "ignore"] = "strict",
) -> None:
"""
remove_platform_metadata method **recursively** removes the host machine's platform-specific metadata
files like `.DS_Store` on macOS, `Thumbs.db` on Windows, and `.Trash-1000` folder on Linux. The class
attribute `metadata_file_by_platforms` stores the platform-specific metadata file names.

Args:
verbose: A boolean flag indicating whether detailed logs of the removal operations
should be printed or logged. Defaults to `True`.
all_platforms: When `all_platforms` is True, the host machine's specific platform is ignored and
all metadata files defined in `metadata_file_by_platforms` are removed.
errors: When attempting to remove a metadata file results in an exception, by default (`errors == "strict"`),
that exception will be raised. This exception, like all other exceptions, will be tied to the problematic
`ProperPath` instance only and can be caught with `p.PathException`. If `errors == "ignore"`, then
all exceptions will be silently ignored.

Returns:
`None`
"""

def _remove_metadata(path: Self) -> None:
try:
path.remove(verbose=verbose)
except path.PathException:
match errors:
case "strict":
raise
case "ignore":
...
case _:
raise ValueError(
f"Invalid value '{errors}' for parameter 'errors'. "
"The following values for 'errors' are allowed: "
"strict, ignore."
)

sys_platform: str = "all" if all_platforms else sys.platform
match sys_platform:
case "all":
for p in self.rglob("*"):
if p.name in itertools.chain.from_iterable(
self.__class__.metadata_file_by_platforms.values()
):
_remove_metadata(p)
case PlatformNames.darwin | PlatformNames.win32 | PlatformNames.linux:
for p in self.rglob("*"):
if (
p.name
in self.__class__.metadata_file_by_platforms[sys_platform]
):
_remove_metadata(p)
case _:
raise ValueError(
f"Platform '{sys_platform}' is unsupported for removing metadata files. "
f"Supported platforms are: "
f"{self.__class__.metadata_file_by_platforms.keys()}"
)


P = ProperPath
18 changes: 18 additions & 0 deletions src/properpath/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from enum import StrEnum


class PlatformNames(StrEnum):
"""
An Enum of platform names found in
[sys.platform](https://docs.python.org/3.13/library/sys.html#sys.platform).
"""

aix = "aix"
android = "android"
emscripten = "emscripten"
ios = "ios"
linux = "linux"
darwin = "darwin"
win32 = "win32"
cygwin = "cygwin"
wasi = "wasi"
Loading