@@ -811,39 +811,34 @@ async def run(self) -> None:
811
811
self ._progress_handler (self ._srcpath , self ._dstpath , 0 , 0 )
812
812
813
813
if self ._srcfs == self ._dstfs and \
814
- isinstance (self ._srcfs , SFTPClient ):
815
- try :
816
- await self ._srcfs .remote_copy (
817
- cast (SFTPClientFile , self ._src ),
818
- cast (SFTPClientFile , self ._dst ))
819
- except SFTPOpUnsupported :
820
- pass
821
- else :
822
- self ._bytes_copied = self ._total_bytes
814
+ isinstance (self ._srcfs , SFTPClient ) and \
815
+ self ._srcfs .supports_remote_copy :
816
+ await self ._srcfs .remote_copy (cast (SFTPClientFile , self ._src ),
817
+ cast (SFTPClientFile , self ._dst ))
823
818
824
- if self ._progress_handler :
825
- self ._progress_handler (self ._srcpath , self ._dstpath ,
826
- self ._bytes_copied ,
827
- self ._total_bytes )
819
+ self ._bytes_copied = self ._total_bytes
828
820
829
- return
830
-
831
- async for _ , datalen in self .iter ():
832
- if datalen :
833
- self ._bytes_copied += datalen
821
+ if self ._progress_handler :
822
+ self ._progress_handler (self ._srcpath , self ._dstpath ,
823
+ self ._bytes_copied ,
824
+ self ._total_bytes )
825
+ else :
826
+ async for _ , datalen in self .iter ():
827
+ if datalen :
828
+ self ._bytes_copied += datalen
834
829
835
- if self ._progress_handler :
836
- self ._progress_handler (self ._srcpath , self ._dstpath ,
837
- self ._bytes_copied ,
838
- self ._total_bytes )
830
+ if self ._progress_handler :
831
+ self ._progress_handler (self ._srcpath , self ._dstpath ,
832
+ self ._bytes_copied ,
833
+ self ._total_bytes )
839
834
840
- if self ._bytes_copied != self ._total_bytes :
841
- exc = SFTPFailure ('Unexpected EOF during file copy' )
835
+ if self ._bytes_copied != self ._total_bytes :
836
+ exc = SFTPFailure ('Unexpected EOF during file copy' )
842
837
843
- setattr (exc , 'filename' , self ._srcpath )
844
- setattr (exc , 'offset' , self ._bytes_copied )
838
+ setattr (exc , 'filename' , self ._srcpath )
839
+ setattr (exc , 'offset' , self ._bytes_copied )
845
840
846
- raise exc
841
+ raise exc
847
842
finally :
848
843
if self ._src : # pragma: no branch
849
844
await self ._src .close ()
@@ -2500,6 +2495,12 @@ def version(self) -> int:
2500
2495
2501
2496
return self ._version
2502
2497
2498
+ @property
2499
+ def supports_copy_data (self ) -> bool :
2500
+ """Return whether or not SFTP remote copy is supported"""
2501
+
2502
+ return self ._supports_copy_data
2503
+
2503
2504
async def _cleanup (self , exc : Optional [Exception ]) -> None :
2504
2505
"""Clean up this SFTP client session"""
2505
2506
@@ -3678,6 +3679,12 @@ def limits(self) -> SFTPLimits:
3678
3679
3679
3680
return self ._handler .limits
3680
3681
3682
+ @property
3683
+ def supports_remote_copy (self ) -> bool :
3684
+ """Return whether or not SFTP remote copy is supported"""
3685
+
3686
+ return self ._handler .supports_copy_data
3687
+
3681
3688
@staticmethod
3682
3689
def basename (path : bytes ) -> bytes :
3683
3690
"""Return the final component of a POSIX-style path"""
@@ -4116,7 +4123,8 @@ async def copy(self, srcpaths: _SFTPPaths,
4116
4123
follow_symlinks : bool = False , block_size : int = - 1 ,
4117
4124
max_requests : int = _MAX_SFTP_REQUESTS ,
4118
4125
progress_handler : SFTPProgressHandler = None ,
4119
- error_handler : SFTPErrorHandler = None ) -> None :
4126
+ error_handler : SFTPErrorHandler = None ,
4127
+ remote_only : bool = False ) -> None :
4120
4128
"""Copy remote files to a new location
4121
4129
4122
4130
This method copies one or more files or directories on the
@@ -4193,6 +4201,8 @@ async def copy(self, srcpaths: _SFTPPaths,
4193
4201
The function to call to report copy progress
4194
4202
:param error_handler: (optional)
4195
4203
The function to call when an error occurs
4204
+ :param remote_only: (optional)
4205
+ Whether or not to only allow this to be a remote copy
4196
4206
:type srcpaths:
4197
4207
:class:`PurePath <pathlib.PurePath>`, `str`, or `bytes`,
4198
4208
or a sequence of these
@@ -4205,12 +4215,16 @@ async def copy(self, srcpaths: _SFTPPaths,
4205
4215
:type max_requests: `int`
4206
4216
:type progress_handler: `callable`
4207
4217
:type error_handler: `callable`
4218
+ :type remote_only: `bool`
4208
4219
4209
4220
:raises: | :exc:`OSError` if a local file I/O error occurs
4210
4221
| :exc:`SFTPError` if the server returns an error
4211
4222
4212
4223
"""
4213
4224
4225
+ if remote_only and not self .supports_remote_copy :
4226
+ raise SFTPOpUnsupported ('Remote copy not supported' )
4227
+
4214
4228
await self ._begin_copy (self , self , srcpaths , dstpath , 'remote copy' ,
4215
4229
False , preserve , recurse , follow_symlinks ,
4216
4230
block_size , max_requests , progress_handler ,
@@ -4268,8 +4282,9 @@ async def mcopy(self, srcpaths: _SFTPPaths,
4268
4282
follow_symlinks : bool = False , block_size : int = - 1 ,
4269
4283
max_requests : int = _MAX_SFTP_REQUESTS ,
4270
4284
progress_handler : SFTPProgressHandler = None ,
4271
- error_handler : SFTPErrorHandler = None ) -> None :
4272
- """Download remote files with glob pattern match
4285
+ error_handler : SFTPErrorHandler = None ,
4286
+ remote_only : bool = False ) -> None :
4287
+ """Copy remote files with glob pattern match
4273
4288
4274
4289
This method copies files and directories on the remote
4275
4290
system matching one or more glob patterns.
@@ -4280,6 +4295,9 @@ async def mcopy(self, srcpaths: _SFTPPaths,
4280
4295
4281
4296
"""
4282
4297
4298
+ if remote_only and not self .supports_remote_copy :
4299
+ raise SFTPOpUnsupported ('Remote copy not supported' )
4300
+
4283
4301
await self ._begin_copy (self , self , srcpaths , dstpath , 'remote mcopy' ,
4284
4302
True , preserve , recurse , follow_symlinks ,
4285
4303
block_size , max_requests , progress_handler ,
0 commit comments