Skip to content

Commit e8169bf

Browse files
committed
Adjust remote_only argument to only apply to copying plain files
This commit adjusts the behavior of the "remote_only" argument in SFTPClient copy() and mcopy() to only raise an error when attempting to copy a plain file on a system which doesn't support remote copy. Other operations during the copy such as creating directories and symlinks and setting attributes will always be allowed. When an error handler is set, it will be called once for each plain file copy which is attempted when remote_only is set and the server doesn't support remote copy. The exceptions will include the source and destination pathname, to allow other forms of copy to be performed.
1 parent 033ef54 commit e8169bf

File tree

2 files changed

+21
-15
lines changed

2 files changed

+21
-15
lines changed

asyncssh/sftp.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3759,7 +3759,8 @@ async def _copy(self, srcfs: _SFTPFSProtocol, dstfs: _SFTPFSProtocol,
37593759
preserve: bool, recurse: bool, follow_symlinks: bool,
37603760
block_size: int, max_requests: int,
37613761
progress_handler: SFTPProgressHandler,
3762-
error_handler: SFTPErrorHandler) -> None:
3762+
error_handler: SFTPErrorHandler,
3763+
remote_only: bool) -> None:
37633764
"""Copy a file, directory, or symbolic link"""
37643765

37653766
try:
@@ -3795,7 +3796,8 @@ async def _copy(self, srcfs: _SFTPFSProtocol, dstfs: _SFTPFSProtocol,
37953796
await self._copy(srcfs, dstfs, srcfile, dstfile,
37963797
srcname.attrs, preserve, recurse,
37973798
follow_symlinks, block_size, max_requests,
3798-
progress_handler, error_handler)
3799+
progress_handler, error_handler,
3800+
remote_only)
37993801

38003802
self.logger.info(' Finished copy of directory %s to %s',
38013803
srcpath, dstpath)
@@ -3810,6 +3812,9 @@ async def _copy(self, srcfs: _SFTPFSProtocol, dstfs: _SFTPFSProtocol,
38103812
else:
38113813
self.logger.info(' Copying file %s to %s', srcpath, dstpath)
38123814

3815+
if remote_only and not self.supports_remote_copy:
3816+
raise SFTPOpUnsupported('Remote copy not supported')
3817+
38133818
await _SFTPFileCopier(block_size, max_requests, 0,
38143819
srcattrs.size or 0, srcfs, dstfs,
38153820
srcpath, dstpath, progress_handler).run()
@@ -3846,7 +3851,8 @@ async def _begin_copy(self, srcfs: _SFTPFSProtocol, dstfs: _SFTPFSProtocol,
38463851
recurse: bool, follow_symlinks: bool,
38473852
block_size: int, max_requests: int,
38483853
progress_handler: SFTPProgressHandler,
3849-
error_handler: SFTPErrorHandler) -> None:
3854+
error_handler: SFTPErrorHandler,
3855+
remote_only: bool = False) -> None:
38503856
"""Begin a new file upload, download, or copy"""
38513857

38523858
if block_size <= 0:
@@ -3903,7 +3909,8 @@ async def _begin_copy(self, srcfs: _SFTPFSProtocol, dstfs: _SFTPFSProtocol,
39033909

39043910
await self._copy(srcfs, dstfs, srcfile, dstfile, srcname.attrs,
39053911
preserve, recurse, follow_symlinks, block_size,
3906-
max_requests, progress_handler, error_handler)
3912+
max_requests, progress_handler, error_handler,
3913+
remote_only)
39073914

39083915
async def get(self, remotepaths: _SFTPPaths,
39093916
localpath: Optional[_SFTPPath] = None, *,
@@ -4222,13 +4229,10 @@ async def copy(self, srcpaths: _SFTPPaths,
42224229
42234230
"""
42244231

4225-
if remote_only and not self.supports_remote_copy:
4226-
raise SFTPOpUnsupported('Remote copy not supported')
4227-
42284232
await self._begin_copy(self, self, srcpaths, dstpath, 'remote copy',
42294233
False, preserve, recurse, follow_symlinks,
42304234
block_size, max_requests, progress_handler,
4231-
error_handler)
4235+
error_handler, remote_only)
42324236

42334237
async def mget(self, remotepaths: _SFTPPaths,
42344238
localpath: Optional[_SFTPPath] = None, *,
@@ -4295,13 +4299,10 @@ async def mcopy(self, srcpaths: _SFTPPaths,
42954299
42964300
"""
42974301

4298-
if remote_only and not self.supports_remote_copy:
4299-
raise SFTPOpUnsupported('Remote copy not supported')
4300-
43014302
await self._begin_copy(self, self, srcpaths, dstpath, 'remote mcopy',
43024303
True, preserve, recurse, follow_symlinks,
43034304
block_size, max_requests, progress_handler,
4304-
error_handler)
4305+
error_handler, remote_only)
43054306

43064307
async def remote_copy(self, src: _SFTPClientFileOrPath,
43074308
dst: _SFTPClientFileOrPath, src_offset: int = 0,

tests/test_sftp.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -777,9 +777,14 @@ async def _test_copy_remote_only(self, sftp):
777777

778778
for method in ('copy', 'mcopy'):
779779
with self.subTest(method=method):
780-
with self.assertRaises(SFTPOpUnsupported):
781-
await getattr(sftp, method)('src', 'dst',
782-
remote_only=True)
780+
try:
781+
self._create_file('src')
782+
783+
with self.assertRaises(SFTPOpUnsupported):
784+
await getattr(sftp, method)('src', 'dst',
785+
remote_only=True)
786+
finally:
787+
remove('src')
783788

784789
with patch('asyncssh.sftp.SFTPServerHandler._extensions', []):
785790
# pylint: disable=no-value-for-parameter

0 commit comments

Comments
 (0)