[pypy-svn] r52328 - in pypy/branch/buffer/pypy: lib/_ctypes module/_ssl module/fcntl module/fcntl/test module/marshal module/marshal/test module/mmap module/struct module/struct/test

arigo at codespeak.net arigo at codespeak.net
Sun Mar 9 12:47:07 CET 2008


Author: arigo
Date: Sun Mar  9 12:47:06 2008
New Revision: 52328

Modified:
   pypy/branch/buffer/pypy/lib/_ctypes/basics.py
   pypy/branch/buffer/pypy/module/_ssl/interp_ssl.py
   pypy/branch/buffer/pypy/module/fcntl/interp_fcntl.py
   pypy/branch/buffer/pypy/module/fcntl/test/test_fcntl.py
   pypy/branch/buffer/pypy/module/marshal/interp_marshal.py
   pypy/branch/buffer/pypy/module/marshal/test/test_marshalimpl.py
   pypy/branch/buffer/pypy/module/mmap/interp_mmap.py
   pypy/branch/buffer/pypy/module/struct/interp_struct.py
   pypy/branch/buffer/pypy/module/struct/test/test_struct.py
Log:
Buffer support for various modules.


Modified: pypy/branch/buffer/pypy/lib/_ctypes/basics.py
==============================================================================
--- pypy/branch/buffer/pypy/lib/_ctypes/basics.py	(original)
+++ pypy/branch/buffer/pypy/lib/_ctypes/basics.py	Sun Mar  9 12:47:06 2008
@@ -104,6 +104,9 @@
     def _get_buffer_value(self):
         return self._buffer[0]
 
+    def __buffer__(self):
+        return buffer(self._buffer)
+
 def sizeof(tp):
     if not isinstance(tp, _CDataMeta):
         if isinstance(tp, _CData):

Modified: pypy/branch/buffer/pypy/module/_ssl/interp_ssl.py
==============================================================================
--- pypy/branch/buffer/pypy/module/_ssl/interp_ssl.py	(original)
+++ pypy/branch/buffer/pypy/module/_ssl/interp_ssl.py	Sun Mar  9 12:47:06 2008
@@ -297,7 +297,7 @@
             errstr, errval = _ssl_seterror(self.space, self, num_bytes)
             raise OperationError(self.space.w_Exception,
                 self.space.wrap("%s: %d" % (errstr, errval)))
-    write.unwrap_spec = ['self', str]
+    write.unwrap_spec = ['self', 'bufferstr']
     
     def read(self, num_bytes=1024):
         """read([len]) -> string

Modified: pypy/branch/buffer/pypy/module/fcntl/interp_fcntl.py
==============================================================================
--- pypy/branch/buffer/pypy/module/fcntl/interp_fcntl.py	(original)
+++ pypy/branch/buffer/pypy/module/fcntl/interp_fcntl.py	Sun Mar  9 12:47:06 2008
@@ -82,7 +82,8 @@
 def _conv_descriptor(space, w_f):
     w_conv_descriptor = _get_module_object(space, "_conv_descriptor")
     w_fd = space.call_function(w_conv_descriptor, w_f)
-    return space.int_w(w_fd)
+    fd = space.int_w(w_fd)
+    return rffi.cast(rffi.INT, fd)     # C long => C int
 
 def _check_flock_op(space, op):
 
@@ -107,24 +108,33 @@
     available from the fcntl module.  The argument arg is optional, and
     defaults to 0; it may be an int or a string. If arg is given as a string,
     the return value of fcntl is a string of that length, containing the
-    resulting value put in the arg buffer by the operating system. The length
-    of the arg string is not allowed to exceed 1024 bytes. If the arg given
-    is an integer or if none is specified, the result value is an integer
-    corresponding to the return value of the fcntl call in the C code."""
+    resulting value put in the arg buffer by the operating system. If the
+    arg given is an integer or if none is specified, the result value is an
+    integer corresponding to the return value of the fcntl call in the C code.
+    """
 
     fd = _conv_descriptor(space, w_fd)
-    
-    if space.is_w(space.type(w_arg), space.w_int):
-        rv = fcntl_int(fd, op, space.int_w(w_arg))
+    op = rffi.cast(rffi.INT, op)        # C long => C int
+
+    try:
+        intarg = space.int_w(w_arg)
+    except OperationError, e:
+        if not e.match(space, space.w_TypeError):
+            raise
+    else:
+        intarg = rffi.cast(rffi.INT, intarg)   # C long => C int
+        rv = fcntl_int(fd, op, intarg)
         if rv < 0:
             raise OperationError(space.w_IOError,
                 space.wrap(_get_error_msg()))
         return space.wrap(rv)
-    elif space.is_w(space.type(w_arg), space.w_str):
-        arg = space.str_w(w_arg)
-        if len(arg) > 1024:   # XXX probably makes no sense for PyPy
-            raise OperationError(space.w_ValueError,
-                space.wrap("fcntl string arg too long"))
+
+    try:
+        arg = space.bufferstr_w(w_arg)
+    except OperationError, e:
+        if not e.match(space, space.w_TypeError):
+            raise
+    else:
         ll_arg = rffi.str2charp(arg)
         rv = fcntl_str(fd, op, ll_arg)
         arg = rffi.charpsize2str(ll_arg, len(arg))
@@ -133,9 +143,9 @@
             raise OperationError(space.w_IOError,
                 space.wrap(_get_error_msg()))
         return space.wrap(arg)
-    else:
-        raise OperationError(space.w_TypeError,
-            space.wrap("int or string required"))
+
+    raise OperationError(space.w_TypeError,
+                         space.wrap("int or string or buffer required"))
 fcntl.unwrap_spec = [ObjSpace, W_Root, int, W_Root]
 
 def flock(space, w_fd, op):
@@ -158,6 +168,7 @@
         rffi.setintfield(l, 'c_l_start', 0)
         rffi.setintfield(l, 'c_l_len', 0)
         op = [F_SETLKW, F_SETLK][op & LOCK_NB]
+        op = rffi.cast(rffi.INT, op)        # C long => C int
         fcntl_flock(fd, op, l)
         lltype.free(l, flavor='raw')
 flock.unwrap_spec = [ObjSpace, W_Root, int]
@@ -207,60 +218,63 @@
         except IndexError:
             raise OperationError(space.w_ValueError,
                                  space.wrap("invalid value for operation"))
+        op = rffi.cast(rffi.INT, op)        # C long => C int
         fcntl_flock(fd, op, l)
     finally:
         lltype.free(l, flavor='raw')
 lockf.unwrap_spec = [ObjSpace, W_Root, int, int, int, int]
 
-def ioctl(space, w_fd, op, w_arg=0, mutate_flag=True):
+def ioctl(space, w_fd, op, w_arg=0, mutate_flag=-1):
     """ioctl(fd, opt[, arg[, mutate_flag]])
 
     Perform the requested operation on file descriptor fd.  The operation is
     defined by opt and is operating system dependent.  Typically these codes
     are retrieved from the fcntl or termios library modules.
+    """
+    # removed the largish docstring because it is not in sync with the
+    # documentation any more (even in CPython's docstring is out of date)
 
-    The argument arg is optional, and defaults to 0; it may be an int or a
-    buffer containing character data (most likely a string or an array).
-
-    If the argument is a mutable buffer (such as an array) and if the
-    mutate_flag argument (which is only allowed in this case) is true then the
-    buffer is (in effect) passed to the operating system and changes made by
-    the OS will be reflected in the contents of the buffer after the call has
-    returned.  The return value is the integer returned by the ioctl system
-    call.
-
-    If the argument is a mutable buffer and the mutable_flag argument is not
-    passed or is false, the behavior is as if a string had been passed.  This
-    behavior will change in future releases of Python.
-
-    If the argument is an immutable buffer (most likely a string) then a copy
-    of the buffer is passed to the operating system and the return value is a
-    string of the same length containing whatever the operating system put in
-    the buffer.  The length of the arg buffer in this case is not allowed to
-    exceed 1024 bytes.
-
-    If the arg given is an integer or if none is specified, the result value
-    is an integer corresponding to the return value of the ioctl call in the
-    C code."""
+    # XXX this function's interface is a mess.
+    # We try to emulate the behavior of Python >= 2.5 w.r.t. mutate_flag
+    
     fd = _conv_descriptor(space, w_fd)
-    # Python turns number > sys.maxint into long, we need the signed C value
-    op = rffi.cast(rffi.INT, op)
+    op = rffi.cast(rffi.INT, op)        # C long => C int
 
