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

Reply via email to