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

rlamy pypy.commits at gmail.com
Mon Aug 28 17:52:53 EDT 2017


Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: multiphase
Changeset: r92276:fdd1b3877173
Date: 2017-08-28 18:33 +0100
http://bitbucket.org/pypy/pypy/changeset/fdd1b3877173/

Log:	hg merge py3.5

diff --git a/lib-python/2.7/ctypes/__init__.py b/lib-python/2.7/ctypes/__init__.py
--- a/lib-python/2.7/ctypes/__init__.py
+++ b/lib-python/2.7/ctypes/__init__.py
@@ -361,17 +361,20 @@
 
         if handle is None:
             if flags & _FUNCFLAG_CDECL:
-                self._handle = _ffi.CDLL(name, mode)
+                pypy_dll = _ffi.CDLL(name, mode)
             else:
-                self._handle = _ffi.WinDLL(name, mode)
-        else:
-            self._handle = handle
+                pypy_dll = _ffi.WinDLL(name, mode)
+            self.__pypy_dll__ = pypy_dll
+            handle = int(pypy_dll)
+            if _sys.maxint > 2 ** 32:
+                handle = int(handle)   # long -> int
+        self._handle = handle
 
     def __repr__(self):
-        return "<%s '%s', handle %r at 0x%x>" % (
-            self.__class__.__name__, self._name, self._handle,
-            id(self) & (_sys.maxint * 2 + 1))
-
+        return "<%s '%s', handle %x at %x>" % \
+               (self.__class__.__name__, self._name,
+                (self._handle & (_sys.maxint*2 + 1)),
+                id(self) & (_sys.maxint*2 + 1))
 
     def __getattr__(self, name):
         if name.startswith('__') and name.endswith('__'):
diff --git a/lib-python/3/ctypes/__init__.py b/lib-python/3/ctypes/__init__.py
--- a/lib-python/3/ctypes/__init__.py
+++ b/lib-python/3/ctypes/__init__.py
@@ -346,16 +346,18 @@
 
         if handle is None:
             if flags & _FUNCFLAG_CDECL:
-                self._handle = _ffi.CDLL(name, mode)
+                pypy_dll = _ffi.CDLL(name, mode)
             else:
-                self._handle = _ffi.WinDLL(name, mode)
-        else:
-            self._handle = handle
+                pypy_dll = _ffi.WinDLL(name, mode)
+            self.__pypy_dll__ = pypy_dll
+            handle = int(pypy_dll)
+        self._handle = handle
 
     def __repr__(self):
-        return "<%s '%s', handle %r at 0x%x>" % (
-            self.__class__.__name__, self._name, self._handle,
-            id(self) & (_sys.maxsize * 2 + 1))
+        return "<%s '%s', handle %x at 0x%x>" % \
+               (self.__class__.__name__, self._name,
+                (self._handle & (_sys.maxsize*2 + 1)),
+                id(self) & (_sys.maxsize*2 + 1))
 
     def __getattr__(self, name):
         if name.startswith('__') and name.endswith('__'):
diff --git a/lib-python/3/datetime.py b/lib-python/3/datetime.py
--- a/lib-python/3/datetime.py
+++ b/lib-python/3/datetime.py
@@ -810,7 +810,8 @@
             month = self._month
         if day is None:
             day = self._day
-        return date(year, month, day)
+        # PyPy fix: returns type(self)() instead of date()
+        return type(self)(year, month, day)
 
     # Comparisons of date objects with other.
 
@@ -1285,7 +1286,8 @@
             microsecond = self.microsecond
         if tzinfo is True:
             tzinfo = self.tzinfo
-        return time(hour, minute, second, microsecond, tzinfo)
+        # PyPy fix: returns type(self)() instead of time()
+        return type(self)(hour, minute, second, microsecond, tzinfo)
 
     # Pickle support.
 
@@ -1497,7 +1499,8 @@
             microsecond = self.microsecond
         if tzinfo is True:
             tzinfo = self.tzinfo
-        return datetime(year, month, day, hour, minute, second, microsecond,
+        # PyPy fix: returns type(self)() instead of datetime()
+        return type(self)(year, month, day, hour, minute, second, microsecond,
                         tzinfo)
 
     def astimezone(self, tz=None):
diff --git a/lib-python/3/test/test_sysconfig.py b/lib-python/3/test/test_sysconfig.py
--- a/lib-python/3/test/test_sysconfig.py
+++ b/lib-python/3/test/test_sysconfig.py
@@ -397,9 +397,16 @@
             self.assertTrue('linux' in suffix, suffix)
         if re.match('(i[3-6]86|x86_64)$', machine):
             if ctypes.sizeof(ctypes.c_char_p()) == 4:
-                self.assertTrue(suffix.endswith('i386-linux-gnu.so') \
-                                or suffix.endswith('x86_64-linux-gnux32.so'),
-                                suffix)
+                self.assertTrue(
+                    suffix.endswith((
+                        'i386-linux-gnu.so',
+                        'i486-linux-gnu.so',
+                        'i586-linux-gnu.so',
+                        'i686-linux-gnu.so',
+                        'x86_64-linux-gnux32.so',
+                    )),
+                    suffix,
+                )
             else: # 8 byte pointer size
                 self.assertTrue(suffix.endswith('x86_64-linux-gnu.so'), suffix)
 
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
@@ -82,7 +82,7 @@
         return False
 
     def in_dll(self, dll, name):
-        return self.from_address(dll._handle.getaddressindll(name))
+        return self.from_address(dll.__pypy_dll__.getaddressindll(name))
 
     def from_buffer(self, obj, offset=0):
         size = self._sizeofinstances()
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
@@ -430,7 +430,7 @@
             ffires = restype.get_ffi_argtype()
             return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires, self._flags_)
 
-        cdll = self.dll._handle
+        cdll = self.dll.__pypy_dll__
         try:
             ffi_argtypes = [argtype.get_ffi_argtype() for argtype in argtypes]
             ffi_restype = restype.get_ffi_argtype()
diff --git a/lib_pypy/pyrepl/reader.py b/lib_pypy/pyrepl/reader.py
--- a/lib_pypy/pyrepl/reader.py
+++ b/lib_pypy/pyrepl/reader.py
@@ -239,6 +239,10 @@
 
     def __init__(self, console):
         self.buffer = []
+        # Enable the use of `insert` without a `prepare` call - necessary to
+        # facilitate the tab completion hack implemented for
+        # <https://bugs.python.org/issue25660>.
+        self.pos = 0
         self.ps1 = "->> "
         self.ps2 = "/>> "
         self.ps3 = "|.. "
diff --git a/lib_pypy/pyrepl/readline.py b/lib_pypy/pyrepl/readline.py
--- a/lib_pypy/pyrepl/readline.py
+++ b/lib_pypy/pyrepl/readline.py
@@ -314,7 +314,8 @@
         # history item: we use \r\n instead of just \n.  If the history
         # file is passed to GNU readline, the extra \r are just ignored.
         history = self.get_reader().history
-        f = open(os.path.expanduser(filename), 'r', encoding='utf-8')
+        f = open(os.path.expanduser(filename), 'r', encoding='utf-8',
+                 errors='replace')
         buffer = []
         for line in f:
             if line.endswith('\r\n'):
diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py
--- a/pypy/interpreter/module.py
+++ b/pypy/interpreter/module.py
@@ -10,9 +10,10 @@
 class Module(W_Root):
     """A module."""
 
-    _immutable_fields_ = ["w_dict?"]
+    _immutable_fields_ = ["w_dict?", "w_userclass?"]
 
     _frozen = False
+    w_userclass = None
 
     def __init__(self, space, w_name, w_dict=None):
         self.space = space
@@ -148,6 +149,26 @@
                         self)
         return space.call_function(space.w_list, w_dict)
 
+    # These three methods are needed to implement '__class__' assignment
+    # between a module and a subclass of module.  They give every module
+    # the ability to have its '__class__' set, manually.  Note that if
+    # you instantiate a subclass of ModuleType in the first place, then
+    # you get an RPython instance of a subclass of Module created in the
+    # normal way by typedef.py.  That instance has got its own
+    # getclass(), getslotvalue(), etc. but provided it has no __slots__,
+    # it is compatible with ModuleType for '__class__' assignment.
+
+    def getclass(self, space):
+        if self.w_userclass is None:
+            return W_Root.getclass(self, space)
+        return self.w_userclass
+
+    def setclass(self, space, w_cls):
+        self.w_userclass = w_cls
+
+    def user_setup(self, space, w_subtype):
+        self.w_userclass = w_subtype
+
 
 def init_extra_module_attrs(space, w_mod):
     w_dict = w_mod.getdict(space)
diff --git a/pypy/interpreter/test/test_module.py b/pypy/interpreter/test/test_module.py
--- a/pypy/interpreter/test/test_module.py
+++ b/pypy/interpreter/test/test_module.py
@@ -220,3 +220,45 @@
         import sys
         m = type(sys).__new__(type(sys))
         assert not m.__dict__
+
+    def test_class_assignment_for_module(self):
+        import sys
+        modtype = type(sys)
+        class X(modtype):
+            _foobar_ = 42
+
+        m = X("yytest_moduleyy")
+        assert type(m) is m.__class__ is X
+        assert m._foobar_ == 42
+        m.__class__ = modtype
+        assert type(m) is m.__class__ is modtype
+        assert not hasattr(m, '_foobar_')
+
+        m = modtype("xxtest_modulexx")
+        assert type(m) is m.__class__ is modtype
+        m.__class__ = X
+        assert m._foobar_ == 42
+        assert type(m) is m.__class__ is X
+
+        sys.__class__ = modtype
+        assert type(sys) is sys.__class__ is modtype
+        sys.__class__ = X
+        assert sys._foobar_ == 42
+        sys.__class__ = modtype
+
+        class XX(modtype):
+            __slots__ = ['a', 'b']
+
+        x = XX("zztest_modulezz")
+        assert x.__class__ is XX
+        raises(AttributeError, "x.a")
+        x.a = 42
+        assert x.a == 42
+        x.a = 43
+        assert x.a == 43
+        assert 'a' not in x.__dict__
+        del x.a
+        raises(AttributeError, "x.a")
+        raises(AttributeError, "del x.a")
+        raises(TypeError, "x.__class__ = X")
+        raises(TypeError, "sys.__class__ = XX")
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -130,7 +130,7 @@
         return subcls
 _unique_subclass_cache = {}
 
