Author: David Schneider <david.schnei...@picle.org> Branch: Changeset: r63267:6ed5e557b6b1 Date: 2013-04-12 09:13 +0200 http://bitbucket.org/pypy/pypy/changeset/6ed5e557b6b1/
Log: merge heads diff --git a/pypy/module/_io/interp_bytesio.py b/pypy/module/_io/interp_bytesio.py --- a/pypy/module/_io/interp_bytesio.py +++ b/pypy/module/_io/interp_bytesio.py @@ -2,37 +2,25 @@ TypeDef, generic_new_descr, GetSetProperty) from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.error import OperationError, operationerrfmt +from rpython.rlib.rStringIO import RStringIO from rpython.rlib.rarithmetic import r_longlong from pypy.module._io.interp_bufferedio import W_BufferedIOBase from pypy.module._io.interp_iobase import convert_size import sys -def buffer2string(buffer, start, end): - from rpython.rlib.rstring import StringBuilder - builder = StringBuilder(end - start) - for i in range(start, end): - builder.append(buffer[i]) - return builder.build() -class W_BytesIO(W_BufferedIOBase): +class W_BytesIO(RStringIO, W_BufferedIOBase): def __init__(self, space): W_BufferedIOBase.__init__(self, space) - self.pos = 0 - self.string_size = 0 - self.buf = None + self.init() def descr_init(self, space, w_initial_bytes=None): - # In case __init__ is called multiple times - self.buf = [] - self.string_size = 0 - self.pos = 0 - if not space.is_none(w_initial_bytes): self.write_w(space, w_initial_bytes) - self.pos = 0 + self.seek(0) def _check_closed(self, space, message=None): - if self.buf is None: + if self.is_closed(): if message is None: message = "I/O operation on closed file" raise OperationError(space.w_ValueError, space.wrap(message)) @@ -40,36 +28,12 @@ def read_w(self, space, w_size=None): self._check_closed(space) size = convert_size(space, w_size) - - # adjust invalid sizes - available = self.string_size - self.pos - if not 0 <= size <= available: - size = available - if size < 0: - size = 0 - - output = buffer2string(self.buf, self.pos, self.pos + size) - self.pos += size - return space.wrap(output) + return space.wrap(self.read(size)) def readline_w(self, space, w_limit=None): self._check_closed(space) limit = convert_size(space, w_limit) - - cur_pos = self.pos - if limit < 0: - end_pos = self.string_size - else: - end_pos = min(cur_pos + limit, self.string_size) - while cur_pos != end_pos: - if self.buf[cur_pos] == '\n': - cur_pos += 1 - break - cur_pos += 1 - - output = buffer2string(self.buf, self.pos, cur_pos) - self.pos = cur_pos - return space.wrap(output) + return space.wrap(self.readline(limit)) def read1_w(self, space, w_size): return self.read_w(space, w_size) @@ -79,56 +43,28 @@ rwbuffer = space.rwbuffer_w(w_buffer) size = rwbuffer.getlength() - if self.pos + size > self.string_size: - size = self.string_size - self.pos - - output = buffer2string(self.buf, self.pos, self.pos + size) - length = len(output) + output = self.read(size) rwbuffer.setslice(0, output) - self.pos += length - return space.wrap(length) + return space.wrap(len(output)) def write_w(self, space, w_data): self._check_closed(space) if space.isinstance_w(w_data, space.w_unicode): raise OperationError(space.w_TypeError, space.wrap( "bytes string of buffer expected")) - buf = space.buffer_w(w_data) - length = buf.getlength() + buf = space.bufferstr_w(w_data) + length = len(buf) if length <= 0: - return - - if self.pos + length > len(self.buf): - self.buf.extend(['\0'] * (self.pos + length - len(self.buf))) - - if self.pos > self.string_size: - # In case of overseek, pad with null bytes the buffer region - # between the end of stream and the current position. - # - # 0 lo string_size hi - # | |<---used--->|<----------available----------->| - # | | <--to pad-->|<---to write---> | - # 0 buf position - for i in range(self.string_size, self.pos): - self.buf[i] = '\0' - - # Copy the data to the internal buffer, overwriting some of the - # existing data if self->pos < self->string_size. - for i in range(length): - self.buf[self.pos + i] = buf.getitem(i) - self.pos += length - - # Set the new length of the internal string if it has changed - if self.string_size < self.pos: - self.string_size = self.pos - + return space.wrap(0) + self.write(buf) return space.wrap(length) def truncate_w(self, space, w_size=None): self._check_closed(space) + pos = self.tell() if space.is_none(w_size): - size = self.pos + size = pos else: size = space.r_longlong_w(w_size) @@ -136,19 +72,17 @@ raise OperationError(space.w_ValueError, space.wrap( "negative size value")) - if size < self.string_size: - self.string_size = size - del self.buf[size:] - + self.truncate(size) + self.seek(pos) return space.wrap(size) def getvalue_w(self, space): self._check_closed(space) - return space.wrap(buffer2string(self.buf, 0, self.string_size)) + return space.wrap(self.getvalue()) def tell_w(self, space): self._check_closed(space) - return space.wrap(self.pos) + return space.wrap(self.tell()) @unwrap_spec(pos=r_longlong, whence=int) def seek_w(self, space, pos, whence=0): @@ -159,24 +93,19 @@ raise OperationError(space.w_ValueError, space.wrap( "negative seek value")) elif whence == 1: - if pos > sys.maxint - self.pos: + if pos > sys.maxint - self.tell(): raise OperationError(space.w_OverflowError, space.wrap( "new position too large")) - pos += self.pos elif whence == 2: - if pos > sys.maxint - self.string_size: + if pos > sys.maxint - self.getsize(): raise OperationError(space.w_OverflowError, space.wrap( "new position too large")) - pos += self.string_size else: raise operationerrfmt(space.w_ValueError, "whence must be between 0 and 2, not %d", whence) - if pos >= 0: - self.pos = pos - else: - self.pos = 0 - return space.wrap(self.pos) + self.seek(pos, whence) + return space.wrap(self.tell()) def readable_w(self, space): return space.w_True @@ -188,17 +117,16 @@ return space.w_True def close_w(self, space): - self.buf = None + self.close() def closed_get_w(self, space): - return space.wrap(self.buf is None) + return space.wrap(self.is_closed()) def getstate_w(self, space): self._check_closed(space) - w_content = space.wrap(buffer2string(self.buf, 0, self.string_size)) return space.newtuple([ - w_content, - space.wrap(self.pos), + space.wrap(self.getvalue()), + space.wrap(self.tell()), self.getdict(space)]) def setstate_w(self, space, w_state): @@ -211,13 +139,13 @@ space.type(w_state).getname(space) ) w_content, w_pos, w_dict = space.unpackiterable(w_state, 3) + self.truncate(0) + self.write_w(space, w_content) pos = space.int_w(w_pos) - self.buf = [] - self.write_w(space, w_content) if pos < 0: raise OperationError(space.w_ValueError, space.wrap( "position value cannot be negative")) - self.pos = pos + self.seek(pos) if not space.is_w(w_dict, space.w_None): space.call_method(self.getdict(space), "update", w_dict) diff --git a/pypy/module/_io/interp_stringio.py b/pypy/module/_io/interp_stringio.py --- a/pypy/module/_io/interp_stringio.py +++ b/pypy/module/_io/interp_stringio.py @@ -169,9 +169,9 @@ self.pos = end return space.wrap(u''.join(self.buf[start:end])) - @unwrap_spec(limit=int) - def readline_w(self, space, limit=-1): + def readline_w(self, space, w_limit=None): self._check_closed(space) + limit = convert_size(space, w_limit) if self.pos >= len(self.buf): return space.wrap(u"") diff --git a/pypy/module/_io/test/test_bytesio.py b/pypy/module/_io/test/test_bytesio.py --- a/pypy/module/_io/test/test_bytesio.py +++ b/pypy/module/_io/test/test_bytesio.py @@ -24,6 +24,7 @@ def test_write(self): import _io f = _io.BytesIO() + assert f.write("") == 0 assert f.write("hello") == 5 import gc; gc.collect() assert f.getvalue() == "hello" @@ -47,10 +48,17 @@ def test_truncate(self): import _io - f = _io.BytesIO("hello") + f = _io.BytesIO() + f.write("hello") + assert f.truncate(0) == 0 + assert f.tell() == 5 + f.seek(0) + f.write("hello") f.seek(3) assert f.truncate() == 3 assert f.getvalue() == "hel" + assert f.truncate(2) == 2 + assert f.tell() == 3 def test_setstate(self): # state is (content, position, __dict__) @@ -73,7 +81,13 @@ import _io b = _io.BytesIO("hello") + a1 = bytearray('t') + a2 = bytearray('testing') + assert b.readinto(a1) == 1 + assert b.readinto(a2) == 4 b.close() + assert a1 == "h" + assert a2 == "elloing" raises(ValueError, b.readinto, bytearray("hello")) def test_readline(self): diff --git a/pypy/module/_io/test/test_stringio.py b/pypy/module/_io/test/test_stringio.py --- a/pypy/module/_io/test/test_stringio.py +++ b/pypy/module/_io/test/test_stringio.py @@ -32,7 +32,7 @@ raises(ValueError, sio.read, 1) raises(ValueError, sio.write, u"text") - def testRead(self): + def test_read(self): import io buf = u"1234567890" sio = io.StringIO(buf) @@ -42,6 +42,13 @@ assert buf[5:] == sio.read(900) assert u"" == sio.read() + def test_readline(self): + import io + sio = io.StringIO(u'123\n456') + assert sio.readline(2) == '12' + assert sio.readline(None) == '3\n' + assert sio.readline() == '456' + def test_seek(self): import io diff --git a/pypy/module/cStringIO/interp_stringio.py b/pypy/module/cStringIO/interp_stringio.py --- a/pypy/module/cStringIO/interp_stringio.py +++ b/pypy/module/cStringIO/interp_stringio.py @@ -146,7 +146,7 @@ class W_OutputType(RStringIO, W_InputOutputType): def __init__(self, space): - RStringIO.__init__(self) + self.init() self.space = space def descr_truncate(self, w_size=None): @@ -159,6 +159,7 @@ if size < 0: raise OperationError(space.w_IOError, space.wrap("negative size")) self.truncate(size) + self.seek(0, 2) @unwrap_spec(buffer='bufferstr') def descr_write(self, buffer): diff --git a/pypy/module/cStringIO/test/test_interp_stringio.py b/pypy/module/cStringIO/test/test_interp_stringio.py --- a/pypy/module/cStringIO/test/test_interp_stringio.py +++ b/pypy/module/cStringIO/test/test_interp_stringio.py @@ -142,8 +142,11 @@ f.write(' world') f.truncate(30) assert f.getvalue() == '\x00' * 20 + 'hello worl' + assert f.tell() == 30 + f.seek(0) f.truncate(25) assert f.getvalue() == '\x00' * 20 + 'hello' + assert f.tell() == 25 f.write('baz') f.write('egg') f.truncate(3) diff --git a/rpython/rlib/rStringIO.py b/rpython/rlib/rStringIO.py --- a/rpython/rlib/rStringIO.py +++ b/rpython/rlib/rStringIO.py @@ -11,167 +11,166 @@ _mixin_ = True # for interp_stringio.py def __init__(self): + self.init() + + def init(self): # The real content is the join of the following data: - # * the list of characters self.bigbuffer; - # * each of the strings in self.strings. + # * the list of characters self.__bigbuffer; + # * each of the strings in self.__strings. # - self.closed = False - self.strings = None - self.bigbuffer = None - self.pos = AT_END + self.__closed = False + self.__strings = None + self.__bigbuffer = None + self.__pos = AT_END def close(self): - self.closed = True - self.strings = None - self.bigbuffer = None - self.pos = AT_END + self.__closed = True + self.__strings = None + self.__bigbuffer = None + self.__pos = AT_END def is_closed(self): - return self.closed + return self.__closed - def _copy_into_bigbuffer(self): - """Copy all the data into the list of characters self.bigbuffer.""" - if self.bigbuffer is None: - self.bigbuffer = [] - if self.strings is not None: - self.bigbuffer += self.strings.build() - self.strings = None + def __copy_into_bigbuffer(self): + """Copy all the data into the list of characters self.__bigbuffer.""" + if self.__bigbuffer is None: + self.__bigbuffer = [] + if self.__strings is not None: + self.__bigbuffer += self.__strings.build() + self.__strings = None def getvalue(self): - """If self.strings contains more than 1 string, join all the + """If self.__strings contains more than 1 string, join all the strings together. Return the final single string.""" - if self.bigbuffer is not None: - self._copy_into_bigbuffer() - return ''.join(self.bigbuffer) - if self.strings is not None: - return self.strings.build() + if self.__bigbuffer is not None: + self.__copy_into_bigbuffer() + return ''.join(self.__bigbuffer) + if self.__strings is not None: + return self.__strings.build() return '' def getsize(self): result = 0 - if self.bigbuffer is not None: - result += len(self.bigbuffer) - if self.strings is not None: - result += self.strings.getlength() + if self.__bigbuffer is not None: + result += len(self.__bigbuffer) + if self.__strings is not None: + result += self.__strings.getlength() return result def write(self, buffer): # Idea: for the common case of a sequence of write() followed - # by only getvalue(), self.bigbuffer remains empty. It is only + # by only getvalue(), self.__bigbuffer remains empty. It is only # used to handle the more complicated cases. - if self.pos == AT_END: - self._fast_write(buffer) + if self.__pos == AT_END: + self.__fast_write(buffer) else: - self._slow_write(buffer) + self.__slow_write(buffer) - def _fast_write(self, buffer): - if self.strings is None: - self.strings = StringBuilder() - self.strings.append(buffer) + def __fast_write(self, buffer): + if self.__strings is None: + self.__strings = StringBuilder() + self.__strings.append(buffer) - def _slow_write(self, buffer): - p = self.pos + def __slow_write(self, buffer): + p = self.__pos assert p >= 0 endp = p + len(buffer) - if self.bigbuffer is not None and len(self.bigbuffer) >= endp: - # semi-fast path: the write is entirely inside self.bigbuffer + if self.__bigbuffer is not None and len(self.__bigbuffer) >= endp: + # semi-fast path: the write is entirely inside self.__bigbuffer for i in range(len(buffer)): - self.bigbuffer[p + i] = buffer[i] + self.__bigbuffer[p + i] = buffer[i] else: - # slow path: collect all data into self.bigbuffer and + # slow path: collect all data into self.__bigbuffer and # handle the various cases - self._copy_into_bigbuffer() - fitting = len(self.bigbuffer) - p + self.__copy_into_bigbuffer() + fitting = len(self.__bigbuffer) - p if fitting > 0: # the write starts before the end of the data fitting = min(len(buffer), fitting) for i in range(fitting): - self.bigbuffer[p + i] = buffer[i] + self.__bigbuffer[p + i] = buffer[i] if len(buffer) > fitting: # the write extends beyond the end of the data - self.bigbuffer += buffer[fitting:] + self.__bigbuffer += buffer[fitting:] endp = AT_END else: # the write starts at or beyond the end of the data - self.bigbuffer += '\x00' * (-fitting) + buffer + self.__bigbuffer += '\x00' * (-fitting) + buffer endp = AT_END - self.pos = endp + self.__pos = endp def seek(self, position, mode=0): if mode == 1: - if self.pos == AT_END: - self.pos = self.getsize() - position += self.pos + if self.__pos == AT_END: + self.__pos = self.getsize() + position += self.__pos elif mode == 2: if position == 0: - self.pos = AT_END + self.__pos = AT_END return position += self.getsize() if position < 0: position = 0 - self.pos = position + self.__pos = position def tell(self): - if self.pos == AT_END: + if self.__pos == AT_END: result = self.getsize() else: - result = self.pos + result = self.__pos assert result >= 0 return result def read(self, n=-1): - p = self.pos + p = self.__pos if p == 0 and n < 0: - self.pos = AT_END + self.__pos = AT_END return self.getvalue() # reading everything if p == AT_END or n == 0: return '' assert p >= 0 - self._copy_into_bigbuffer() - mysize = len(self.bigbuffer) + self.__copy_into_bigbuffer() + mysize = len(self.__bigbuffer) count = mysize - p if n >= 0: count = min(n, count) if count <= 0: return '' if p == 0 and count == mysize: - self.pos = AT_END - return ''.join(self.bigbuffer) + self.__pos = AT_END + return ''.join(self.__bigbuffer) else: - self.pos = p + count - return ''.join(self.bigbuffer[p:p+count]) + self.__pos = p + count + return ''.join(self.__bigbuffer[p:p+count]) def readline(self, size=-1): - p = self.pos + p = self.__pos if p == AT_END or size == 0: return '' assert p >= 0 - self._copy_into_bigbuffer() - end = len(self.bigbuffer) + self.__copy_into_bigbuffer() + end = len(self.__bigbuffer) if size >= 0 and size < end - p: end = p + size i = p while i < end: - finished = self.bigbuffer[i] == '\n' + finished = self.__bigbuffer[i] == '\n' i += 1 if finished: break - self.seek(i) - return ''.join(self.bigbuffer[p:i]) + self.__pos = i + return ''.join(self.__bigbuffer[p:i]) def truncate(self, size): - # NB. 'size' is mandatory. This has the same un-Posix-y semantics - # than CPython: it never grows the buffer, and it sets the current - # position to the end. assert size >= 0 - if self.bigbuffer is None or size > len(self.bigbuffer): - self._copy_into_bigbuffer() + if self.__bigbuffer is None or size > len(self.__bigbuffer): + self.__copy_into_bigbuffer() else: # we can drop all extra strings - if self.strings is not None: - self.strings = None - if size < len(self.bigbuffer): - del self.bigbuffer[size:] - if len(self.bigbuffer) == 0: - self.bigbuffer = None - self.pos = AT_END + if self.__strings is not None: + self.__strings = None + if size < len(self.__bigbuffer): + del self.__bigbuffer[size:] + if len(self.__bigbuffer) == 0: + self.__bigbuffer = None diff --git a/rpython/rtyper/rlist.py b/rpython/rtyper/rlist.py --- a/rpython/rtyper/rlist.py +++ b/rpython/rtyper/rlist.py @@ -950,6 +950,7 @@ count = l2.ll_length() ll_assert(start >= 0, "l[start:x] = l with unexpectedly negative start") ll_assert(start <= l1.ll_length(), "l[start:x] = l with start > len(l)") + ll_assert(stop <= l1.ll_length(), "stop cannot be past the end of l1") ll_assert(count == stop - start, "setslice cannot resize lists in RPython") # XXX ...but it would be easy enough to support if really needed _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit