diff --git a/cterasdk/asynchronous/core/files/browser.py b/cterasdk/asynchronous/core/files/browser.py index 07a61a38..5364ea45 100644 --- a/cterasdk/asynchronous/core/files/browser.py +++ b/cterasdk/asynchronous/core/files/browser.py @@ -112,9 +112,10 @@ async def copy(self, *paths, destination=None): :param list[str] paths: List of paths :param str destination: Destination """ - if destination is None: + try: + return await io.copy(self._core, *[self.normalize(path) for path in paths], destination=self.normalize(destination)) + except ValueError: raise ValueError('Copy destination was not specified.') - return await io.copy(self._core, *[self.normalize(path) for path in paths], destination=self.normalize(destination)) async def permalink(self, path): """ @@ -206,6 +207,7 @@ async def move(self, *paths, destination=None): :param list[str] paths: List of paths :param str destination: Destination """ - if destination is None: + try: + return await io.move(self._core, *[self.normalize(path) for path in paths], destination=self.normalize(destination)) + except ValueError: raise ValueError('Move destination was not specified.') - return await io.move(self._core, *[self.normalize(path) for path in paths], destination=self.normalize(destination)) diff --git a/cterasdk/cio/core.py b/cterasdk/cio/core.py index 0e5f6231..af494266 100644 --- a/cterasdk/cio/core.py +++ b/cterasdk/cio/core.py @@ -70,6 +70,9 @@ def absolute(self): def instance(scope, entries): if isinstance(entries, list): return [CorePath(scope, e) for e in entries] + if isinstance(entries, tuple): + source, destination = entries + return (CorePath(scope, source), CorePath(scope, destination)) return CorePath(scope, entries) @@ -237,11 +240,16 @@ def recover(*paths): def _copy_or_move(paths, destination, *, message=None): param = ActionResourcesParam.instance() - paths = [paths] if not isinstance(paths, list) else paths for path in paths: - param.add(SrcDstParam.instance(src=path.absolute_encode, dest=destination.join(path.name).absolute_encode)) - if message: - logger.info('%s from: %s to: %s', message, path.reference.as_posix(), destination.join(path.name).reference.as_posix()) + src, dest = path, destination + if isinstance(path, tuple): + src, dest = path + else: + if not dest.reference.name: + raise ValueError(f'Error: No destination specified for: {src}') + dest = dest.join(src.name) + param.add(SrcDstParam.instance(src=src.absolute_encode, dest=dest.absolute_encode)) + logger.info('%s from: %s to: %s', message, src.reference.as_posix(), dest.reference.as_posix()) yield param diff --git a/cterasdk/core/files/browser.py b/cterasdk/core/files/browser.py index d043c3cc..37fbef1b 100644 --- a/cterasdk/core/files/browser.py +++ b/cterasdk/core/files/browser.py @@ -118,9 +118,10 @@ def copy(self, *paths, destination=None): :param list[str] paths: List of paths :param str destination: Destination """ - if destination is None: + try: + return io.copy(self._core, *[self.normalize(path) for path in paths], destination=self.normalize(destination)) + except ValueError: raise ValueError('Copy destination was not specified.') - return io.copy(self._core, *[self.normalize(path) for path in paths], destination=self.normalize(destination)) def permalink(self, path): """ @@ -212,9 +213,10 @@ def move(self, *paths, destination=None): :param list[str] paths: List of paths :param str destination: Destination """ - if destination is None: + try: + return io.move(self._core, *[self.normalize(path) for path in paths], destination=self.normalize(destination)) + except ValueError: raise ValueError('Move destination was not specified.') - return io.move(self._core, *[self.normalize(path) for path in paths], destination=self.normalize(destination)) def get_share_info(self, path): """ diff --git a/docs/source/UserGuides/Miscellaneous/Changelog.rst b/docs/source/UserGuides/Miscellaneous/Changelog.rst index d44c94b2..db16da33 100644 --- a/docs/source/UserGuides/Miscellaneous/Changelog.rst +++ b/docs/source/UserGuides/Miscellaneous/Changelog.rst @@ -8,6 +8,7 @@ Improvements ^^^^^^^^^^^^ * Added support for enabling or disabling Direct Mode on CTERA Portal Storage Nodes. +* Support copying and moving multiple sources to multiple destinations on CTERA Portal. Bug Fixes ^^^^^^^^^ @@ -16,6 +17,23 @@ Bug Fixes Related issues and pull requests on GitHub: `#310 `_, `#311 `_ +`#312 `_ + +.. code:: python + + """ + Copy multiple sources: the 'Sample.docx' file and the 'Spreadsheets' directory to 'My Files/Archive' + """ + user.files.copy('My Files/Documents/Sample.docx', 'My Files/Spreadsheets', destination='My Files/Archive') + + """ + Copy multiple sources to different destinations under a different name. + """ + user.files.copy( + ("Docs/Report_January.docx", "Archive/Jan_Report_Final.docx"), + ("Budget/Budget_2024.xlsx", "Finance/2024_Annual_Budget.xlsx"), + ("Presentations/Presentation.pptx", "Sales/Q2_Sales_Pitch.pptx") + ) 2.20.15 -------