Commit 648bcd70 authored by Antoine Pitrou's avatar Antoine Pitrou

Merged revisions 76546 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r76546 | antoine.pitrou | 2009-11-27 14:18:34 +0100 (ven., 27 nov. 2009) | 7 lines

  Issue #6845: Add restart support for binary upload in ftplib.  The
  `storbinary()` method of FTP and FTP_TLS objects gains an optional `rest`
  argument.  Patch by Pablo Mouzo.

  (note: the patch also adds a test for the rest argument in retrbinary())
........
parent 1a305fd1
...@@ -226,14 +226,18 @@ followed by ``lines`` for the text version or ``binary`` for the binary version. ...@@ -226,14 +226,18 @@ followed by ``lines`` for the text version or ``binary`` for the binary version.
Passive mode is on by default. Passive mode is on by default.
.. method:: FTP.storbinary(cmd, file, blocksize=8192, callback=None) .. method:: FTP.storbinary(cmd, file, blocksize=8192, callback=None, rest=None)
Store a file in binary transfer mode. *cmd* should be an appropriate Store a file in binary transfer mode. *cmd* should be an appropriate
``STOR`` command: ``"STOR filename"``. *file* is an open file object which is ``STOR`` command: ``"STOR filename"``. *file* is an open file object which is
read until EOF using its :meth:`read` method in blocks of size *blocksize* to read until EOF using its :meth:`read` method in blocks of size *blocksize* to
provide the data to be stored. The *blocksize* argument defaults to 8192. provide the data to be stored. The *blocksize* argument defaults to 8192.
*callback* is an optional single parameter callable that is called *callback* is an optional single parameter callable that is called
on each block of data after it is sent. on each block of data after it is sent. *rest* means the same thing as in
the :meth:`transfercmd` method.
.. versionchanged:: 3.2
*rest* parameter added.
.. method:: FTP.storlines(cmd, file, callback=None) .. method:: FTP.storlines(cmd, file, callback=None)
......
...@@ -433,7 +433,7 @@ class FTP: ...@@ -433,7 +433,7 @@ class FTP:
conn.close() conn.close()
return self.voidresp() return self.voidresp()
def storbinary(self, cmd, fp, blocksize=8192, callback=None): def storbinary(self, cmd, fp, blocksize=8192, callback=None, rest=None):
"""Store a file in binary mode. A new port is created for you. """Store a file in binary mode. A new port is created for you.
Args: Args:
...@@ -443,12 +443,13 @@ class FTP: ...@@ -443,12 +443,13 @@ class FTP:
the connection at once. [default: 8192] the connection at once. [default: 8192]
callback: An optional single parameter callable that is called on callback: An optional single parameter callable that is called on
on each block of data after it is sent. [default: None] on each block of data after it is sent. [default: None]
rest: Passed to transfercmd(). [default: None]
Returns: Returns:
The response code. The response code.
""" """
self.voidcmd('TYPE I') self.voidcmd('TYPE I')
conn = self.transfercmd(cmd) conn = self.transfercmd(cmd, rest)
while 1: while 1:
buf = fp.read(blocksize) buf = fp.read(blocksize)
if not buf: break if not buf: break
...@@ -714,9 +715,9 @@ else: ...@@ -714,9 +715,9 @@ else:
conn.close() conn.close()
return self.voidresp() return self.voidresp()
def storbinary(self, cmd, fp, blocksize=8192, callback=None): def storbinary(self, cmd, fp, blocksize=8192, callback=None, rest=None):
self.voidcmd('TYPE I') self.voidcmd('TYPE I')
conn = self.transfercmd(cmd) conn = self.transfercmd(cmd, rest)
try: try:
while 1: while 1:
buf = fp.read(blocksize) buf = fp.read(blocksize)
......
...@@ -57,6 +57,7 @@ class DummyFTPHandler(asynchat.async_chat): ...@@ -57,6 +57,7 @@ class DummyFTPHandler(asynchat.async_chat):
self.last_received_cmd = None self.last_received_cmd = None
self.last_received_data = '' self.last_received_data = ''
self.next_response = '' self.next_response = ''
self.rest = None
self.push('220 welcome') self.push('220 welcome')
def collect_incoming_data(self, data): def collect_incoming_data(self, data):
...@@ -170,10 +171,19 @@ class DummyFTPHandler(asynchat.async_chat): ...@@ -170,10 +171,19 @@ class DummyFTPHandler(asynchat.async_chat):
def cmd_stor(self, arg): def cmd_stor(self, arg):
self.push('125 stor ok') self.push('125 stor ok')
def cmd_rest(self, arg):
self.rest = arg
self.push('350 rest ok')
def cmd_retr(self, arg): def cmd_retr(self, arg):
self.push('125 retr ok') self.push('125 retr ok')
self.dtp.push(RETR_DATA) if self.rest is not None:
offset = int(self.rest)
else:
offset = 0
self.dtp.push(RETR_DATA[offset:])
self.dtp.close_when_done() self.dtp.close_when_done()
self.rest = None
def cmd_list(self, arg): def cmd_list(self, arg):
self.push('125 list ok') self.push('125 list ok')
...@@ -450,6 +460,17 @@ class TestFTPClass(TestCase): ...@@ -450,6 +460,17 @@ class TestFTPClass(TestCase):
self.client.retrbinary('retr', callback) self.client.retrbinary('retr', callback)
self.assertEqual(''.join(received), RETR_DATA) self.assertEqual(''.join(received), RETR_DATA)
def test_retrbinary_rest(self):
def callback(data):
received.append(data.decode('ascii'))
for rest in (0, 10, 20):
received = []
self.client.retrbinary('retr', callback, rest=rest)
self.assertEqual(''.join(received), RETR_DATA[rest:],
msg='rest test case %d %d %d' % (rest,
len(''.join(received)),
len(RETR_DATA[rest:])))
def test_retrlines(self): def test_retrlines(self):
received = [] received = []
self.client.retrlines('retr', received.append) self.client.retrlines('retr', received.append)
...@@ -465,6 +486,13 @@ class TestFTPClass(TestCase): ...@@ -465,6 +486,13 @@ class TestFTPClass(TestCase):
self.client.storbinary('stor', f, callback=lambda x: flag.append(None)) self.client.storbinary('stor', f, callback=lambda x: flag.append(None))
self.assertTrue(flag) self.assertTrue(flag)
def test_storbinary_rest(self):
f = io.BytesIO(RETR_DATA.replace('\r\n', '\n').encode('ascii'))
for r in (30, '30'):
f.seek(0)
self.client.storbinary('stor', f, rest=r)
self.assertEqual(self.server.handler.rest, str(r))
def test_storlines(self): def test_storlines(self):
f = io.BytesIO(RETR_DATA.replace('\r\n', '\n').encode('ascii')) f = io.BytesIO(RETR_DATA.replace('\r\n', '\n').encode('ascii'))
self.client.storlines('stor', f) self.client.storlines('stor', f)
......
...@@ -140,6 +140,10 @@ C-API ...@@ -140,6 +140,10 @@ C-API
Library Library
------- -------
- Issue #6845: Add restart support for binary upload in ftplib. The
`storbinary()` method of FTP and FTP_TLS objects gains an optional `rest`
argument. Patch by Pablo Mouzo.
- Issue #5788: `datetime.timedelta` objects get a new `total_seconds()` - Issue #5788: `datetime.timedelta` objects get a new `total_seconds()`
method returning the total number of seconds in the duration. Patch by method returning the total number of seconds in the duration. Patch by
Brian Quinlan. Brian Quinlan.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment