[pypy-commit] pypy py3.6: hg merge py3.5

rlamy pypy.commits at gmail.com
Sat Sep 1 09:58:43 EDT 2018


Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: py3.6
Changeset: r95059:3101fec75c3f
Date: 2018-09-01 15:57 +0200
http://bitbucket.org/pypy/pypy/changeset/3101fec75c3f/

Log:	hg merge py3.5

diff --git a/lib_pypy/_ctypes/array.py b/lib_pypy/_ctypes/array.py
--- a/lib_pypy/_ctypes/array.py
+++ b/lib_pypy/_ctypes/array.py
@@ -189,6 +189,7 @@
             self._buffer = self._ffiarray(self._length_, autofree=True)
         for i, arg in enumerate(args):
             self[i] = arg
+    _init_no_arg_ = __init__
 
     def _fix_index(self, index):
         if index < 0:
diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py
--- a/lib_pypy/_ctypes/basics.py
+++ b/lib_pypy/_ctypes/basics.py
@@ -110,7 +110,7 @@
             raise ValueError(
                 "Buffer size too small (%d instead of at least %d bytes)"
                 % (buf.nbytes, offset + size))
-        result = self()
+        result = self._newowninstance_()
         dest = result._buffer.buffer
         try:
             raw_addr = buf._pypy_raw_address() + offset
@@ -121,6 +121,11 @@
             memmove(dest, raw_addr, size)
         return result
 
+    def _newowninstance_(self):
+        result = self.__new__(self)
+        result._init_no_arg_()
+        return result
+
 
 class CArgObject(object):
     """ simple wrapper around buffer, just for the case of freeing
@@ -151,6 +156,7 @@
 
     def __init__(self, *args, **kwds):
         raise TypeError("%s has no type" % (type(self),))
+    _init_no_arg_ = __init__
 
     def _ensure_objects(self):
         if '_objects' not in self.__dict__:
diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py
--- a/lib_pypy/_ctypes/function.py
+++ b/lib_pypy/_ctypes/function.py
@@ -267,6 +267,7 @@
             return
 
         raise TypeError("Unknown constructor %s" % (args,))
+    _init_no_arg_ = __init__
 
     def _wrap_callable(self, to_call, argtypes):
         def f(*args):
@@ -557,7 +558,7 @@
                         keepalive, newarg, newargtype = self._conv_param(argtype, defval)
                     else:
                         import ctypes
-                        val = argtype._type_()
+                        val = argtype._type_._newowninstance_()
                         keepalive = None
                         newarg = ctypes.byref(val)
                         newargtype = type(newarg)
diff --git a/lib_pypy/_ctypes/pointer.py b/lib_pypy/_ctypes/pointer.py
--- a/lib_pypy/_ctypes/pointer.py
+++ b/lib_pypy/_ctypes/pointer.py
@@ -67,8 +67,11 @@
                 self._buffer = ffiarray(1, autofree=True)
             if value is not None:
                 self.contents = value
+        def _init_no_arg_(self):
+            self._buffer = ffiarray(1, autofree=True)
         self._ffiarray = ffiarray
         self.__init__ = __init__
+        self._init_no_arg_ = _init_no_arg_
         self._type_ = TP
 
     def _build_ffiargtype(self):
@@ -136,27 +139,21 @@
     if not (isinstance(tp, _CDataMeta) and tp._is_pointer_like()):
         raise TypeError("cast() argument 2 must be a pointer type, not %s"
                         % (tp,))
+    result = tp._newowninstance_()
     if isinstance(obj, int):
-        result = tp()
         result._buffer[0] = obj
         return result
     elif obj is None:
-        result = tp()
         return result
     elif isinstance(obj, Array):
-        ptr = tp.__new__(tp)
-        ptr._buffer = tp._ffiarray(1, autofree=True)
-        ptr._buffer[0] = obj._buffer
-        result = ptr
+        result._buffer[0] = obj._buffer
     elif isinstance(obj, bytes):
-        result = tp()
         result._buffer[0] = memoryview(obj)._pypy_raw_address()
         return result
     elif not (isinstance(obj, _CData) and type(obj)._is_pointer_like()):
         raise TypeError("cast() argument 1 must be a pointer, not %s"
                         % (type(obj),))
     else:
-        result = tp()
         result._buffer[0] = obj._buffer[0]
 
     # The casted objects '_objects' member:
diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py
--- a/lib_pypy/_ctypes/primitive.py
+++ b/lib_pypy/_ctypes/primitive.py
@@ -378,11 +378,14 @@
             self._buffer = self._ffiarray(1, autofree=True)
         if value is not DEFAULT_VALUE:
             self.value = value
+    _init_no_arg_ = __init__
 
     def _ensure_objects(self):
-        if self._type_ not in 'zZP':
-            assert self._objects is None
-        return self._objects
+        # No '_objects' is the common case for primitives.  Examples
+        # where there is an _objects is if _type in 'zZP', or if
+        # self comes from 'from_buffer(buf)'.  See module/test_lib_pypy/
+        # ctypes_test/test_buffers.py: test_from_buffer_keepalive.
+        return getattr(self, '_objects', None)
 
     def _getvalue(self):
         return self._buffer[0]
diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py
--- a/lib_pypy/_ctypes/structure.py
+++ b/lib_pypy/_ctypes/structure.py
@@ -280,6 +280,7 @@
             self.__setattr__(name, arg)
         for name, arg in kwds.items():
             self.__setattr__(name, arg)
+    _init_no_arg_ = __init__
 
     def _subarray(self, fieldtype, name):
         """Return a _rawffi array of length 1 whose address is the same as
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_buffers.py b/pypy/module/test_lib_pypy/ctypes_tests/test_buffers.py
--- a/pypy/module/test_lib_pypy/ctypes_tests/test_buffers.py
+++ b/pypy/module/test_lib_pypy/ctypes_tests/test_buffers.py
@@ -34,6 +34,15 @@
         assert b.value in (1684234849,   # little endian
                            1633837924)   # big endian
 
+    def test_from_buffer_keepalive(self):
+        # Issue #2878
+        b1 = bytearray("ab")
+        array = (c_uint16 * 32)()
+        array[6] = c_uint16.from_buffer(b1)
+        # this is also what we get on CPython.  I don't think it makes
+        # sense because the array contains just a copy of the number.
+        assert array._objects == {'6': b1}
+
     try:
         c_wchar
     except NameError:
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py
--- a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py
+++ b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py
@@ -498,6 +498,22 @@
                 assert dostruct(Native) == dostruct(Big)
                 assert dostruct(Native) != dostruct(Little)
 
+    def test_from_buffer_copy(self):
+        from array import array
+
+        class S(Structure):
+            _fields_ = [('i', c_int)]
+            def __init__(self, some, unused, arguments):
+                pass
+        a = array('i', [1234567])
+        s1 = S.from_buffer(a)
+        s2 = S.from_buffer_copy(a)
+        assert s1.i == 1234567
+        assert s2.i == 1234567
+        a[0] = -7654321
+        assert s1.i == -7654321
+        assert s2.i == 1234567
+
 
 class TestPointerMember(BaseCTypesTestChecker):
     def test_1(self):
diff --git a/rpython/rlib/rstring.py b/rpython/rlib/rstring.py
--- a/rpython/rlib/rstring.py
+++ b/rpython/rlib/rstring.py
@@ -464,6 +464,10 @@
             raise InvalidBaseError("%s() base must be >= 2 and <= 36" % fname)
         self.base = base
 
+        # Leading underscores are not allowed
+        if s.startswith('_'):
+            self.error()
+
         if base == 16 and (s.startswith('0x') or s.startswith('0X')):
             s = s[2:]
         if base == 8 and (s.startswith('0o') or s.startswith('0O')):
diff --git a/rpython/rlib/test/test_rarithmetic.py b/rpython/rlib/test/test_rarithmetic.py
--- a/rpython/rlib/test/test_rarithmetic.py
+++ b/rpython/rlib/test/test_rarithmetic.py
@@ -554,50 +554,52 @@
             py.test.raises(ParseStringError, string_to_int, '+'+s, base)
             py.test.raises(ParseStringError, string_to_int, '-'+s, base)
 
-    def test_number_underscores(self):
-        VALID_UNDERSCORE_LITERALS = [
-            '0_0_0',
-            '4_2',
-            '1_0000_0000',
-            '0b1001_0100',
-            '0xfff_ffff',
-            '0o5_7_7',
-            '0b_0',
-            '0x_f',
-            '0o_5',
-        ]
-        INVALID_UNDERSCORE_LITERALS = [
-            # Trailing underscores:
-            '0_',
-            '42_',
-            '1.4j_',
-            '0x_',
-            '0b1_',
-            '0xf_',
-            '0o5_',
-            # Underscores in the base selector:
-            '0_b0',
-            '0_xf',
-            '0_o5',
-            # Old-style octal, still disallowed:
-            '09_99',
-            # Multiple consecutive underscores:
-            '4_______2',
-            '0b1001__0100',
-            '0xfff__ffff',
-            '0x___',
-            '0o5__77',
-            '1e1__0',
-        ]
-        for x in VALID_UNDERSCORE_LITERALS:
-            print x
-            y = string_to_int(x, base=0, allow_underscores=True,
-                              no_implicit_octal=True)
-            assert y == int(x.replace('_', ''), base=0)
-        for x in INVALID_UNDERSCORE_LITERALS:
-            print x
-            py.test.raises(ParseStringError, string_to_int, x, base=0,
-                           allow_underscores=True)
+    @py.test.mark.parametrize('s', [
+        '0_0_0',
+        '4_2',
+        '1_0000_0000',
+        '0b1001_0100',
+        '0xfff_ffff',
+        '0o5_7_7',
+        '0b_0',
+        '0x_f',
+        '0o_5',
+    ])
+    def test_valid_underscores(self, s):
+        result = string_to_int(
+            s, base=0, allow_underscores=True, no_implicit_octal=True)
+        assert result == int(s.replace('_', ''), base=0)
+
+    @py.test.mark.parametrize('s', [
+        # Leading underscores
+        '_100',
+        '_',
+        '_0b1001_0100',
+        # Trailing underscores:
+        '0_',
+        '42_',
+        '1.4j_',
+        '0x_',
+        '0b1_',
+        '0xf_',
+        '0o5_',
+        # Underscores in the base selector:
+        '0_b0',
+        '0_xf',
+        '0_o5',
+        # Old-style octal, still disallowed:
+        '09_99',
+        # Multiple consecutive underscores:
+        '4_______2',
+        '0b1001__0100',
+        '0xfff__ffff',
+        '0x___',
+        '0o5__77',
+        '1e1__0',
+    ])
+    def test_invalid_underscores(self, s):
+        with py.test.raises(ParseStringError):
+            string_to_int(s, base=0, allow_underscores=True)
 
     def test_no_implicit_octal(self):
         TESTS = ['00', '000', '00_00', '02', '0377', '02_34']


More information about the pypy-commit mailing list