[project @ Arch-1:robey@lag.net--2005-master-shake%paramiko--dev--1--patch-33]

add SFTPClient.put and SFTPClient.get, and make sftp file objects auto-close on del
This commit is contained in:
Robey Pointer 2005-07-13 08:35:15 +00:00
parent 1f88224239
commit 93f3cae64f
5 changed files with 97 additions and 2 deletions

1
README
View File

@ -238,7 +238,6 @@ v0.9 FEAROW
* ctr forms of ciphers are missing (blowfish-ctr, aes128-ctr, aes256-ctr)
* would be nice to have an ftp-like interface to sftp (put, get, chdir...)
* cool sftp extension: retreive MD5 or SHA1 of section of a file
* SFTPClient.from_url('sftp://robey@arch.lag.net/folder/filename', 'r+')
keep cache of opened sftp clients by (host, port, username)

View File

@ -56,6 +56,9 @@ class BufferedFile (object):
# (these may be different because we buffer for line reading)
self._pos = self._realpos = 0
def __del__(self):
self.close()
def __iter__(self):
"""
Returns an iterator that can be used to iterate over the lines in this

View File

@ -20,6 +20,7 @@
Client-mode SFTP support.
"""
import os
from sftp import *
from sftp_attr import SFTPAttributes
from sftp_file import SFTPFile
@ -428,6 +429,62 @@ class SFTPClient (BaseSFTP):
@since: 1.4
"""
return self._cwd
def put(self, localpath, remotepath):
"""
Copy a local file (C{localpath}) to the SFTP server as C{remotepath}.
Any exception raised by operations will be passed through. This
method is primarily provided as a convenience.
@param localpath: the local file to copy
@type localpath: str
@param remotepath: the destination path on the SFTP server
@type remotepath: str
@since: 1.4
"""
fl = file(localpath, 'rb')
fr = self.file(remotepath, 'wb')
size = 0
while True:
data = fl.read(16384)
if len(data) == 0:
break
fr.write(data)
size += len(data)
fl.close()
fr.close()
s = self.stat(remotepath)
if s.st_size != size:
raise IOError('size mismatch in put! %d != %d' % (s.st_size, size))
def get(self, remotepath, localpath):
"""
Copy a remote file (C{remotepath}) from the SFTP server to the local
host as C{localpath}. Any exception raised by operations will be
passed through. This method is primarily provided as a convenience.
@param remotepath: the remote file to copy
@type remotepath: str
@param localpath: the destination path on the local host
@type localpath: str
@since: 1.4
"""
fr = self.file(remotepath, 'rb')
fl = file(localpath, 'wb')
size = 0
while True:
data = fr.read(16384)
if len(data) == 0:
break
fl.write(data)
size += len(data)
fl.close()
fr.close()
s = os.stat(localpath)
if s.st_size != size:
raise IOError('size mismatch in get! %d != %d' % (s.st_size, size))
### internals...

View File

@ -43,7 +43,14 @@ class SFTPFile (BufferedFile):
def close(self):
BufferedFile.close(self)
self.sftp._request(CMD_CLOSE, self.handle)
try:
self.sftp._request(CMD_CLOSE, self.handle)
except EOFError:
# may have outlived the Transport connection
pass
except IOError:
# may have outlived the Transport connection
pass
def _read(self, size):
size = min(size, self.MAX_REQUEST_SIZE)

View File

@ -540,3 +540,32 @@ class SFTPTest (unittest.TestCase):
except:
pass
def test_J_get_put(self):
"""
verify that get/put work.
"""
import os, warnings
warnings.filterwarnings('ignore', 'tempnam.*')
localname = os.tempnam()
text = 'All I wanted was a plastic bunny rabbit.\n'
f = open(localname, 'w')
f.write(text)
f.close()
sftp.put(localname, FOLDER + '/bunny.txt')
f = sftp.open(FOLDER + '/bunny.txt', 'r')
self.assertEquals(text, f.read(128))
f.close()
os.unlink(localname)
localname = os.tempnam()
sftp.get(FOLDER + '/bunny.txt', localname)
f = open(localname, 'r')
self.assertEquals(text, f.read(128))
f.close()
os.unlink(localname)
sftp.unlink(FOLDER + '/bunny.txt')