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 9a72f9b
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 2 deletions.
63 changes: 61 additions & 2 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.rstrip("/") + "/")
self.invalidate_cache(path.rstrip("/"))
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.rstrip("/"))
self.invalidate_cache("")

def _info_from_cache(
self, path: str, fullpath: str, version_id: Optional[str]
) -> dict:
Expand Down Expand Up @@ -643,9 +701,10 @@ def _split_path(self, path: str) -> Tuple[str, str, Optional[str]]:

@staticmethod
def _fill_common_prefix_info(common_prefix: CommonPrefixInfo, bucket: str) -> dict:
name = "/".join([bucket, common_prefix.prefix[:-1]])
return {
"name": common_prefix.prefix[:-1],
"Key": "/".join([bucket, common_prefix.prefix]),
"name": name,
"Key": name,
"Size": 0,
"type": "directory",
}
Expand Down
26 changes: 26 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,28 @@ 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, refresh=True
)

0 comments on commit 9a72f9b

Please sign in to comment.