-def _getusercls(cls, reallywantdict=False):
+def _getusercls(cls):
     from rpython.rlib import objectmodel
     from pypy.objspace.std.objectobject import W_ObjectObject
     from pypy.objspace.std.mapdict import (BaseUserClassMapdict,
@@ -144,7 +144,7 @@
     else:
         base_mixin = MapdictStorageMixin
     copy_methods = [BaseUserClassMapdict]
-    if reallywantdict or not typedef.hasdict:
+    if not typedef.hasdict:
         # the type has no dict, mapdict to provide the dict
         copy_methods.append(MapdictDictSupport)
         name += "Dict"
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -1661,7 +1661,7 @@
         assert cpyext_glob_tid_ptr[0] == 0
         cpyext_glob_tid_ptr[0] = tid
 
-        preexist_error = PyErr_Occurred(space) is not None
+        preexist_error = PyErr_Occurred(space)
         try:
             # Call the function
             result = call_external_function(func, *boxed_args)
@@ -1685,17 +1685,19 @@
                 has_result = ret is not None
 
             # Check for exception consistency
-            has_error = PyErr_Occurred(space) is not None
-            if not preexist_error:
-                if has_error and has_result:
-                    raise oefmt(space.w_SystemError,
-                                "An exception was set, but function returned a "
-                                "value")
-                elif not expect_null and not has_error and not has_result:
-                    raise oefmt(space.w_SystemError,
-                                "Function returned a NULL result without setting "
-                                "an exception")
-            if has_error:
+            # XXX best attempt, will miss preexisting error that is
+            # overwritten with a new error of the same type
+            error = PyErr_Occurred(space)
+            has_new_error = (error is not None) and (error is not preexist_error)
+            if not expect_null and has_new_error and has_result:
+                raise oefmt(space.w_SystemError,
+                            "An exception was set, but function returned a "
+                            "value")
+            elif not expect_null and not has_new_error and not has_result:
+                raise oefmt(space.w_SystemError,
+                            "Function returned a NULL result without setting "
+                            "an exception")
+            elif has_new_error:
                 state = space.fromcache(State)
                 state.check_and_raise_exception()
 
diff --git a/pypy/module/cpyext/include/object.h b/pypy/module/cpyext/include/object.h
--- a/pypy/module/cpyext/include/object.h
+++ b/pypy/module/cpyext/include/object.h
@@ -273,6 +273,11 @@
 #define _PyGC_FINALIZED(o) 1
 #define PyType_IS_GC(tp) 1
 
+#define PyObject_GC_Track(o)      do { } while(0)
+#define PyObject_GC_UnTrack(o)    do { } while(0)
+#define _PyObject_GC_TRACK(o)     do { } while(0)
+#define _PyObject_GC_UNTRACK(o)   do { } while(0)
+
 /* Utility macro to help write tp_traverse functions.
  * To use this macro, the tp_traverse function must name its arguments
  * "visit" and "arg".  This is intended to keep tp_traverse functions
diff --git a/pypy/module/cpyext/object.py b/pypy/module/cpyext/object.py
--- a/pypy/module/cpyext/object.py
+++ b/pypy/module/cpyext/object.py
@@ -80,24 +80,6 @@
 def PyObject_GC_Del(space, obj):
     PyObject_Free(space, obj)
 
- at cpython_api([rffi.VOIDP], lltype.Void)
-def PyObject_GC_Track(space, op):
-    """Adds the object op to the set of container objects tracked by the
-    collector.  The collector can run at unexpected times so objects must be
-    valid while being tracked.  This should be called once all the fields
-    followed by the tp_traverse handler become valid, usually near the
-    end of the constructor."""
-    pass
-
- at cpython_api([rffi.VOIDP], lltype.Void)
-def PyObject_GC_UnTrack(space, op):
-    """Remove the object op from the set of container objects tracked by the
-    collector.  Note that PyObject_GC_Track() can be called again on
-    this object to add it back to the set of tracked objects.  The deallocator
-    (tp_dealloc handler) should call this for the object before any of
-    the fields used by the tp_traverse handler become invalid."""
-    pass
-
 @cpython_api([PyObject], PyObjectP, error=CANNOT_FAIL)
 def _PyObject_GetDictPtr(space, op):
     return lltype.nullptr(PyObjectP.TO)
@@ -311,7 +293,7 @@
     PyErr_BadInternalCall(space)
 
 @cpython_api([PyObject, PyObject, rffi.INT_real], rffi.INT_real, error=-1)
-def PyObject_RichCompareBool(space, ref1, ref2, opid_int):
+def PyObject_RichCompareBool(space, w_o1, w_o2, opid_int):
     """Compare the values of o1 and o2 using the operation specified by opid,
     which must be one of Py_LT, Py_LE, Py_EQ,
     Py_NE, Py_GT, or Py_GE, corresponding to <,
@@ -321,13 +303,13 @@
     opid."""
     # Quick result when objects are the same.
     # Guarantees that identity implies equality.
-    if ref1 is ref2:
+    if space.is_w(w_o1, w_o2):
         opid = rffi.cast(lltype.Signed, opid_int)
         if opid == Py_EQ:
             return 1
         if opid == Py_NE:
             return 0 
-    w_res = PyObject_RichCompare(space, ref1, ref2, opid_int)
+    w_res = PyObject_RichCompare(space, w_o1, w_o2, opid_int)
     return int(space.is_true(w_res))
 
 @cpython_api([PyObject], PyObject, result_is_ll=True)
diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py
--- a/pypy/module/cpyext/sequence.py
+++ b/pypy/module/cpyext/sequence.py
@@ -294,6 +294,23 @@
     def getitems_fixedsize(self, w_list):
         return self.getitems_unroll(w_list)
 
+    def copy_into(self, w_list, w_other):
+        w_other.strategy = self
+        w_other.lstorage = self.getstorage_copy(w_list)
+
+    def clone(self, w_list):
+        storage = self.getstorage_copy(w_list)
+        w_clone = W_ListObject.from_storage_and_strategy(self.space, storage,
+                                                         self)
+        return w_clone
+
+    def getitems_copy(self, w_list):
+        return self.getitems(w_list) # getitems copies anyway
+
+    def getstorage_copy(self, w_list):
+        lst = self.getitems(w_list)
+        return self.erase(CPyListStorage(w_list.space, lst))
+
     #------------------------------------------
     # all these methods fail or switch strategy and then call ListObjectStrategy's method
 
@@ -301,23 +318,9 @@
         w_list.switch_to_object_strategy()
         w_list.strategy.setslice(w_list, start, stop, step, length)
 
-    def get_sizehint(self):
-        return -1
-
     def init_from_list_w(self, w_list, list_w):
         raise NotImplementedError
 
-    def clone(self, w_list):
-        storage = w_list.lstorage  # lstorage is tuple, no need to clone
-        w_clone = W_ListObject.from_storage_and_strategy(self.space, storage,
-                                                         self)
-        w_clone.switch_to_object_strategy()
-        return w_clone
-
-    def copy_into(self, w_list, w_other):
-        w_list.switch_to_object_strategy()
-        w_list.strategy.copy_into(w_list, w_other)
-
     def _resize_hint(self, w_list, hint):
         pass
 
@@ -325,13 +328,6 @@
         w_list.switch_to_object_strategy()
         return w_list.strategy.find(w_list, w_item, start, stop)
 
-    def getitems_copy(self, w_list):
-        w_list.switch_to_object_strategy()
-        return w_list.strategy.getitems_copy(w_list)
-
-    def getstorage_copy(self, w_list):
-        raise NotImplementedError
-
     def append(self, w_list, w_item):
         w_list.switch_to_object_strategy()
         w_list.strategy.append(w_list, w_item)
diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py
--- a/pypy/module/cpyext/stubs.py
+++ b/pypy/module/cpyext/stubs.py
@@ -625,18 +625,6 @@
     resized object or NULL on failure."""
     raise NotImplementedError
 
- at cpython_api([PyObject], lltype.Void)
-def _PyObject_GC_TRACK(space, op):
-    """A macro version of PyObject_GC_Track().  It should not be used for
-    extension modules."""
-    raise NotImplementedError
-
- at cpython_api([PyObject], lltype.Void)
-def _PyObject_GC_UNTRACK(space, op):
-    """A macro version of PyObject_GC_UnTrack().  It should not be used for
-    extension modules."""
-    raise NotImplementedError
-
 @cpython_api([PyFrameObject], PyObject)
 def PyGen_New(space, frame):
     """Create and return a new generator object based on the frame object. A
@@ -1516,13 +1504,6 @@
     raise NotImplementedError
 
 
- at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
-def PyType_IS_GC(space, o):
-    """Return true if the type object includes support for the cycle detector; this
-    tests the type flag Py_TPFLAGS_HAVE_GC."""
-    raise NotImplementedError
-
-
 @cpython_api([], rffi.INT_real, error=-1)
 def PyUnicode_ClearFreeList(space, ):
     """Clear the free list. Return the total number of freed items."""
diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -24,6 +24,10 @@
 def PyPy_Crash2(space):
     1/0
 
+ at api.cpython_api([api.PyObject], api.PyObject, result_is_ll=True)
+def PyPy_Noop(space, pyobj):
+    return pyobj
+
 class TestApi:
     def test_signature(self):
         common_functions = api.FUNCTIONS_BY_HEADER[api.pypy_decl]
@@ -665,6 +669,7 @@
         body = """
         PyAPI_FUNC(PyObject*) PyPy_Crash1(void);
         PyAPI_FUNC(long) PyPy_Crash2(void);
+        PyAPI_FUNC(PyObject*) PyPy_Noop(PyObject*);
         static PyObject* foo_crash1(PyObject* self, PyObject *args)
         {
             return PyPy_Crash1();
@@ -688,9 +693,27 @@
             int a = PyPy_Crash2();
             return PyFloat_FromDouble(a);
         }
+        static PyObject* foo_noop(PyObject* self, PyObject* args)
+        {
+            Py_INCREF(args);
+            return PyPy_Noop(args);
+        }
+        static PyObject* foo_set(PyObject* self, PyObject *args)
+        {
+            PyErr_SetString(PyExc_TypeError, "clear called with no error");
+            if (PyLong_Check(args)) {
+                Py_INCREF(args);
+                return args;
+            }
+            return NULL;
+        }
         static PyObject* foo_clear(PyObject* self, PyObject *args)
         {
             PyErr_Clear();
+            if (PyLong_Check(args)) {
+                Py_INCREF(args);
+                return args;
+            }
             return NULL;
         }
         static PyMethodDef methods[] = {
@@ -698,7 +721,9 @@
             { "crash2", foo_crash2, METH_NOARGS },
             { "crash3", foo_crash3, METH_NOARGS },
             { "crash4", foo_crash4, METH_NOARGS },
-            { "clear",  foo_clear, METH_NOARGS },
+            { "clear",  foo_clear,  METH_O },
+            { "set",    foo_set,    METH_O },
+            { "noop",   foo_noop,   METH_O },
             { NULL }
         };
         static struct PyModuleDef moduledef = {
@@ -710,15 +735,46 @@
         };
         """
         module = self.import_module(name='foo', body=body)
+
         # uncaught interplevel exceptions are turned into SystemError
-        raises(SystemError, module.crash1)
-        raises(SystemError, module.crash2)
-        # caught exception
+        expected = "ZeroDivisionError('integer division or modulo by zero',)"
+        exc = raises(SystemError, module.crash1)
+        assert exc.value.args[0] == expected
+
+        exc = raises(SystemError, module.crash2)
+        assert exc.value.args[0] == expected
+
+        # caught exception, api.cpython_api return value works
         assert module.crash3() == -1
-        # An exception was set, but function returned a value
-        raises(SystemError, module.crash4)
-        # No exception set, but NULL returned
-        raises(SystemError, module.clear)
+
+        expected = 'An exception was set, but function returned a value'
+        # PyPy only incompatibility/extension
+        exc = raises(SystemError, module.crash4)
+        assert exc.value.args[0] == expected
+
+        # An exception was set by the previous call, it can pass
+        # cleanly through a call that doesn't check error state
+        assert module.noop(1) == 1
+
+        # clear the exception but return NULL, signalling an error
+        expected = 'Function returned a NULL result without setting an exception'
+        exc = raises(SystemError, module.clear, None)
+        assert exc.value.args[0] == expected
+
+        # Set an exception and return NULL
+        raises(TypeError, module.set, None)
+
+        # clear any exception and return a value
+        assert module.clear(1) == 1
+
+        # Set an exception, but return non-NULL
+        expected = 'An exception was set, but function returned a value'
+        exc = raises(SystemError, module.set, 1)
+        assert exc.value.args[0] == expected
+
+
+        # Clear the exception and return a value, all is OK
+        assert module.clear(1) == 1
 
     def test_new_exception(self):
         mod = self.import_extension('foo', [
diff --git a/pypy/module/cpyext/test/test_object.py b/pypy/module/cpyext/test/test_object.py
--- a/pypy/module/cpyext/test/test_object.py
+++ b/pypy/module/cpyext/test/test_object.py
@@ -416,7 +416,7 @@
         Py_buffer passed to it.
         """
         module = self.import_extension('foo', [
-                ("fillinfo", "METH_VARARGS",
+                ("fillinfo", "METH_NOARGS",
                  """
     Py_buffer buf;
     PyObject *str = PyBytes_FromString("hello, world.");
@@ -468,7 +468,7 @@
         object.
         """
         module = self.import_extension('foo', [
-                ("fillinfo", "METH_VARARGS",
+                ("fillinfo", "METH_NOARGS",
                  """
     Py_buffer buf;
     PyObject *str = PyBytes_FromString("hello, world.");
@@ -514,7 +514,7 @@
         PyBuffer_FillInfo fails if WRITABLE is passed but object is readonly.
         """
         module = self.import_extension('foo', [
-                ("fillinfo", "METH_VARARGS",
+                ("fillinfo", "METH_NOARGS",
                  """
     Py_buffer buf;
     PyObject *str = PyBytes_FromString("hello, world.");
@@ -541,7 +541,7 @@
         decremented by PyBuffer_Release.
         """
         module = self.import_extension('foo', [
-                ("release", "METH_VARARGS",
+                ("release", "METH_NOARGS",
                  """
     Py_buffer buf;
     buf.obj = PyBytes_FromString("release me!");
@@ -560,3 +560,20 @@
     Py_RETURN_NONE;
                  """)])
         assert module.release() is None
+
+
+class AppTestPyBuffer_Release(AppTestCpythonExtensionBase):
+    def test_richcomp_nan(self):
+        module = self.import_extension('foo', [
+               ("comp_eq", "METH_VARARGS",
+                """
+                PyObject *a = PyTuple_GetItem(args, 0);
+                PyObject *b = PyTuple_GetItem(args, 1);
+                int res = PyObject_RichCompareBool(a, b, Py_EQ);
+                return PyLong_FromLong(res);  
+                """),])
+        a = float('nan')
+        b = float('nan')
+        assert a is b
+        res = module.comp_eq(a, b)
+        assert res == 1
diff --git a/pypy/module/cpyext/test/test_sequence.py b/pypy/module/cpyext/test/test_sequence.py
--- a/pypy/module/cpyext/test/test_sequence.py
+++ b/pypy/module/cpyext/test/test_sequence.py
@@ -226,6 +226,15 @@
         w_l.inplace_mul(2)
         assert space.int_w(space.len(w_l)) == 10
 
+    def test_getstorage_copy(self, space, api):
+        w = space.wrap
+        w_l = w([1, 2, 3, 4])
+        api.PySequence_Fast(w_l, "foo") # converts
+
+        w_l1 = w([])
+        space.setitem(w_l1, space.newslice(w(0), w(0), w(1)), w_l)
+        assert map(space.unwrap, space.unpackiterable(w_l1)) == [1, 2, 3, 4]
+
 
 class AppTestSequenceObject(AppTestCpythonExtensionBase):
     def test_fast(self):
diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py
--- a/pypy/module/exceptions/interp_exceptions.py
+++ b/pypy/module/exceptions/interp_exceptions.py
@@ -636,6 +636,14 @@
 else:
     WINERROR_TO_ERRNO, DEFAULT_WIN32_ERRNO = {}, 22 # EINVAL
 
+if rwin32.WIN32:
+    _winerror_property = dict(
+        winerror = readwrite_attrproperty_w('w_winerror', W_OSError),
+    )
+else:
+    _winerror_property = dict()
+
+
 W_OSError.typedef = TypeDef(
     'OSError',
     W_Exception.typedef,
@@ -648,9 +656,9 @@
     strerror = readwrite_attrproperty_w('w_strerror', W_OSError),
     filename = readwrite_attrproperty_w('w_filename', W_OSError),
     filename2= readwrite_attrproperty_w('w_filename2',W_OSError),
-    winerror = readwrite_attrproperty_w('w_winerror', W_OSError),
     characters_written = GetSetProperty(W_OSError.descr_get_written,
                                         W_OSError.descr_set_written),
+    **_winerror_property
     )
 
 W_BlockingIOError = _new_exception(
diff --git a/pypy/module/imp/test/test_app.py b/pypy/module/imp/test/test_app.py
--- a/pypy/module/imp/test/test_app.py
+++ b/pypy/module/imp/test/test_app.py
@@ -81,15 +81,17 @@
     def test_suffixes(self):
         import imp
         for suffix, mode, type in imp.get_suffixes():
-            if mode == imp.PY_SOURCE:
+            if type == imp.PY_SOURCE:
                 assert suffix == '.py'
-                assert type == 'r'
-            elif mode == imp.PY_COMPILED:
+                assert mode == 'r'
+            elif type == imp.PY_COMPILED:
                 assert suffix in ('.pyc', '.pyo')
-                assert type == 'rb'
-            elif mode == imp.C_EXTENSION:
+                assert mode == 'rb'
+            elif type == imp.C_EXTENSION:
                 assert suffix.endswith(('.pyd', '.so'))
-                assert type == 'rb'
+                assert mode == 'rb'
+            else:
+                assert False, ("Unknown type", suffix, mode, type)
 
     def test_ext_suffixes(self):
         import _imp
diff --git a/pypy/module/readline/test/test_readline.py b/pypy/module/readline/test/test_readline.py
--- a/pypy/module/readline/test/test_readline.py
+++ b/pypy/module/readline/test/test_readline.py
@@ -29,3 +29,14 @@
             readline.add_history("dummy")
         assert readline.get_history_item(1) ==  "entrée 1"
         assert readline.get_history_item(2) == "entrée 22"
+
+
+    def test_insert_text_leading_tab(self):
+        """
+        A literal tab can be inserted at the beginning of a line.
+
+        See <https://bugs.python.org/issue25660>
+        """
+        import readline
+        readline.insert_text("\t")
+        assert readline.get_line_buffer() == b"\t"
diff --git a/pypy/module/test_lib_pypy/README.txt b/pypy/module/test_lib_pypy/README.txt
--- a/pypy/module/test_lib_pypy/README.txt
+++ b/pypy/module/test_lib_pypy/README.txt
@@ -1,4 +1,7 @@
 This directory contains app-level tests are supposed to be run *after*
 translation. So you run them by saying:
 
-pypy pytest.py <testfile.py>
+../../goal/pypy-c pytest.py <testfile.py>
+
+Note that if you run it with a PyPy from elsewhere, it will not pick
+up the changes to lib-python and lib_pypy.
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_loading.py b/pypy/module/test_lib_pypy/ctypes_tests/test_loading.py
--- a/pypy/module/test_lib_pypy/ctypes_tests/test_loading.py
+++ b/pypy/module/test_lib_pypy/ctypes_tests/test_loading.py
@@ -43,6 +43,12 @@
                 cdll.LoadLibrary(lib)
                 CDLL(lib)
 
+    def test__handle(self):
+        lib = find_library("c")
+        if lib:
+            cdll = CDLL(lib)
+            assert type(cdll._handle) in (int, long)
+
     if os.name in ("nt", "ce"):
         def test_load_library(self):
             if is_resource_enabled("printing"):
diff --git a/pypy/objspace/std/bytesobject.py b/pypy/objspace/std/bytesobject.py
--- a/pypy/objspace/std/bytesobject.py
+++ b/pypy/objspace/std/bytesobject.py
@@ -364,8 +364,8 @@
         characters, all remaining cased characters have lowercase.
         """
 
-    @unwrap_spec(w_deletechars=WrappedDefault(''))
-    def descr_translate(self, space, w_table, w_deletechars):
+    @unwrap_spec(w_delete=WrappedDefault(''))
+    def descr_translate(self, space, w_table, w_delete):
         """B.translate(table[, deletechars]) -> copy of B
 
         Return a copy of the string B, where all characters occurring
diff --git a/pypy/objspace/std/objectobject.py b/pypy/objspace/std/objectobject.py
--- a/pypy/objspace/std/objectobject.py
+++ b/pypy/objspace/std/objectobject.py
@@ -141,13 +141,17 @@
 
 def descr_set___class__(space, w_obj, w_newcls):
     from pypy.objspace.std.typeobject import W_TypeObject
+    from pypy.interpreter.module import Module
+    #
     if not isinstance(w_newcls, W_TypeObject):
         raise oefmt(space.w_TypeError,
-                    "__class__ must be set to new-style class, not '%T' "
+                    "__class__ must be set to a class, not '%T' "
                     "object", w_newcls)
-    if not w_newcls.is_heaptype():
+    if not (w_newcls.is_heaptype() or
+            w_newcls is space.gettypeobject(Module.typedef)):
         raise oefmt(space.w_TypeError,
-                    "__class__ assignment: only for heap types")
+                    "__class__ assignment only supported for heap types "
+                    "or ModuleType subclasses")
     w_oldcls = space.type(w_obj)
     assert isinstance(w_oldcls, W_TypeObject)
     if (w_oldcls.get_full_instance_layout() ==
diff --git a/pypy/objspace/std/stringmethods.py b/pypy/objspace/std/stringmethods.py
--- a/pypy/objspace/std/stringmethods.py
+++ b/pypy/objspace/std/stringmethods.py
@@ -742,8 +742,8 @@
     DEFAULT_NOOP_TABLE = ''.join([chr(i) for i in range(256)])
 
     # for bytes and bytearray, overridden by unicode
-    @unwrap_spec(w_deletechars=WrappedDefault(''))
-    def descr_translate(self, space, w_table, w_deletechars):
+    @unwrap_spec(w_delete=WrappedDefault(''))
+    def descr_translate(self, space, w_table, w_delete):
         if space.is_w(w_table, space.w_None):
             table = self.DEFAULT_NOOP_TABLE
         else:
@@ -753,7 +753,7 @@
                             "translation table must be 256 characters long")
 
         string = self._val(space)
-        deletechars = self._op_val(space, w_deletechars)
+        deletechars = self._op_val(space, w_delete)
         if len(deletechars) == 0:
             buf = self._builder(len(string))
             for char in string:
diff --git a/pypy/objspace/std/test/test_typeobject.py b/pypy/objspace/std/test/test_typeobject.py
--- a/pypy/objspace/std/test/test_typeobject.py
+++ b/pypy/objspace/std/test/test_typeobject.py
@@ -1284,6 +1284,65 @@
         raises(ValueError, type, 'A\x00B', (), {})
         raises(TypeError, type, b'A', (), {})
 
+    def test_incomplete_extend(self): """
+        # Extending an unitialized type with type.__mro__ is None must
+        # throw a reasonable TypeError exception, instead of failing
+        # with a segfault.
+        class M(type):
+            def mro(cls):
+                if cls.__mro__ is None and cls.__name__ != 'X':
+                    try:
+                        class X(cls):
+                            pass
+                    except TypeError:
+                        found.append(1)
+                return type.mro(cls)
+        found = []
+        class A(metaclass=M):
+            pass
+        assert found == [1]
+        """
+
+    def test_incomplete_extend_2(self): """
+        # Same as test_incomplete_extend, with multiple inheritance
+        class M(type):
+            def mro(cls):
+                if cls.__mro__ is None and cls.__name__ == 'Second':
+                    try:
+                        class X(First, cls):
+                            pass
+                    except TypeError:
+                        found.append(1)
+                return type.mro(cls)
+        found = []
+        class Base(metaclass=M):
+            pass
+        class First(Base):
+            pass
+        class Second(Base):
+            pass
+        assert found == [1]
+        """
+
+    def test_incomplete_extend_3(self): """
+        # this case "works", but gives a slightly strange error message
+        # on both CPython and PyPy
+        class M(type):
+            def mro(cls):
+                if cls.__mro__ is None and cls.__name__ == 'A':
+                    try:
+                        Base.__new__(cls)
+                    except TypeError:
+                        found.append(1)
+                return type.mro(cls)
+        found = []
+        class Base(metaclass=M):
+            pass
+        class A(Base):
+            pass
+        assert found == [1]
+        """
+
 
 class AppTestWithMethodCacheCounter:
     spaceconfig = {"objspace.std.withmethodcachecounter": True}
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -546,19 +546,24 @@
         space = self.space
         if self.is_heaptype():
             return self.getdictvalue(space, '__module__')
+        elif self.is_cpytype():
+            dot = self.name.rfind('.')
         else:
             dot = self.name.find('.')
-            if dot >= 0:
-                mod = self.name[:dot]
-            else:
-                mod = "builtins"
-            return space.newtext(mod)
+        if dot >= 0:
+            mod = self.name[:dot]
+        else:
+            mod = "builtins"
+        return space.newtext(mod)
 
     def getname(self, space):
         if self.is_heaptype():
             result = self.name
         else:
-            dot = self.name.find('.')
+            if self.is_cpytype():
+                dot = self.name.rfind('.')
+            else:
+                dot = self.name.find('.')
             if dot >= 0:
                 result = self.name[dot+1:]
             else:
@@ -1036,6 +1041,9 @@
     for w_candidate in bases_w:
         if not isinstance(w_candidate, W_TypeObject):
             continue
+        if not w_candidate.hasmro:
+            raise oefmt(w_candidate.space.w_TypeError,
+                        "Cannot extend an incomplete type '%N'", w_candidate)
         if w_bestbase is None:
             w_bestbase = w_candidate   # for now
             continue
diff --git a/rpython/jit/backend/llsupport/regalloc.py b/rpython/jit/backend/llsupport/regalloc.py
--- a/rpython/jit/backend/llsupport/regalloc.py
+++ b/rpython/jit/backend/llsupport/regalloc.py
@@ -552,10 +552,11 @@
             self.reg_bindings[result_v] = loc
             return loc
         if v not in self.reg_bindings:
+            # v not in a register. allocate one for result_v and move v there
             prev_loc = self.frame_manager.loc(v)
-            loc = self.force_allocate_reg(v, forbidden_vars)
+            loc = self.force_allocate_reg(result_v, forbidden_vars)
             self.assembler.regalloc_mov(prev_loc, loc)
-        assert v in self.reg_bindings
+            return loc
         if self.longevity[v][1] > self.position:
             # we need to find a new place for variable v and
             # store result in the same place
diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -504,7 +504,7 @@
         clt.frame_info = rffi.cast(jitframe.JITFRAMEINFOPTR, frame_info)
         clt.frame_info.clear() # for now
 
-        if log:
+        if log or self._debug:
             number = looptoken.number
             operations = self._inject_debugging_code(looptoken, operations,
                                                      'e', number)
@@ -589,7 +589,7 @@
                 faildescr.adr_jump_offset)
         self.mc.force_frame_size(DEFAULT_FRAME_BYTES)
         descr_number = compute_unique_id(faildescr)
-        if log:
+        if log or self._debug:
             operations = self._inject_debugging_code(faildescr, operations,
                                                      'b', descr_number)
         arglocs = self.rebuild_faillocs_from_descr(faildescr, inputargs)
@@ -1618,18 +1618,6 @@
         else:
             not_implemented("save_into_mem size = %d" % size)
 
-    def _genop_getfield(self, op, arglocs, resloc):
-        base_loc, ofs_loc, size_loc, sign_loc = arglocs
-        assert isinstance(size_loc, ImmedLoc)
-        source_addr = AddressLoc(base_loc, ofs_loc)
-        self.load_from_mem(resloc, source_addr, size_loc, sign_loc)
-
-    genop_getfield_gc_i = _genop_getfield
-    genop_getfield_gc_r = _genop_getfield
-    genop_getfield_gc_f = _genop_getfield
-    genop_getfield_raw_i = _genop_getfield
-    genop_getfield_raw_f = _genop_getfield
-
     def _genop_gc_load(self, op, arglocs, resloc):
         base_loc, ofs_loc, size_loc, sign_loc = arglocs
         assert isinstance(size_loc, ImmedLoc)
diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -1305,7 +1305,7 @@
         self.rm.possibly_free_var(tmpbox_high)
 
     def compute_hint_frame_locations(self, operations):
-        # optimization only: fill in the 'hint_frame_locations' dictionary
+        # optimization only: fill in the 'hint_frame_pos' dictionary
         # of 'fm' based on the JUMP at the end of the loop, by looking
         # at where we would like the boxes to be after the jump.
         op = operations[-1]
@@ -1320,7 +1320,7 @@
             self._compute_hint_frame_locations_from_descr(descr)
         #else:
         #   The loop ends in a JUMP going back to a LABEL in the same loop.
-        #   We cannot fill 'hint_frame_locations' immediately, but we can
+        #   We cannot fill 'hint_frame_pos' immediately, but we can
         #   wait until the corresponding consider_label() to know where the
         #   we would like the boxes to be after the jump.
 
diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -205,6 +205,18 @@
         if not is_valid_fd(fd):
             from errno import EBADF
             raise OSError(EBADF, 'Bad file descriptor')
+
+    def _bound_for_write(fd, count):
+        if count > 32767 and c_isatty(fd):
+            # CPython Issue #11395, PyPy Issue #2636: the Windows console
+            # returns an error (12: not enough space error) on writing into
+            # stdout if stdout mode is binary and the length is greater than
+            # 66,000 bytes (or less, depending on heap usage).  Can't easily
+            # test that, because we need 'fd' to be non-redirected...
+            count = 32767
+        elif count > 0x7fffffff:
+            count = 0x7fffffff
+        return count
 else:
     def is_valid_fd(fd):
         return 1
@@ -213,6 +225,9 @@
     def validate_fd(fd):
         pass
 
+    def _bound_for_write(fd, count):
+        return count
+
 def closerange(fd_low, fd_high):
     # this behaves like os.closerange() from Python 2.6.
     for fd in xrange(fd_low, fd_high):
@@ -449,6 +464,7 @@
 def write(fd, data):
     count = len(data)
     validate_fd(fd)
+    count = _bound_for_write(fd, count)
     with rffi.scoped_nonmovingbuffer(data) as buf:
         return handle_posix_error('write', c_write(fd, buf, count))
 
diff --git a/rpython/rtyper/tool/rffi_platform.py b/rpython/rtyper/tool/rffi_platform.py
--- a/rpython/rtyper/tool/rffi_platform.py
+++ b/rpython/rtyper/tool/rffi_platform.py
@@ -710,7 +710,8 @@
         size, _ = expected_size_and_sign
         return lltype.FixedSizeArray(fieldtype.OF, size/_sizeof(fieldtype.OF))
     raise TypeError("conflict between translating python and compiler field"
-                    " type %r for %r" % (fieldtype, fieldname))
+                    " type %r for symbol %r, expected size+sign %r" % (
+                        fieldtype, fieldname, expected_size_and_sign))
 
 def expose_value_as_rpython(value):
     if intmask(value) == value:


More information about the pypy-commit mailing list