-    IOCTL_BUFSZ = 1024
-    
-    if space.is_w(space.type(w_arg), space.w_int):
-        arg = space.int_w(w_arg)
-        rv = ioctl_int(fd, op, arg)
-        if rv < 0:
-            raise OperationError(space.w_IOError,
-                space.wrap(_get_error_msg()))
-        return space.wrap(rv)
-    elif space.is_w(space.type(w_arg), space.w_str): # immutable
-        arg = space.str_w(w_arg)
-        if len(arg) > IOCTL_BUFSZ:
-            raise OperationError(space.w_ValueError,
-                space.wrap("ioctl string arg too long"))
-    
+    if mutate_flag != 0:
+        try:
+            rwbuffer = space.rwbuffer_w(w_arg)
+        except OperationError, e:
+            if not e.match(space, space.w_TypeError):
+                raise
+            if mutate_flag > 0:
+                raise
+        else:
+            arg = rwbuffer.as_str()
+            ll_arg = rffi.str2charp(arg)
+            rv = ioctl_str(fd, op, ll_arg)
+            arg = rffi.charpsize2str(ll_arg, len(arg))
+            lltype.free(ll_arg, flavor='raw')
+            if rv < 0:
+                raise OperationError(space.w_IOError,
+                    space.wrap(_get_error_msg()))
+            rwbuffer.setslice(0, arg)
+            return space.wrap(rv)
+
+    try:
+        intarg = space.int_w(w_arg)
+    except OperationError, e:
+        if not e.match(space, space.w_TypeError):
+            raise
+    else:
+        intarg = rffi.cast(rffi.INT, intarg)   # C long => C int
+        rv = ioctl_int(fd, op, intarg)
+
+    try:
+        arg = space.bufferstr_w(w_arg)
+    except OperationError, e:
+        if not e.match(space, space.w_TypeError):
+            raise
+    else:
         ll_arg = rffi.str2charp(arg)
         rv = ioctl_str(fd, op, ll_arg)
         arg = rffi.charpsize2str(ll_arg, len(arg))
@@ -269,29 +283,7 @@
             raise OperationError(space.w_IOError,
                 space.wrap(_get_error_msg()))
         return space.wrap(arg)
-    else:
-        raise OperationError(space.w_TypeError,
-                space.wrap("an integer or a buffer required"))
-        # try:
-        #     # array.array instances
-        #     arg = space.call_method(w_arg, "tostring")
-        #     buf = create_string_buffer(len(arg))
-        # except:
-        #     raise OperationError(space.w_TypeError,
-        #         space.wrap("an integer or a buffer required"))
-        # 
-        # if not mutate_flag:
-        #     if len(arg) > IOCTL_BUFSZ:
-        #         raise OperationError(space.w_ValueError,
-        #             space.wrap("ioctl string arg too long"))
-        # 
-        # rv = ioctl_str(fd, op, buf)
-        # if rv < 0:
-        #     raise OperationError(space.w_IOError,
-        #         space.wrap(_get_error_msg()))
-        # 
-        # if mutate_flag:
-        #     return space.wrap(rv)
-        # else:
-        #     return space.wrap(buf.value)
+
+    raise OperationError(space.w_TypeError,
+                         space.wrap("int or string or buffer required"))
 ioctl.unwrap_spec = [ObjSpace, W_Root, int, W_Root, int]

Modified: pypy/branch/buffer/pypy/module/fcntl/test/test_fcntl.py
==============================================================================
--- pypy/branch/buffer/pypy/module/fcntl/test/test_fcntl.py	(original)
+++ pypy/branch/buffer/pypy/module/fcntl/test/test_fcntl.py	Sun Mar  9 12:47:06 2008
@@ -1,5 +1,6 @@
 from pypy.conftest import gettestobjspace
 import os
+from pypy.tool.udir import udir
 
 if os.name == "nt":
     from py.test import skip
@@ -12,13 +13,17 @@
 
 class AppTestFcntl:
     def setup_class(cls):
-        space = gettestobjspace(usemodules=('fcntl',))
+        space = gettestobjspace(usemodules=('fcntl', 'array'))
         cls.space = space
+        tmpprefix = str(udir.ensure('test_fcntl', dir=1).join('tmp_'))
+        cls.w_tmp = space.wrap(tmpprefix)
 
     def test_conv_descriptor(self):
         import fcntl
+        if not hasattr(fcntl, '_conv_descriptor'):
+            skip("PyPy only")
         
-        f = open("a", "w+")
+        f = open(self.tmp + "a", "w+")
         
         raises(TypeError, fcntl._conv_descriptor, "foo")
         raises(TypeError, fcntl._conv_descriptor, 2.0)
@@ -37,15 +42,16 @@
         import sys
         import struct
         
-        f = open("b", "w+")
+        f = open(self.tmp + "b", "w+")
         
         fcntl.fcntl(f, 1, 0)
         fcntl.fcntl(f, 1)
         raises(TypeError, fcntl.fcntl, "foo")
         raises(TypeError, fcntl.fcntl, f, "foo")
-        raises(IOError, fcntl.fcntl, -1, 1, 0)
+        raises((IOError, ValueError), fcntl.fcntl, -1, 1, 0)
         assert fcntl.fcntl(f, 1, 0) == 0
         assert fcntl.fcntl(f, 2, "foo") == "foo"
+        assert fcntl.fcntl(f, 2, buffer("foo")) == "foo"
         
         try:
             os.O_LARGEFILE
@@ -119,7 +125,7 @@
         import fcntl
         import sys
         
-        f = open("c", "w+")
+        f = open(self.tmp + "c", "w+")
         
         raises(TypeError, fcntl.flock, "foo")
         raises(TypeError, fcntl.flock, f, "foo")
@@ -134,12 +140,12 @@
     def test_lockf(self):
         import fcntl
         
-        f = open("d", "w+")
+        f = open(self.tmp + "d", "w+")
         
         raises(TypeError, fcntl.lockf, f, "foo")
         raises(TypeError, fcntl.lockf, f, fcntl.LOCK_UN, "foo")
-        raises(ValueError, fcntl.lockf, f, -1)
-        raises(ValueError, fcntl.lockf, f, 255)
+        raises(ValueError, fcntl.lockf, f, -256)
+        raises(ValueError, fcntl.lockf, f, 256)
         
         fcntl.lockf(f, fcntl.LOCK_SH)
         fcntl.lockf(f, fcntl.LOCK_UN)
@@ -149,23 +155,39 @@
     def test_ioctl(self):
         import fcntl
         import array
-        import sys
-        
-        f = open("e", "w+")
-        
+        import sys, os
+
         if "linux" in sys.platform:
             TIOCGPGRP = 0x540f
         elif "darwin" in sys.platform or "freebsd6" == sys.platform:
             TIOCGPGRP = 0x40047477
+        else:
+            skip("don't know how to test ioctl() on this platform")
         
         raises(TypeError, fcntl.ioctl, "foo")
-        raises(TypeError, fcntl.ioctl, f, "foo")
-        raises(TypeError, fcntl.ioctl, f, TIOCGPGRP, float(0))
-        raises(TypeError, fcntl.ioctl, f, TIOCGPGRP, 1, "foo")
-
-        # buf = array.array('h', [0])
-        # fcntl.ioctl(0, TIOCGPGRP, buf, True)
-        # buf = array.array('c', "a"*1025)
-        # py.test.raises(ValueError, cfcntl.ioctl, 0, termios.TIOCGPGRP, buf, 0)
-        # py.test.raises(ValueError, cfcntl.ioctl, 0, termios.TIOCGPGRP,
-        #                "a"*1025, 0)
+        raises(TypeError, fcntl.ioctl, 0, "foo")
+        #raises(TypeError, fcntl.ioctl, 0, TIOCGPGRP, float(0))
+        raises(TypeError, fcntl.ioctl, 0, TIOCGPGRP, 1, "foo")
+
+        if not os.isatty(0):
+            skip("stdin is not a tty")
+
+        buf = array.array('h', [0])
+        res = fcntl.ioctl(0, TIOCGPGRP, buf, True)
+        assert res == 0
+        assert buf[0] != 0
+        expected = buf.tostring()
+
+        if '__pypy__' in sys.builtin_module_names or sys.version_info >= (2,5):
+            buf = array.array('h', [0])
+            res = fcntl.ioctl(0, TIOCGPGRP, buf)
+            assert res == 0
+            assert buf.tostring() == expected
+
+        res = fcntl.ioctl(0, TIOCGPGRP, buf, False)
+        assert res == expected
+
+        raises(TypeError, fcntl.ioctl, 0, TIOCGPGRP, "\x00\x00", True)
+
+        res = fcntl.ioctl(0, TIOCGPGRP, "\x00\x00")
+        assert res == expected

