Merge "Port FileLikeIter to Python 3"
This commit is contained in:
commit
4e370e5116
@ -454,6 +454,8 @@ class FileLikeIter(object):
|
|||||||
def __init__(self, iterable):
|
def __init__(self, iterable):
|
||||||
"""
|
"""
|
||||||
Wraps an iterable to behave as a file-like object.
|
Wraps an iterable to behave as a file-like object.
|
||||||
|
|
||||||
|
The iterable must yield bytes strings.
|
||||||
"""
|
"""
|
||||||
self.iterator = iter(iterable)
|
self.iterator = iter(iterable)
|
||||||
self.buf = None
|
self.buf = None
|
||||||
@ -474,10 +476,11 @@ class FileLikeIter(object):
|
|||||||
return rv
|
return rv
|
||||||
else:
|
else:
|
||||||
return next(self.iterator)
|
return next(self.iterator)
|
||||||
|
__next__ = next
|
||||||
|
|
||||||
def read(self, size=-1):
|
def read(self, size=-1):
|
||||||
"""
|
"""
|
||||||
read([size]) -> read at most size bytes, returned as a string.
|
read([size]) -> read at most size bytes, returned as a bytes string.
|
||||||
|
|
||||||
If the size argument is negative or omitted, read until EOF is reached.
|
If the size argument is negative or omitted, read until EOF is reached.
|
||||||
Notice that when in non-blocking mode, less data than what was
|
Notice that when in non-blocking mode, less data than what was
|
||||||
@ -486,9 +489,9 @@ class FileLikeIter(object):
|
|||||||
if self.closed:
|
if self.closed:
|
||||||
raise ValueError('I/O operation on closed file')
|
raise ValueError('I/O operation on closed file')
|
||||||
if size < 0:
|
if size < 0:
|
||||||
return ''.join(self)
|
return b''.join(self)
|
||||||
elif not size:
|
elif not size:
|
||||||
chunk = ''
|
chunk = b''
|
||||||
elif self.buf:
|
elif self.buf:
|
||||||
chunk = self.buf
|
chunk = self.buf
|
||||||
self.buf = None
|
self.buf = None
|
||||||
@ -496,7 +499,7 @@ class FileLikeIter(object):
|
|||||||
try:
|
try:
|
||||||
chunk = next(self.iterator)
|
chunk = next(self.iterator)
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
return ''
|
return b''
|
||||||
if len(chunk) > size:
|
if len(chunk) > size:
|
||||||
self.buf = chunk[size:]
|
self.buf = chunk[size:]
|
||||||
chunk = chunk[:size]
|
chunk = chunk[:size]
|
||||||
@ -504,7 +507,7 @@ class FileLikeIter(object):
|
|||||||
|
|
||||||
def readline(self, size=-1):
|
def readline(self, size=-1):
|
||||||
"""
|
"""
|
||||||
readline([size]) -> next line from the file, as a string.
|
readline([size]) -> next line from the file, as a bytes string.
|
||||||
|
|
||||||
Retain newline. A non-negative size argument limits the maximum
|
Retain newline. A non-negative size argument limits the maximum
|
||||||
number of bytes to return (an incomplete line may be returned then).
|
number of bytes to return (an incomplete line may be returned then).
|
||||||
@ -512,8 +515,8 @@ class FileLikeIter(object):
|
|||||||
"""
|
"""
|
||||||
if self.closed:
|
if self.closed:
|
||||||
raise ValueError('I/O operation on closed file')
|
raise ValueError('I/O operation on closed file')
|
||||||
data = ''
|
data = b''
|
||||||
while '\n' not in data and (size < 0 or len(data) < size):
|
while b'\n' not in data and (size < 0 or len(data) < size):
|
||||||
if size < 0:
|
if size < 0:
|
||||||
chunk = self.read(1024)
|
chunk = self.read(1024)
|
||||||
else:
|
else:
|
||||||
@ -521,8 +524,8 @@ class FileLikeIter(object):
|
|||||||
if not chunk:
|
if not chunk:
|
||||||
break
|
break
|
||||||
data += chunk
|
data += chunk
|
||||||
if '\n' in data:
|
if b'\n' in data:
|
||||||
data, sep, rest = data.partition('\n')
|
data, sep, rest = data.partition(b'\n')
|
||||||
data += sep
|
data += sep
|
||||||
if self.buf:
|
if self.buf:
|
||||||
self.buf = rest + self.buf
|
self.buf = rest + self.buf
|
||||||
@ -532,7 +535,7 @@ class FileLikeIter(object):
|
|||||||
|
|
||||||
def readlines(self, sizehint=-1):
|
def readlines(self, sizehint=-1):
|
||||||
"""
|
"""
|
||||||
readlines([size]) -> list of strings, each a line from the file.
|
readlines([size]) -> list of bytes strings, each a line from the file.
|
||||||
|
|
||||||
Call readline() repeatedly and return a list of the lines so read.
|
Call readline() repeatedly and return a list of the lines so read.
|
||||||
The optional size argument, if given, is an approximate bound on the
|
The optional size argument, if given, is an approximate bound on the
|
||||||
@ -3370,7 +3373,7 @@ class _MultipartMimeFileLikeObject(object):
|
|||||||
if not length:
|
if not length:
|
||||||
length = self.read_chunk_size
|
length = self.read_chunk_size
|
||||||
if self.no_more_data_for_this_file:
|
if self.no_more_data_for_this_file:
|
||||||
return ''
|
return b''
|
||||||
|
|
||||||
# read enough data to know whether we're going to run
|
# read enough data to know whether we're going to run
|
||||||
# into a boundary in next [length] bytes
|
# into a boundary in next [length] bytes
|
||||||
@ -3396,14 +3399,14 @@ class _MultipartMimeFileLikeObject(object):
|
|||||||
# if it does, just return data up to the boundary
|
# if it does, just return data up to the boundary
|
||||||
else:
|
else:
|
||||||
ret, self.input_buffer = self.input_buffer.split(self.boundary, 1)
|
ret, self.input_buffer = self.input_buffer.split(self.boundary, 1)
|
||||||
self.no_more_files = self.input_buffer.startswith('--')
|
self.no_more_files = self.input_buffer.startswith(b'--')
|
||||||
self.no_more_data_for_this_file = True
|
self.no_more_data_for_this_file = True
|
||||||
self.input_buffer = self.input_buffer[2:]
|
self.input_buffer = self.input_buffer[2:]
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def readline(self):
|
def readline(self):
|
||||||
if self.no_more_data_for_this_file:
|
if self.no_more_data_for_this_file:
|
||||||
return ''
|
return b''
|
||||||
boundary_pos = newline_pos = -1
|
boundary_pos = newline_pos = -1
|
||||||
while newline_pos < 0 and boundary_pos < 0:
|
while newline_pos < 0 and boundary_pos < 0:
|
||||||
try:
|
try:
|
||||||
@ -3411,7 +3414,7 @@ class _MultipartMimeFileLikeObject(object):
|
|||||||
except (IOError, ValueError) as e:
|
except (IOError, ValueError) as e:
|
||||||
raise swift.common.exceptions.ChunkReadError(str(e))
|
raise swift.common.exceptions.ChunkReadError(str(e))
|
||||||
self.input_buffer += chunk
|
self.input_buffer += chunk
|
||||||
newline_pos = self.input_buffer.find('\r\n')
|
newline_pos = self.input_buffer.find(b'\r\n')
|
||||||
boundary_pos = self.input_buffer.find(self.boundary)
|
boundary_pos = self.input_buffer.find(self.boundary)
|
||||||
if not chunk:
|
if not chunk:
|
||||||
self.no_more_files = True
|
self.no_more_files = True
|
||||||
@ -3420,7 +3423,7 @@ class _MultipartMimeFileLikeObject(object):
|
|||||||
if newline_pos >= 0 and \
|
if newline_pos >= 0 and \
|
||||||
(boundary_pos < 0 or newline_pos < boundary_pos):
|
(boundary_pos < 0 or newline_pos < boundary_pos):
|
||||||
# Use self.read to ensure any logic there happens...
|
# Use self.read to ensure any logic there happens...
|
||||||
ret = ''
|
ret = b''
|
||||||
to_read = newline_pos + 2
|
to_read = newline_pos + 2
|
||||||
while to_read > 0:
|
while to_read > 0:
|
||||||
chunk = self.read(to_read)
|
chunk = self.read(to_read)
|
||||||
|
@ -3493,14 +3493,14 @@ class TestSwiftInfo(unittest.TestCase):
|
|||||||
class TestFileLikeIter(unittest.TestCase):
|
class TestFileLikeIter(unittest.TestCase):
|
||||||
|
|
||||||
def test_iter_file_iter(self):
|
def test_iter_file_iter(self):
|
||||||
in_iter = ['abc', 'de', 'fghijk', 'l']
|
in_iter = [b'abc', b'de', b'fghijk', b'l']
|
||||||
chunks = []
|
chunks = []
|
||||||
for chunk in utils.FileLikeIter(in_iter):
|
for chunk in utils.FileLikeIter(in_iter):
|
||||||
chunks.append(chunk)
|
chunks.append(chunk)
|
||||||
self.assertEqual(chunks, in_iter)
|
self.assertEqual(chunks, in_iter)
|
||||||
|
|
||||||
def test_next(self):
|
def test_next(self):
|
||||||
in_iter = ['abc', 'de', 'fghijk', 'l']
|
in_iter = [b'abc', b'de', b'fghijk', b'l']
|
||||||
chunks = []
|
chunks = []
|
||||||
iter_file = utils.FileLikeIter(in_iter)
|
iter_file = utils.FileLikeIter(in_iter)
|
||||||
while True:
|
while True:
|
||||||
@ -3512,12 +3512,12 @@ class TestFileLikeIter(unittest.TestCase):
|
|||||||
self.assertEqual(chunks, in_iter)
|
self.assertEqual(chunks, in_iter)
|
||||||
|
|
||||||
def test_read(self):
|
def test_read(self):
|
||||||
in_iter = ['abc', 'de', 'fghijk', 'l']
|
in_iter = [b'abc', b'de', b'fghijk', b'l']
|
||||||
iter_file = utils.FileLikeIter(in_iter)
|
iter_file = utils.FileLikeIter(in_iter)
|
||||||
self.assertEqual(iter_file.read(), ''.join(in_iter))
|
self.assertEqual(iter_file.read(), b''.join(in_iter))
|
||||||
|
|
||||||
def test_read_with_size(self):
|
def test_read_with_size(self):
|
||||||
in_iter = ['abc', 'de', 'fghijk', 'l']
|
in_iter = [b'abc', b'de', b'fghijk', b'l']
|
||||||
chunks = []
|
chunks = []
|
||||||
iter_file = utils.FileLikeIter(in_iter)
|
iter_file = utils.FileLikeIter(in_iter)
|
||||||
while True:
|
while True:
|
||||||
@ -3526,14 +3526,15 @@ class TestFileLikeIter(unittest.TestCase):
|
|||||||
break
|
break
|
||||||
self.assertTrue(len(chunk) <= 2)
|
self.assertTrue(len(chunk) <= 2)
|
||||||
chunks.append(chunk)
|
chunks.append(chunk)
|
||||||
self.assertEqual(''.join(chunks), ''.join(in_iter))
|
self.assertEqual(b''.join(chunks), b''.join(in_iter))
|
||||||
|
|
||||||
def test_read_with_size_zero(self):
|
def test_read_with_size_zero(self):
|
||||||
# makes little sense, but file supports it, so...
|
# makes little sense, but file supports it, so...
|
||||||
self.assertEqual(utils.FileLikeIter('abc').read(0), '')
|
self.assertEqual(utils.FileLikeIter(b'abc').read(0), b'')
|
||||||
|
|
||||||
def test_readline(self):
|
def test_readline(self):
|
||||||
in_iter = ['abc\n', 'd', '\nef', 'g\nh', '\nij\n\nk\n', 'trailing.']
|
in_iter = [b'abc\n', b'd', b'\nef', b'g\nh', b'\nij\n\nk\n',
|
||||||
|
b'trailing.']
|
||||||
lines = []
|
lines = []
|
||||||
iter_file = utils.FileLikeIter(in_iter)
|
iter_file = utils.FileLikeIter(in_iter)
|
||||||
while True:
|
while True:
|
||||||
@ -3543,22 +3544,23 @@ class TestFileLikeIter(unittest.TestCase):
|
|||||||
lines.append(line)
|
lines.append(line)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
lines,
|
lines,
|
||||||
[v if v == 'trailing.' else v + '\n'
|
[v if v == b'trailing.' else v + b'\n'
|
||||||
for v in ''.join(in_iter).split('\n')])
|
for v in b''.join(in_iter).split(b'\n')])
|
||||||
|
|
||||||
def test_readline2(self):
|
def test_readline2(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
utils.FileLikeIter(['abc', 'def\n']).readline(4),
|
utils.FileLikeIter([b'abc', b'def\n']).readline(4),
|
||||||
'abcd')
|
b'abcd')
|
||||||
|
|
||||||
def test_readline3(self):
|
def test_readline3(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
utils.FileLikeIter(['a' * 1111, 'bc\ndef']).readline(),
|
utils.FileLikeIter([b'a' * 1111, b'bc\ndef']).readline(),
|
||||||
('a' * 1111) + 'bc\n')
|
(b'a' * 1111) + b'bc\n')
|
||||||
|
|
||||||
def test_readline_with_size(self):
|
def test_readline_with_size(self):
|
||||||
|
|
||||||
in_iter = ['abc\n', 'd', '\nef', 'g\nh', '\nij\n\nk\n', 'trailing.']
|
in_iter = [b'abc\n', b'd', b'\nef', b'g\nh', b'\nij\n\nk\n',
|
||||||
|
b'trailing.']
|
||||||
lines = []
|
lines = []
|
||||||
iter_file = utils.FileLikeIter(in_iter)
|
iter_file = utils.FileLikeIter(in_iter)
|
||||||
while True:
|
while True:
|
||||||
@ -3568,19 +3570,21 @@ class TestFileLikeIter(unittest.TestCase):
|
|||||||
lines.append(line)
|
lines.append(line)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
lines,
|
lines,
|
||||||
['ab', 'c\n', 'd\n', 'ef', 'g\n', 'h\n', 'ij', '\n', '\n', 'k\n',
|
[b'ab', b'c\n', b'd\n', b'ef', b'g\n', b'h\n', b'ij', b'\n', b'\n',
|
||||||
'tr', 'ai', 'li', 'ng', '.'])
|
b'k\n', b'tr', b'ai', b'li', b'ng', b'.'])
|
||||||
|
|
||||||
def test_readlines(self):
|
def test_readlines(self):
|
||||||
in_iter = ['abc\n', 'd', '\nef', 'g\nh', '\nij\n\nk\n', 'trailing.']
|
in_iter = [b'abc\n', b'd', b'\nef', b'g\nh', b'\nij\n\nk\n',
|
||||||
|
b'trailing.']
|
||||||
lines = utils.FileLikeIter(in_iter).readlines()
|
lines = utils.FileLikeIter(in_iter).readlines()
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
lines,
|
lines,
|
||||||
[v if v == 'trailing.' else v + '\n'
|
[v if v == b'trailing.' else v + b'\n'
|
||||||
for v in ''.join(in_iter).split('\n')])
|
for v in b''.join(in_iter).split(b'\n')])
|
||||||
|
|
||||||
def test_readlines_with_size(self):
|
def test_readlines_with_size(self):
|
||||||
in_iter = ['abc\n', 'd', '\nef', 'g\nh', '\nij\n\nk\n', 'trailing.']
|
in_iter = [b'abc\n', b'd', b'\nef', b'g\nh', b'\nij\n\nk\n',
|
||||||
|
b'trailing.']
|
||||||
iter_file = utils.FileLikeIter(in_iter)
|
iter_file = utils.FileLikeIter(in_iter)
|
||||||
lists_of_lines = []
|
lists_of_lines = []
|
||||||
while True:
|
while True:
|
||||||
@ -3590,12 +3594,13 @@ class TestFileLikeIter(unittest.TestCase):
|
|||||||
lists_of_lines.append(lines)
|
lists_of_lines.append(lines)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
lists_of_lines,
|
lists_of_lines,
|
||||||
[['ab'], ['c\n'], ['d\n'], ['ef'], ['g\n'], ['h\n'], ['ij'],
|
[[b'ab'], [b'c\n'], [b'd\n'], [b'ef'], [b'g\n'], [b'h\n'], [b'ij'],
|
||||||
['\n', '\n'], ['k\n'], ['tr'], ['ai'], ['li'], ['ng'], ['.']])
|
[b'\n', b'\n'], [b'k\n'], [b'tr'], [b'ai'], [b'li'], [b'ng'],
|
||||||
|
[b'.']])
|
||||||
|
|
||||||
def test_close(self):
|
def test_close(self):
|
||||||
iter_file = utils.FileLikeIter('abcdef')
|
iter_file = utils.FileLikeIter([b'a', b'b', b'c'])
|
||||||
self.assertEqual(next(iter_file), 'a')
|
self.assertEqual(next(iter_file), b'a')
|
||||||
iter_file.close()
|
iter_file.close()
|
||||||
self.assertTrue(iter_file.closed)
|
self.assertTrue(iter_file.closed)
|
||||||
self.assertRaises(ValueError, iter_file.next)
|
self.assertRaises(ValueError, iter_file.next)
|
||||||
|
Loading…
Reference in New Issue
Block a user