Skip to content

Commit

Permalink
[TOSFS #10] Implement rmdir API
Browse files Browse the repository at this point in the history
  • Loading branch information
yanghua committed Aug 19, 2024
1 parent 27a7906 commit c7e0c56
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 0 deletions.
58 changes: 58 additions & 0 deletions tosfs/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,64 @@ def info(

return self._try_dir_info(bucket, key, path, fullpath)

def rmdir(self, path: str) -> None:
"""Remove a directory, if empty."""
path = self._strip_protocol(path).rstrip("/") + "/"
bucket, key, _ = self._split_path(path)
if not key:
return self._rm_bucket(path)

if not self.exists(path):
raise FileNotFoundError(f"Directory {path} not found.")

if not self.isdir(path):
raise NotADirectoryError(f"{path} is not a directory.")

if len(self.ls(path, refresh=True, detail=False)) > 0:
raise TosfsError(f"Directory {path} is not empty.")

try:
self.tos_client.delete_object(bucket, key)
self.invalidate_cache(path)
except tos.exceptions.TosClientError as e:
logger.error("Tosfs failed with client error: %s", e)
raise e
except tos.exceptions.TosServerError as e:
logger.error("Tosfs failed with server error: %s", e)
raise e
except Exception as e:
logger.error("Tosfs failed with unknown error: %s", e)
raise TosfsError(f"Tosfs failed with unknown error: {e}") from e

def _rm_bucket(self, path: str) -> None:
"""Remove a bucket."""
bucket, _, _ = self._split_path(path)

try:
# if the bucket is not empty, raise an error
if len(self.ls(bucket, refresh=True, detail=False)) > 0:
logger.warning(
"Try to delete bucket %s, "
"but delete failed due to bucket is not empty.",
bucket,
)
raise TosfsError(f"Bucket {bucket} is not empty.")

logger.warning("Deleting an empty bucket %s", bucket)
self.tos_client.delete_bucket(bucket)
except tos.exceptions.TosClientError as e:
logger.error("Tosfs failed with client error: %s", e)
raise e
except tos.exceptions.TosServerError as e:
logger.error("Tosfs failed with server error: %s", e)
raise e
except Exception as e:
logger.error("Tosfs failed with unknown error: %s", e)
raise TosfsError(f"Tosfs failed with unknown error: {e}") from e

self.invalidate_cache(path)
self.invalidate_cache("")

def _info_from_cache(
self, path: str, fullpath: str, version_id: Optional[str]
) -> dict:
Expand Down
24 changes: 24 additions & 0 deletions tosfs/tests/test_tosfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from tos.exceptions import TosServerError

from tosfs.core import TosFileSystem
from tosfs.exceptions import TosfsError
from tosfs.utils import random_path


Expand Down Expand Up @@ -105,3 +106,26 @@ def test_info(tosfs: TosFileSystem, bucket: str, temporary_workspace: str) -> No

with pytest.raises(FileNotFoundError):
tosfs.info(f"{bucket}/nonexistent")


def test_rmdir(tosfs: TosFileSystem, bucket: str, temporary_workspace: str) -> None:
with pytest.raises(TosfsError):
tosfs.rmdir(bucket)

file_name = random_path()
tosfs.tos_client.put_object(bucket=bucket, key=f"{temporary_workspace}/{file_name}")
assert f"{bucket}/{temporary_workspace}/{file_name}" in tosfs.ls(
f"{bucket}/{temporary_workspace}", detail=False
)

with pytest.raises(TosfsError):
tosfs.rmdir(f"{bucket}/{temporary_workspace}")

with pytest.raises(NotADirectoryError):
tosfs.rmdir(f"{bucket}/{temporary_workspace}/{file_name}")

tosfs._rm(f"{bucket}/{temporary_workspace}/{file_name}")
assert tosfs.ls(f"{bucket}/{temporary_workspace}", detail=False) == []

tosfs.rmdir(f"{bucket}/{temporary_workspace}")
assert f"{bucket}/{temporary_workspace}" not in tosfs.ls(bucket, detail=False)

0 comments on commit c7e0c56

Please sign in to comment.