Modified: pypy/branch/buffer/pypy/module/marshal/interp_marshal.py
==============================================================================
--- pypy/branch/buffer/pypy/module/marshal/interp_marshal.py	(original)
+++ pypy/branch/buffer/pypy/module/marshal/interp_marshal.py	Sun Mar  9 12:47:06 2008
@@ -503,12 +503,12 @@
     def __init__(self, space, w_str):
         Unmarshaller.__init__(self, space, None)
         try:
-            self.bufstr = space.str_w(w_str)
+            self.bufstr = space.bufferstr_w(w_str)
         except OperationError, e:
             if not e.match(space, space.w_TypeError):
                 raise
             raise OperationError(space.w_TypeError, space.wrap(
-                'marshal.loads() arg must be string'))
+                'marshal.loads() arg must be string or buffer'))
         self.bufpos = 0
         self.limit = len(self.bufstr)
 

Modified: pypy/branch/buffer/pypy/module/marshal/test/test_marshalimpl.py
==============================================================================
--- pypy/branch/buffer/pypy/module/marshal/test/test_marshalimpl.py	(original)
+++ pypy/branch/buffer/pypy/module/marshal/test/test_marshalimpl.py	Sun Mar  9 12:47:06 2008
@@ -20,3 +20,8 @@
         assert z == 10000000000
         z = marshal.loads('I\x00\x1c\xf4\xab\xfd\xff\xff\xff')
         assert z == -10000000000
+
+    def test_buffer(self):
+        import marshal
+        z = marshal.loads(buffer('i\x02\x00\x00\x00???'))
+        assert z == 2

Modified: pypy/branch/buffer/pypy/module/mmap/interp_mmap.py
==============================================================================
--- pypy/branch/buffer/pypy/module/mmap/interp_mmap.py	(original)
+++ pypy/branch/buffer/pypy/module/mmap/interp_mmap.py	Sun Mar  9 12:47:06 2008
@@ -39,7 +39,7 @@
 
     def find(self, tofind, start=0):
         return self.space.wrap(self.mmap.find(tofind, start))
-    find.unwrap_spec = ['self', str, int]
+    find.unwrap_spec = ['self', 'bufferstr', int]
 
     def seek(self, pos, whence=0):
         try:
@@ -64,7 +64,7 @@
         except RValueError, v:
             raise OperationError(self.space.w_ValueError,
                                  self.space.wrap(v.message))
-    write.unwrap_spec = ['self', str]
+    write.unwrap_spec = ['self', 'bufferstr']
     
     def write_byte(self, byte):
         try:
@@ -168,7 +168,7 @@
         else:
             raise OperationError(space.w_ValueError,
                 space.wrap("mmap object does not support slicing with a step"))
-    descr_setitem.unwrap_spec = ['self', W_Root, str]
+    descr_setitem.unwrap_spec = ['self', W_Root, 'bufferstr']
 
     def descr_buffer(self):
         # XXX improve to work directly on the low-level address

Modified: pypy/branch/buffer/pypy/module/struct/interp_struct.py
==============================================================================
--- pypy/branch/buffer/pypy/module/struct/interp_struct.py	(original)
+++ pypy/branch/buffer/pypy/module/struct/interp_struct.py	Sun Mar  9 12:47:06 2008
@@ -34,4 +34,4 @@
     except StructError, e:
         raise e.at_applevel(space)
     return space.newtuple(fmtiter.result_w)
-unpack.unwrap_spec = [ObjSpace, str, str]
+unpack.unwrap_spec = [ObjSpace, str, 'bufferstr']

Modified: pypy/branch/buffer/pypy/module/struct/test/test_struct.py
==============================================================================
--- pypy/branch/buffer/pypy/module/struct/test/test_struct.py	(original)
+++ pypy/branch/buffer/pypy/module/struct/test/test_struct.py	Sun Mar  9 12:47:06 2008
@@ -335,6 +335,15 @@
         assert self.struct.unpack("uuu", data) == (u'X', u'Y', u'Z')
 
 
+    def test_unpack_buffer(self):
+        """
+        Buffer objects can be passed to struct.unpack().
+        """
+        b = buffer(self.struct.pack("ii", 62, 12))
+        assert self.struct.unpack("ii", b) == (62, 12)
+        raises(self.struct.error, self.struct.unpack, "i", b)
+
+
 class AppTestStructBuffer(object):
 
     def setup_class(cls):



More information about the Pypy-commit mailing list