From fd2238f5ca74852672c892d10f05a2e4b1975dcd Mon Sep 17 00:00:00 2001 From: Yoshihiro OKUMURA Date: Tue, 9 May 2023 18:38:58 +0900 Subject: [PATCH] implemented to move or rename file/folder command `mv` --- mdrsclient/api/file.py | 11 ++++-- mdrsclient/api/folder.py | 11 +++++- mdrsclient/commands/file.py | 79 +++++++++++++++++++++++++------------ 3 files changed, 70 insertions(+), 31 deletions(-) diff --git a/mdrsclient/api/file.py b/mdrsclient/api/file.py index 5655459..ab9d011 100644 --- a/mdrsclient/api/file.py +++ b/mdrsclient/api/file.py @@ -45,12 +45,14 @@ class FileApi(BaseApi): url = self.ENTRYPOINT + file.id + "/" token_check(self.connection) if path is not None: + # update file body try: with open(path, mode="rb") as fp: response = self._put(url, files={"file": fp}) except OSError: raise UnexpectedException(f"Could not open `{path}` file.") else: + # update metadata data = {"name": file.name, "description": file.description} response = self._put(url, data=data) self._raise_response_error(response) @@ -64,7 +66,7 @@ class FileApi(BaseApi): self._raise_response_error(response) return True - def move(self, file: File, folder_id: str | None) -> bool: + def move(self, file: File, folder_id: str) -> bool: print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name) url = self.ENTRYPOINT + file.id + "/move/" data = {"folder": folder_id} @@ -83,11 +85,12 @@ class FileApi(BaseApi): def download(self, file: File, path: str) -> bool: print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name) - url = self.connection.build_url("v2/", file.download_url) - r = self.connection.session.get(url, stream=True) + url = "v2/" + file.download_url + response = self._get(url, stream=True) + self._raise_response_error(response) try: with open(path, "wb") as f: - for chunk in r.iter_content(chunk_size=4096): + for chunk in response.iter_content(chunk_size=4096): if chunk: f.write(chunk) f.flush() diff --git a/mdrsclient/api/folder.py b/mdrsclient/api/folder.py index 3c48fd5..85043fa 100644 --- a/mdrsclient/api/folder.py +++ b/mdrsclient/api/folder.py @@ -50,7 +50,7 @@ class FolderApi(BaseApi): def update(self, folder: FolderSimple) -> bool: print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name) - url = self.ENTRYPOINT + url = self.ENTRYPOINT + folder.id + "/" data = { "name": folder.name, "description": folder.description, @@ -68,6 +68,15 @@ class FolderApi(BaseApi): self._raise_response_error(response) return True + def move(self, folder: FolderSimple, folder_id: str) -> bool: + print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name) + url = self.ENTRYPOINT + folder.id + "/move/" + data = {"parent": folder_id} + token_check(self.connection) + response = self._post(url, data=data) + self._raise_response_error(response) + return True + def metadata(self, id: str) -> dict: print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name) url = self.ENTRYPOINT + id + "/metadata/" diff --git a/mdrsclient/commands/file.py b/mdrsclient/commands/file.py index 3e73b01..6ea2160 100644 --- a/mdrsclient/commands/file.py +++ b/mdrsclient/commands/file.py @@ -20,7 +20,7 @@ from mdrsclient.exceptions import ( MDRSException, UnexpectedException, ) -from mdrsclient.models import File, Folder +from mdrsclient.models import File, Folder, FolderSimple from mdrsclient.settings import NUMBER_OF_PROCESS @@ -55,10 +55,10 @@ class FileCommand(BaseCommand): download_parser.add_argument("remote_path", help="Remote file path (remote:/lab/path/file)") download_parser.add_argument("local_path", help="Local folder path (/foo/bar/)") download_parser.set_defaults(func=FileCommand.download) - # move - move_parser = top_level_subparsers.add_parser("move", help="move a file") - move_parser.add_argument("src_path", help="Source remote file path (remote:/lab/path/file)") - move_parser.add_argument("dest_path", help="Destination remote file path (remote:/lab/path/file)") + # mv + move_parser = top_level_subparsers.add_parser("mv", help="move or rename file or folder") + move_parser.add_argument("src_path", help="Source remote path (remote:/lab/path/src)") + move_parser.add_argument("dest_path", help="Destination remote path (remote:/lab/path/dest)") move_parser.set_defaults(func=FileCommand.move) # remove remove_parser = top_level_subparsers.add_parser("remove", help="remove a file") @@ -157,31 +157,58 @@ class FileCommand(BaseCommand): if src_laboratory_name != dest_laboratory_name: raise IllegalArgumentException("Laboratory mismatched.") src_path = src_path.rstrip("/") - src_dirpath = os.path.dirname(src_path) - src_filename = os.path.basename(src_path) + src_dirname = os.path.dirname(src_path) + src_basename = os.path.basename(src_path) if dest_path.endswith("/"): - dest_dirpath = dest_path - dest_filename = src_filename + dest_dirname = dest_path + dest_basename = src_basename else: - dest_dirpath = os.path.dirname(dest_path) - dest_filename = os.path.basename(dest_path) + dest_dirname = os.path.dirname(dest_path) + dest_basename = os.path.basename(dest_path) connection = create_connection(src_remote) laboratory = find_laboratory(connection, src_laboratory_name) - src_folder = find_folder(connection, laboratory, src_dirpath) - dest_folder = find_folder(connection, laboratory, dest_dirpath) - src_file = src_folder.find_file(src_filename) - if src_file is None: - raise IllegalArgumentException(f"File `{src_filename}` not found.") - dest_file = dest_folder.find_file(dest_filename) - if dest_file is not None: - raise IllegalArgumentException(f"File `{dest_filename}` already exists.") - file_api = FileApi(connection) - if src_folder.id != dest_folder.id: - file_api.move(src_file, dest_folder.id) - if dest_filename != src_filename: - dest_file_dict = dataclasses.asdict(src_file) | {"name": dest_filename} - dest_file = parse_obj_as(File, dest_file_dict) - file_api.update(dest_file, None) + src_parent_folder = find_folder(connection, laboratory, src_dirname) + dest_parent_folder = find_folder(connection, laboratory, dest_dirname) + src_file = src_parent_folder.find_file(src_basename) + if src_file is not None: + # source is file + dest_file = dest_parent_folder.find_file(dest_basename) + if dest_file is not None: + raise IllegalArgumentException(f"File `{dest_basename}` already exists.") + dest_sub_folder = dest_parent_folder.find_sub_folder(dest_basename) + if dest_sub_folder is not None: + raise IllegalArgumentException( + f"Cannot overwrite non-folder `{dest_basename}` with folder `{dest_path}`." + ) + file_api = FileApi(connection) + if src_parent_folder.id != dest_parent_folder.id: + file_api.move(src_file, dest_parent_folder.id) + if dest_basename != src_basename: + dest_file_dict = dataclasses.asdict(src_file) | {"name": dest_basename} + dest_file = parse_obj_as(File, dest_file_dict) + file_api.update(dest_file, None) + else: + src_folder = src_parent_folder.find_sub_folder(src_basename) + if src_folder is None: + raise IllegalArgumentException(f"File or Folder `{src_basename}` not found.") + # source is folder + dest_file = dest_parent_folder.find_file(dest_basename) + if dest_file is not None: + raise IllegalArgumentException( + f"Cannot overwrite non-folder `{dest_basename}` with folder `{src_path}`." + ) + dest_folder = dest_parent_folder.find_sub_folder(dest_basename) + if dest_folder is not None: + if dest_folder.id == src_folder.id: + raise IllegalArgumentException(f"`{src_path}` and `{src_path}` are the same folder.") + raise IllegalArgumentException(f"Cannot move `{src_path}` to `{dest_path}`: Folder not empty.") + folder_api = FolderApi(connection) + if src_parent_folder.id != dest_parent_folder.id: + folder_api.move(src_folder, dest_parent_folder.id) + if src_basename != dest_basename: + dest_folder_dict = dataclasses.asdict(src_folder) | {"name": dest_basename} + dest_folder = parse_obj_as(FolderSimple, dest_folder_dict) + folder_api.update(dest_folder) @staticmethod def remove(args: Namespace) -> None: