Author: Ronan Lamy <ronan.l...@gmail.com>
Branch: PyBuffer
Changeset: r91048:2fbdc25dcb1b
Date: 2017-04-13 00:49 +0100
http://bitbucket.org/pypy/pypy/changeset/2fbdc25dcb1b/

Log:    hg merge py3.5

diff too long, truncating to 2000 out of 51546 lines

diff --git a/lib-python/3/distutils/ccompiler.py 
b/lib-python/3/distutils/ccompiler.py
--- a/lib-python/3/distutils/ccompiler.py
+++ b/lib-python/3/distutils/ccompiler.py
@@ -959,7 +959,9 @@
 # is assumed to be in the 'distutils' package.)
 compiler_class = { 'unix':    ('unixccompiler', 'UnixCCompiler',
                                "standard UNIX-style compiler"),
-                   'msvc':    ('_msvccompiler', 'MSVCCompiler',
+                   # PyPy change: On win32 PyPy is translated with the
+                   # "msvc9compiler", force the same here.
+                   'msvc':    ('msvc9compiler', 'MSVCCompiler',
                                "Microsoft Visual C++"),
                    'cygwin':  ('cygwinccompiler', 'CygwinCCompiler',
                                "Cygwin port of GNU C Compiler for Win32"),
diff --git a/lib-python/3/distutils/sysconfig_pypy.py 
b/lib-python/3/distutils/sysconfig_pypy.py
--- a/lib-python/3/distutils/sysconfig_pypy.py
+++ b/lib-python/3/distutils/sysconfig_pypy.py
@@ -66,12 +66,12 @@
     so_ext = [s[0] for s in imp.get_suffixes() if s[2] == imp.C_EXTENSION][0]
 
     g = {}
-    g['CC'] = "gcc -pthread"
-    g['CXX'] = "g++ -pthread"
+    g['CC'] = "cc -pthread"
+    g['CXX'] = "c++ -pthread"
     g['OPT'] = "-DNDEBUG -O2"
     g['CFLAGS'] = "-DNDEBUG -O2"
     g['CCSHARED'] = "-fPIC"
-    g['LDSHARED'] = "gcc -pthread -shared"
+    g['LDSHARED'] = "cc -pthread -shared"
     g['EXT_SUFFIX'] = so_ext
     g['SHLIB_SUFFIX'] = so_ext
     g['SO'] = so_ext  # deprecated in Python 3, for backward compatibility
diff --git a/lib-python/3/pathlib.py b/lib-python/3/pathlib.py
--- a/lib-python/3/pathlib.py
+++ b/lib-python/3/pathlib.py
@@ -1209,23 +1209,19 @@
     def mkdir(self, mode=0o777, parents=False, exist_ok=False):
         if self._closed:
             self._raise_closed()
-        if not parents:
-            try:
-                self._accessor.mkdir(self, mode)
-            except FileExistsError:
-                if not exist_ok or not self.is_dir():
-                    raise
-        else:
-            try:
-                self._accessor.mkdir(self, mode)
-            except FileExistsError:
-                if not exist_ok or not self.is_dir():
-                    raise
-            except OSError as e:
-                if e.errno != ENOENT:
-                    raise
-                self.parent.mkdir(parents=True)
-                self._accessor.mkdir(self, mode)
+        # NOTE: version from CPython 3.7 plus fix at issue #29694
+        try:
+            self._accessor.mkdir(self, mode)
+        except FileNotFoundError:
+            if not parents or self.parent == self:
+                raise
+            self.parent.mkdir(parents=True, exist_ok=True)
+            self.mkdir(mode, parents=False, exist_ok=exist_ok)
+        except OSError:
+            # Cannot rely on checking for EEXIST, since the operating system
+            # could give priority to other errors like EACCES or EROFS
+            if not exist_ok or not self.is_dir():
+                raise
 
     def chmod(self, mode):
         """
diff --git a/lib-python/3/sre_compile.py b/lib-python/3/sre_compile.py
--- a/lib-python/3/sre_compile.py
+++ b/lib-python/3/sre_compile.py
@@ -378,7 +378,11 @@
 
 def _bytes_to_codes(b):
     # Convert block indices to word array
-    a = memoryview(b).cast('I')
+    if _sre.CODESIZE == 2:
+        code = 'H'
+    else:
+        code = 'I'
+    a = memoryview(b).cast(code)
     assert a.itemsize == _sre.CODESIZE
     assert len(a) * a.itemsize == len(b)
     return a.tolist()
diff --git a/lib-python/3/test/_test_multiprocessing.py 
b/lib-python/3/test/_test_multiprocessing.py
--- a/lib-python/3/test/_test_multiprocessing.py
+++ b/lib-python/3/test/_test_multiprocessing.py
@@ -2147,7 +2147,8 @@
 
         # Because we are using xmlrpclib for serialization instead of
         # pickle this will cause a serialization error.
-        self.assertRaises(Exception, queue.put, time.sleep)
+        # Changed on PyPy: passing functions to xmlrpc is broken
+        #self.assertRaises(Exception, queue.put, time.sleep)
 
         # Make queue finalizer run before the server is stopped
         del queue
diff --git a/lib-python/3/test/test_pathlib.py 
b/lib-python/3/test/test_pathlib.py
--- a/lib-python/3/test/test_pathlib.py
+++ b/lib-python/3/test/test_pathlib.py
@@ -8,6 +8,7 @@
 import stat
 import tempfile
 import unittest
+from unittest import mock
 
 from test import support
 TESTFN = support.TESTFN
@@ -1751,6 +1752,35 @@
             p.mkdir(exist_ok=True)
         self.assertEqual(cm.exception.errno, errno.EEXIST)
 
+    def test_mkdir_concurrent_parent_creation(self):
+        for pattern_num in range(32):
+            p = self.cls(BASE, 'dirCPC%d' % pattern_num)
+            self.assertFalse(p.exists())
+
+            def my_mkdir(path, mode=0o777):
+                path = str(path)
+                # Emulate another process that would create the directory
+                # just before we try to create it ourselves.  We do it
+                # in all possible pattern combinations, assuming that this
+                # function is called at most 5 times (dirCPC/dir1/dir2,
+                # dirCPC/dir1, dirCPC, dirCPC/dir1, cirCPC/dir1/dir2).
+                if pattern.pop():
+                    os.mkdir(path, mode)      # from another process
+                    concurrently_created.add(path)
+                os.mkdir(path, mode)          # our real call
+
+            pattern = [bool(pattern_num & (1 << n)) for n in range(5)]
+            concurrently_created = set()
+            p12 = p / 'dir1' / 'dir2'
+            try:
+                with mock.patch("pathlib._normal_accessor.mkdir", my_mkdir):
+                    p12.mkdir(parents=True, exist_ok=False)
+            except FileExistsError:
+                self.assertIn(str(p12), concurrently_created)
+            else:
+                self.assertNotIn(str(p12), concurrently_created)
+            self.assertTrue(p.exists())
+
     @with_symlinks
     def test_symlink_to(self):
         P = self.cls(BASE)
diff --git a/lib-python/3/test/test_xml_etree.py 
b/lib-python/3/test/test_xml_etree.py
--- a/lib-python/3/test/test_xml_etree.py
+++ b/lib-python/3/test/test_xml_etree.py
@@ -1878,6 +1878,17 @@
             with self.assertRaises(RuntimeError):
                 repr(e)  # Should not crash
 
+    def test_bad_find_returns_none(self):
+        # This behavior is the one we get historically when the C
+        # extension module is enabled.  With the Python version, it
+        # raised a TypeError instead.  There are projects out there
+        # that depend on the non-raising behavior, of course.
+        e = ET.Element('foo')
+        assert e.find('') is None
+        assert e.findall('') == []
+        assert e.findtext('') is None
+        assert e.findtext('', default="default.") == "default."
+
 class MutatingElementPath(str):
     def __new__(cls, elem, *args):
         self = str.__new__(cls, *args)
diff --git a/lib-python/3/xml/etree/ElementTree.py 
b/lib-python/3/xml/etree/ElementTree.py
--- a/lib-python/3/xml/etree/ElementTree.py
+++ b/lib-python/3/xml/etree/ElementTree.py
@@ -294,7 +294,14 @@
         Return the first matching element, or None if no element was found.
 
         """
-        return ElementPath.find(self, path, namespaces)
+        # Used to be:  return ElementPath.find(self, path, namespaces)
+        # but there are projects out there that rely on it getting None
+        # instead of an internal TypeError.  This is what the C version
+        # of this class does.
+        result = ElementPath.iterfind(self, path, namespaces)
+        if result is None:
+            return None
+        return next(result, None)
 
     def findtext(self, path, default=None, namespaces=None):
         """Find text for first matching element by tag name or path.
@@ -308,7 +315,17 @@
         content, the empty string is returned.
 
         """
-        return ElementPath.findtext(self, path, default, namespaces)
+        # Used to be:
+        #     return ElementPath.findtext(self, path, default, namespaces)
+        # See find().
+        result = ElementPath.iterfind(self, path, namespaces)
+        if result is None:
+            return default
+        try:
+            elem = next(result)
+            return elem.text or ""
+        except StopIteration:
+            return default
 
     def findall(self, path, namespaces=None):
         """Find all matching subelements by tag name or path.
@@ -319,7 +336,12 @@
         Returns list containing all matching elements in document order.
 
         """
-        return ElementPath.findall(self, path, namespaces)
+        # Used to be:  return ElementPath.findall(self, path, namespaces)
+        # See find().
+        result = ElementPath.iterfind(self, path, namespaces)
+        if result is None:
+            return []
+        return list(result)
 
     def iterfind(self, path, namespaces=None):
         """Find all matching subelements by tag name or path.
diff --git a/lib-python/conftest.py b/lib-python/conftest.py
--- a/lib-python/conftest.py
+++ b/lib-python/conftest.py
@@ -597,7 +597,7 @@
                     py.test.skip("%s module not included in %s" % (mod,
                                                                    execpath))
 
-            cmd = "%s %s %s" % (execpath, regrrun, fspath.purebasename)
+            cmd = "%s -m test -v %s" % (execpath, fspath.purebasename)
             # add watchdog for timing out
             cmd = "%s %s %s %s" % (python, watchdog_script, TIMEOUT, cmd)
         else:
diff --git a/lib_pypy/_audioop_build.py b/lib_pypy/_audioop_build.py
--- a/lib_pypy/_audioop_build.py
+++ b/lib_pypy/_audioop_build.py
@@ -656,4 +656,4 @@
 ffi.set_source("_audioop_cffi", C_SOURCE)
 
 if __name__ == "__main__":
-    ffi.compile()
+    ffi.compile(verbose=2)
diff --git a/lib_pypy/_decimal_build.py b/lib_pypy/_decimal_build.py
--- a/lib_pypy/_decimal_build.py
+++ b/lib_pypy/_decimal_build.py
@@ -226,6 +226,16 @@
 _libdir = os.path.join(os.path.dirname(__file__), '_libmpdec')
 ffi.set_source('_decimal_cffi',
     """
+#ifdef _MSC_VER
+  #if defined(_WIN64)
+    typedef __int64 LONG_PTR; 
+  #else
+    typedef long LONG_PTR;
+  #endif
+  typedef LONG_PTR ssize_t;
+#else
+  #define HAVE_STDINT_H
+#endif
 #include "mpdecimal.h"
 
 #define MPD_Float_operation MPD_Not_implemented
@@ -266,7 +276,6 @@
     include_dirs=[_libdir],
     extra_compile_args=[
         "-DANSI",
-        "-DHAVE_STDINT_H",
         "-DHAVE_INTTYPES_H",
         "-DCONFIG_64" if sys.maxsize > 1 << 32 else "-DCONFIG_32",
     ],
diff --git a/lib_pypy/_pypy_testcapi.py b/lib_pypy/_pypy_testcapi.py
--- a/lib_pypy/_pypy_testcapi.py
+++ b/lib_pypy/_pypy_testcapi.py
@@ -61,13 +61,12 @@
     # set link options
     output_filename = modulename + _get_c_extension_suffix()
     if sys.platform == 'win32':
-        # XXX pyconfig.h uses a pragma to link to the import library,
-        #     which is currently python3.lib
-        library = os.path.join(thisdir, '..', 'libs', 'python32')
+        libname = 'python{0[0]}{0[1]}'.format(sys.version_info)
+        library = os.path.join(thisdir, '..', 'lib', libname)
         if not os.path.exists(library + '.lib'):
             # For a local translation or nightly build
-            library = os.path.join(thisdir, '..', 'pypy', 'goal', 'python32')
-        assert os.path.exists(library + '.lib'),'Could not find import library 
"%s"' % library
+            library = os.path.join(thisdir, '..', 'pypy', 'goal', libname)
+        assert os.path.exists(library + '.lib'), 'Could not find import 
library "%s"' % library
         libraries = [library, 'oleaut32']
         extra_ldargs = ['/MANIFEST',  # needed for VC10
                         '/EXPORT:PyInit_' + modulename]
diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py
--- a/lib_pypy/_sqlite3.py
+++ b/lib_pypy/_sqlite3.py
@@ -32,10 +32,11 @@
 import threading
 
 try:
-    from __pypy__ import newlist_hint
+    from __pypy__ import newlist_hint, add_memory_pressure
 except ImportError:
     assert '__pypy__' not in sys.builtin_module_names
     newlist_hint = lambda sizehint: []
+    add_memory_pressure = lambda size: None
 
 if sys.version_info[0] >= 3:
     StandardError = Exception
@@ -152,6 +153,9 @@
                  check_same_thread=True, factory=None, cached_statements=100,
                  uri=0):
     factory = Connection if not factory else factory
+    # an sqlite3 db seems to be around 100 KiB at least (doesn't matter if
+    # backed by :memory: or a file)
+    add_memory_pressure(100 * 1024)
     return factory(database, timeout, detect_types, isolation_level,
                     check_same_thread, factory, cached_statements, uri)
 
diff --git a/lib_pypy/cffi/api.py b/lib_pypy/cffi/api.py
--- a/lib_pypy/cffi/api.py
+++ b/lib_pypy/cffi/api.py
@@ -563,7 +563,7 @@
             if sys.platform == "win32":
                 # we need 'libpypy-c.lib'.  Current distributions of
                 # pypy (>= 4.1) contain it as 'libs/python27.lib'.
-                pythonlib = "python27"
+                pythonlib = "python{0[0]}{0[1]}".format(sys.version_info)
                 if hasattr(sys, 'prefix'):
                     ensure('library_dirs', os.path.join(sys.prefix, 'libs'))
             else:
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -72,8 +72,6 @@
 
     if "cppyy" in working_modules:
         working_modules.remove("cppyy")  # not tested on win32
-    if "faulthandler" in working_modules:
-        working_modules.remove("faulthandler")  # missing details
 
     # The _locale module is needed by site.py on Windows
     default_modules.add("_locale")
diff --git a/pypy/doc/build.rst b/pypy/doc/build.rst
--- a/pypy/doc/build.rst
+++ b/pypy/doc/build.rst
@@ -79,6 +79,9 @@
 _ssl
     libssl
 
+_vmprof
+    libunwind (optional, loaded dynamically at runtime)
+
 Make sure to have these libraries (with development headers) installed
 before building PyPy, otherwise the resulting binary will not contain
 these modules.  Furthermore, the following libraries should be present
@@ -185,7 +188,7 @@
 ::
 
     cd pypy/tool/release
-    ./package.py pypy-VER-PLATFORM
+    ./package.py --archive-name=pypy-VER-PLATFORM
 
 This creates a clean and prepared hierarchy, as well as a ``.tar.bz2``
 with the same content; both are found by default in
diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -364,6 +364,24 @@
 
 .. __: 
https://bitbucket.org/pypy/pypy/issue/1974/different-behaviour-for-collections-of
 
+Performance Differences
+-------------------------
+
+CPython has an optimization that can make repeated string concatenation not
+quadratic. For example, this kind of code runs in O(n) time::
+
+    s = ''
+    for string in mylist:
+        s += string
+
+In PyPy, this code will always have quadratic complexity. Note also, that the
+CPython optimization is brittle and can break by having slight variations in
+your code anyway. So you should anyway replace the code with::
+
+    parts = []
+    for string in mylist:
+        parts.append(string)
+    s = "".join(parts)
 
 Miscellaneous
 -------------
diff --git a/pypy/doc/install.rst b/pypy/doc/install.rst
--- a/pypy/doc/install.rst
+++ b/pypy/doc/install.rst
@@ -57,6 +57,7 @@
 .. code-block:: console
 
     $ ./pypy-xxx/bin/pypy -m ensurepip
+    $ ./pypy-xxx/bin/pip install -U pip wheel # to upgrade to the latest 
versions
     $ ./pypy-xxx/bin/pip install pygments  # for example
 
 Third party libraries will be installed in ``pypy-xxx/site-packages``, and
@@ -77,7 +78,17 @@
        # from the mercurial checkout
        $ virtualenv -p /path/to/pypy/pypy/translator/goal/pypy-c my-pypy-env
 
-Note that bin/python is now a symlink to bin/pypy.
+       # in any case activate it
+       $ source my-pypy-env/bin/activate
+
+Note that my-pypy-env/bin/python is now a symlink to my-pypy-env/bin/pypy
+so you should be able to run pypy simply by typing::
+
+    $ python
+
+You should still upgrade pip and wheel to the latest versions via::
+
+    $ my-pypy-env/bin/pip install -U pip wheel
 
 .. _pip: http://pypi.python.org/pypi/pip
 .. _ensurepip: https://docs.python.org/2.7/library/ensurepip.html
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -2,7 +2,22 @@
 What's new in PyPy2.7 5.8+
 ==========================
 
-.. this is a revision shortly after release-pypy2.7-v5.7
+.. this is a revision shortly after release-pypy2.7-v5.7.0
 .. startrev: 44f31f6dd39f
 
+Add cpyext interfaces for ``PyModule_New``
 
+Correctly handle `dict.pop`` where the ``pop``
+key is not the same type as the ``dict``'s and ``pop``
+is called with a default (will be part of release 5.7.1)
+
+.. branch: issue2522
+
+Fix missing tp_new on w_object called through multiple inheritance
+(will be part of release 5.7.1)
+
+.. branch: lstrip_to_empty_string
+
+.. branch: vmprof-native
+
+PyPy support to profile native frames in vmprof.
diff --git a/pypy/doc/whatsnew-pypy3-head.rst b/pypy/doc/whatsnew-pypy3-head.rst
--- a/pypy/doc/whatsnew-pypy3-head.rst
+++ b/pypy/doc/whatsnew-pypy3-head.rst
@@ -5,3 +5,16 @@
 .. this is the revision after release-pypy3.3-5.7.x was branched
 .. startrev: afbf09453369
 
+.. branch: mtest
+Use "<python> -m test" to run the CPython test suite, as documented by CPython,
+instead of our outdated regrverbose.py script.
+
+.. branch: win32-faulthandler
+
+Enable the 'faulthandler' module on Windows;
+this unblocks the Python test suite.
+
+.. branch: superjumbo
+
+Implement posix.posix_fallocate() and posix.posix_fadvise()
+
diff --git a/pypy/goal/targetpypystandalone.py 
b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -13,6 +13,7 @@
 from pypy import pypydir
 from rpython.rlib import rthread
 from pypy.module.thread import os_thread
+from pypy.module.sys.version import CPYTHON_VERSION
 
 thisdir = py.path.local(__file__).dirpath()
 
@@ -285,7 +286,8 @@
         if sys.platform == 'win32':
             libdir = thisdir.join('..', '..', 'libs')
             libdir.ensure(dir=1)
-            config.translation.libname = str(libdir.join('python27.lib'))
+            pythonlib = "python{0[0]}{0[1]}.lib".format(CPYTHON_VERSION)
+            config.translation.libname = str(libdir.join(pythonlib))
 
         if config.translation.thread:
             config.objspace.usemodules.thread = True
diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -9,6 +9,7 @@
 from rpython.rlib.objectmodel import we_are_translated, specialize
 from rpython.rlib.objectmodel import dont_inline
 from rpython.rlib import rstack, rstackovf
+from rpython.rlib import rwin32
 
 from pypy.interpreter import debug
 
@@ -568,33 +569,6 @@
     # 31: ANSI color code "red"
     ansi_print(text, esc="31", file=file, newline=newline)
 
-try:
-    WindowsError
-except NameError:
-    _WINDOWS = False
-else:
-    _WINDOWS = True
-
-    def wrap_windowserror(space, e, w_filename=None):
-        XXX    # WindowsError no longer exists in Py3.5
-               # instead, OSError has a kwarg winerror that overrides
-               # any errno supplied
-        from rpython.rlib import rwin32
-
-        winerror = e.winerror
-        try:
-            msg = rwin32.FormatError(winerror)
-        except ValueError:
-            msg = 'Windows Error %d' % winerror
-        exc = space.w_WindowsError
-        if w_filename is not None:
-            w_error = space.call_function(exc, space.newint(winerror),
-                                          space.newtext(msg), w_filename)
-        else:
-            w_error = space.call_function(exc, space.newint(winerror),
-                                          space.newtext(msg))
-        return OperationError(exc, w_error)
-
 @specialize.arg(3, 6)
 def wrap_oserror2(space, e, w_filename=None, exception_name='w_OSError',
                   w_exception_class=None, w_filename2=None, eintr_retry=False):
@@ -612,9 +586,6 @@
     """
     assert isinstance(e, OSError)
 
-    if _WINDOWS and isinstance(e, WindowsError):
-        return wrap_windowserror(space, e, w_filename)
-
     if w_exception_class is None:
         w_exc = getattr(space, exception_name)
     else:
@@ -631,28 +602,37 @@
 def _wrap_oserror2_impl(space, e, w_filename, w_filename2, w_exc, eintr_retry):
     # move the common logic in its own function, instead of having it
     # duplicated 4 times in all 4 specialized versions of wrap_oserror2()
-    errno = e.errno
 
-    if errno == EINTR:
-        space.getexecutioncontext().checksignals()
-        if eintr_retry:
-            return None
+    if rwin32.WIN32 and isinstance(e, WindowsError):
+        winerror = e.winerror
+        try:
+            msg = rwin32.FormatError(winerror)
+        except ValueError:
+            msg = 'Windows Error %d' % winerror
+        w_errno = space.w_None
+        w_winerror = space.newint(winerror)
+        w_msg = space.newtext(msg)
+    else:
+        errno = e.errno
+        if errno == EINTR:
+            space.getexecutioncontext().checksignals()
+            if eintr_retry:
+                return None
 
-    try:
-        msg = strerror(errno)
-    except ValueError:
-        msg = u'error %d' % errno
-    if w_filename is not None:
-        if w_filename2 is not None:
-            w_error = space.call_function(w_exc, space.newint(errno),
-                                          space.newunicode(msg), w_filename,
-                                          space.w_None, w_filename2)
-        else:
-            w_error = space.call_function(w_exc, space.newint(errno),
-                                          space.newunicode(msg), w_filename)
-    else:
-        w_error = space.call_function(w_exc, space.newint(errno),
-                                      space.newunicode(msg))
+        try:
+            msg = strerror(errno)
+        except ValueError:
+            msg = u'error %d' % errno
+        w_errno = space.newint(errno)
+        w_winerror = space.w_None
+        w_msg = space.newunicode(msg)
+
+    if w_filename is None:
+        w_filename = space.w_None
+    if w_filename2 is None:
+        w_filename2 = space.w_None
+    w_error = space.call_function(w_exc, w_errno, w_msg, w_filename,
+                                  w_winerror, w_filename2)
     operror = OperationError(w_exc, w_error)
     if eintr_retry:
         raise operror
diff --git a/pypy/interpreter/pyparser/future.py 
b/pypy/interpreter/pyparser/future.py
--- a/pypy/interpreter/pyparser/future.py
+++ b/pypy/interpreter/pyparser/future.py
@@ -80,6 +80,7 @@
     from pypy.interpreter.pyparser import pygram
     it = TokenIterator(tokens)
     result = 0
+    last_position = (0, 0)
     #
     # The only things that can precede a future statement are another
     # future statement and a doc string (only one).  This is a very
@@ -94,6 +95,11 @@
            it.skip_name("__future__") and
            it.skip_name("import")):
         it.skip(pygram.tokens.LPAR)    # optionally
+        # return in 'last_position' any line-column pair that points
+        # somewhere inside the last __future__ import statement
+        # (at the start would be fine too, but it's easier to grab a
+        # random position inside)
+        last_position = (it.tok[2], it.tok[3])
         result |= future_flags.get_compiler_feature(it.next_feature_name())
         while it.skip(pygram.tokens.COMMA):
             result |= future_flags.get_compiler_feature(it.next_feature_name())
@@ -104,5 +110,4 @@
     # remove the flags that were specified but are anyway mandatory
     result &= ~future_flags.mandatory_flags
 
-    position = (it.tok[2], it.tok[3])
-    return result, position
+    return result, last_position
diff --git a/pypy/interpreter/pyparser/test/test_future.py 
b/pypy/interpreter/pyparser/test/test_future.py
--- a/pypy/interpreter/pyparser/test/test_future.py
+++ b/pypy/interpreter/pyparser/test/test_future.py
@@ -2,10 +2,9 @@
 from pypy.interpreter.pyparser import future, pytokenizer
 from pypy.tool import stdlib___future__ as fut
 
-def run(s, expected_last_future=None):
+def run(s, expected_last_future=(0, 0)):
     source_lines = s.splitlines(True)
     tokens = pytokenizer.generate_tokens(source_lines, 0)
-    expected_last_future = expected_last_future or tokens[-1][2:4]
     #
     flags, last_future_import = future.add_future_flags(
         future.futureFlags_3_5, tokens)
@@ -14,7 +13,7 @@
 
 def test_docstring():
     s = '"Docstring\\" "\nfrom  __future__ import division\n'
-    f = run(s)
+    f = run(s, (2, 24))
     assert f == 0
 
 def test_comment():
@@ -45,152 +44,152 @@
 
 def test_from():
     s = 'from  __future__ import division\n'
-    f = run(s)
+    f = run(s, (1, 24))
     assert f == 0
 
 def test_froms():
     s = 'from  __future__ import division, generators, with_statement\n'
-    f = run(s)
+    f = run(s, (1, 24))
     assert f == 0
 
 def test_from_as():
     s = 'from  __future__ import division as b\n'
-    f = run(s)
+    f = run(s, (1, 24))
     assert f == 0
 
 def test_froms_as():
     s = 'from  __future__ import division as b, generators as c\n'
-    f = run(s)
+    f = run(s, (1, 24))
     assert f == 0
 
 def test_from_paren():
     s = 'from  __future__ import (division)\n'
-    f = run(s)
+    f = run(s, (1, 25))
     assert f == 0
 
 def test_froms_paren():
     s = 'from  __future__ import (division, generators)\n'
-    f = run(s)
+    f = run(s, (1, 25))
     assert f == 0
 
 def test_froms_paren_as():
     s = 'from  __future__ import (division as b, generators,)\n'
-    f = run(s)
+    f = run(s, (1, 25))
     assert f == 0
 
 def test_paren_with_newline():
     s = 'from __future__ import (division,\nabsolute_import)\n'
-    f = run(s)
+    f = run(s, (1, 24))
     assert f == 0
 
 def test_paren_with_newline_2():
     s = 'from __future__ import (\ndivision,\nabsolute_import)\n'
-    f = run(s)
+    f = run(s, (2, 0))
     assert f == 0
 
 def test_multiline():
     s = '"abc" #def\n  #ghi\nfrom  __future__ import (division as b, 
generators,)\nfrom __future__ import with_statement\n'
-    f = run(s)
+    f = run(s, (4, 23))
     assert f == 0
 
 def test_windows_style_lineendings():
     s = '"abc" #def\r\n  #ghi\r\nfrom  __future__ import (division as b, 
generators,)\r\nfrom __future__ import with_statement\r\n'
-    f = run(s)
+    f = run(s, (4, 23))
     assert f == 0
 
 def test_mac_style_lineendings():
     s = '"abc" #def\r  #ghi\rfrom  __future__ import (division as b, 
generators,)\rfrom __future__ import with_statement\r'
-    f = run(s)
+    f = run(s, (4, 23))
     assert f == 0
 
 def test_semicolon():
     s = '"abc" #def\n  #ghi\nfrom  __future__ import (division as b, 
generators,);  from __future__ import with_statement\n'
-    f = run(s)
+    f = run(s, (3, 78))
     assert f == 0
 
 def test_semicolon_2():
     s = 'from  __future__ import division; from foo import bar'
-    f = run(s, expected_last_future=(1, 39))
+    f = run(s, expected_last_future=(1, 24))
     assert f == 0
 
 def test_full_chain():
     s = '"abc" #def\n  #ghi\nfrom  __future__ import (division as b, 
generators,);  from __future__ import with_statement\n'
-    f = run(s)
+    f = run(s, (3, 78))
     assert f == 0
 
 def test_intervening_code():
     s = 'from  __future__ import (division as b, generators,)\nfrom sys import 
modules\nfrom __future__ import with_statement\n'
-    f = run(s, expected_last_future=(2, 5))
+    f = run(s, expected_last_future=(1, 25))
     assert f == 0
 
 def test_nonexisting():
     s = 'from  __future__ import non_existing_feature\n'
-    f = run(s)
+    f = run(s, (1, 24))
     assert f == 0
 
 def test_nonexisting_2():
     s = 'from  __future__ import non_existing_feature, with_statement\n'
-    f = run(s)
+    f = run(s, (1, 24))
     assert f == 0
 
 def test_from_import_abs_import():
     s = 'from  __future__ import absolute_import\n'
-    f = run(s)
+    f = run(s, (1, 24))
     assert f == 0
 
 def test_raw_doc():
     s = 'r"Doc"\nfrom __future__ import with_statement\n'
-    f = run(s)
+    f = run(s, (2, 23))
     assert f == 0
 
 def test_unicode_doc():
     s = 'u"Doc"\nfrom __future__ import with_statement\n'
-    f = run(s)
+    f = run(s, (2, 23))
     assert f == 0
 
 def test_raw_unicode_doc():
     s = 'ru"Doc"\nfrom __future__ import with_statement\n'
-    f = run(s)
+    f = run(s, (2, 23))
     assert f == 0
 
 def test_continuation_line():
     s = "\\\nfrom __future__ import with_statement\n"
-    f = run(s)
+    f = run(s, (2, 23))
     assert f == 0
 
 def test_continuation_lines():
     s = "\\\n  \t\\\nfrom __future__ import with_statement\n"
-    f = run(s)
+    f = run(s, (3, 23))
     assert f == 0
 
 def test_lots_of_continuation_lines():
     s = "\\\n\\\n\\\n\\\n\\\n\\\n\nfrom __future__ import with_statement\n"
-    f = run(s)
+    f = run(s, (8, 23))
     assert f == 0
 
 def test_continuation_lines_raise():
     s = "   \\\n  \t\\\nfrom __future__ import with_statement\n"
-    f = run(s, expected_last_future=(1, 0))
+    f = run(s)
     assert f == 0     # because of the INDENT
 
 def test_continuation_lines_in_docstring_single_quoted():
     s = '"\\\n\\\n\\\n\\\n\\\n\\\n"\nfrom  __future__ import division\n'
-    f = run(s)
+    f = run(s, (8, 24))
     assert f == 0
 
 def test_continuation_lines_in_docstring_triple_quoted():
     s = '"""\\\n\\\n\\\n\\\n\\\n\\\n"""\nfrom  __future__ import division\n'
-    f = run(s)
+    f = run(s, (8, 24))
     assert f == 0
 
 def test_blank_lines():
     s = ('\n\t\n\nfrom __future__ import with_statement'
          '  \n  \n  \nfrom __future__ import division')
-    f = run(s)
+    f = run(s, (7, 23))
     assert f == 0
 
 def test_dummy_semicolons():
     s = ('from __future__ import division;\n'
          'from __future__ import with_statement;')
-    f = run(s)
+    f = run(s, (2, 23))
     assert f == 0
diff --git a/pypy/interpreter/test/test_syntax.py 
b/pypy/interpreter/test/test_syntax.py
--- a/pypy/interpreter/test/test_syntax.py
+++ b/pypy/interpreter/test/test_syntax.py
@@ -308,6 +308,15 @@
         assert isinstance(ns["c"], bytes)
         assert isinstance(ns["d"], bytes)
 
+    def test_both_futures_with_semicolon(self):
+        # Issue #2526: a corner case which crashes only if the file
+        # contains *nothing more* than two __future__ imports separated
+        # by a semicolon.
+        s = """
+from __future__ import unicode_literals; from __future__ import print_function
+"""
+        exec s in {}
+
 
 class AppTestComprehensions:
 
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -6,6 +6,8 @@
 
 
 class BuildersModule(MixedModule):
+    """ Module containing string and unicode builders """
+
     appleveldefs = {}
 
     interpleveldefs = {
@@ -34,6 +36,8 @@
 
 
 class IntOpModule(MixedModule):
+    """ Module for integer operations that have two-complement overflow
+    behaviour instead of overflowing to longs """
     appleveldefs = {}
     interpleveldefs = {
         'int_add':         'interp_intop.int_add',
@@ -55,6 +59,8 @@
 
 
 class Module(MixedModule):
+    """ PyPy specific "magic" functions. A lot of them are experimental and
+    subject to change, many are internal. """
     appleveldefs = {
     }
 
diff --git a/pypy/module/__pypy__/interp_magic.py 
b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -106,13 +106,15 @@
         raise wrap_oserror(space, e)
 
 @unwrap_spec(sizehint=int)
-def resizelist_hint(space, w_iterable, sizehint):
-    if not isinstance(w_iterable, W_ListObject):
+def resizelist_hint(space, w_list, sizehint):
+    """ Reallocate the underlying storage of the argument list to sizehint """
+    if not isinstance(w_list, W_ListObject):
         raise oefmt(space.w_TypeError, "arg 1 must be a 'list'")
-    w_iterable._resize_hint(sizehint)
+    w_list._resize_hint(sizehint)
 
 @unwrap_spec(sizehint=int)
 def newlist_hint(space, sizehint):
+    """ Create a new empty list that has an underlying storage of length 
sizehint """
     return space.newlist_hint(sizehint)
 
 @unwrap_spec(debug=int)
@@ -125,6 +127,9 @@
 
 @unwrap_spec(estimate=int)
 def add_memory_pressure(estimate):
+    """ Add memory pressure of estimate bytes. Useful when calling a C function
+    that internally allocates a big chunk of memory. This instructs the GC to
+    garbage collect sooner than it would otherwise."""
     rgc.add_memory_pressure(estimate)
 
 @unwrap_spec(w_frame=PyFrame)
diff --git a/pypy/module/_cffi_backend/test/test_recompiler.py 
b/pypy/module/_cffi_backend/test/test_recompiler.py
--- a/pypy/module/_cffi_backend/test/test_recompiler.py
+++ b/pypy/module/_cffi_backend/test/test_recompiler.py
@@ -1471,8 +1471,13 @@
         with self.StdErrCapture(fd=True) as f:
             res = lib.bar(4, 5)
         assert res == 0
-        assert f.getvalue() == (
+        assert f.getvalue() in (
+            # If the underlying cffi is <= 1.9
             "extern \"Python\": function bar() called, but no code was 
attached "
+            "to it yet with @ffi.def_extern().  Returning 0.\n",
+            # If the underlying cffi is >= 1.10
+            "extern \"Python\": function _CFFI_test_extern_python_1.bar() "
+            "called, but no code was attached "
             "to it yet with @ffi.def_extern().  Returning 0.\n")
 
         @ffi.def_extern("bar")
diff --git a/pypy/module/_multiprocessing/interp_win32.py 
b/pypy/module/_multiprocessing/interp_win32.py
--- a/pypy/module/_multiprocessing/interp_win32.py
+++ b/pypy/module/_multiprocessing/interp_win32.py
@@ -4,10 +4,9 @@
 from rpython.rtyper.tool import rffi_platform
 from rpython.translator.tool.cbuild import ExternalCompilationInfo
 
-from pypy.interpreter.error import oefmt, wrap_windowserror
+from pypy.interpreter.error import oefmt, wrap_oserror
 from pypy.interpreter.function import StaticMethod
 from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.module._multiprocessing.interp_connection import w_handle
 
 CONSTANTS = """
     PIPE_ACCESS_INBOUND PIPE_ACCESS_DUPLEX
@@ -35,6 +34,9 @@
 def handle_w(space, w_handle):
     return rffi.cast(rwin32.HANDLE, space.int_w(w_handle))
 
+def w_handle(space, handle):
+    return space.newint(rffi.cast(rffi.INTPTR_T, handle))
+
 _CreateNamedPipe = rwin32.winexternal(
     'CreateNamedPipeA', [
         rwin32.LPCSTR,
@@ -106,7 +108,7 @@
 def CloseHandle(space, w_handle):
     handle = handle_w(space, w_handle)
     if not rwin32.CloseHandle(handle):
-        raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
+        raise wrap_oserror(space, rwin32.lastSavedWindowsError())
 
 def GetLastError(space):
     return space.newint(rwin32.GetLastError_saved())
@@ -126,7 +128,7 @@
         outputsize, inputsize, timeout, rffi.NULL)
 
     if handle == rwin32.INVALID_HANDLE_VALUE:
-        raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
+        raise wrap_oserror(space, rwin32.lastSavedWindowsError())
 
     return w_handle(space, handle)
 
@@ -136,7 +138,7 @@
     if overlapped:
         raise oefmt(space.w_NotImplementedError, "expected a NULL pointer")
     if not _ConnectNamedPipe(handle, rffi.NULL):
-        raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
+        raise wrap_oserror(space, rwin32.lastSavedWindowsError())
 
 def SetNamedPipeHandleState(space, w_handle, w_pipemode, w_maxinstances,
                             w_timeout):
@@ -156,7 +158,7 @@
             statep[2] = rffi.ptradd(state, 2)
         if not _SetNamedPipeHandleState(handle, statep[0], statep[1],
                                         statep[2]):
-            raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
+            raise wrap_oserror(space, rwin32.lastSavedWindowsError())
     finally:
         lltype.free(state, flavor='raw')
         lltype.free(statep, flavor='raw')
@@ -165,7 +167,7 @@
 def WaitNamedPipe(space, name, timeout):
     # Careful: zero means "default value specified by CreateNamedPipe()"
     if not _WaitNamedPipe(name, timeout):
-        raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
+        raise wrap_oserror(space, rwin32.lastSavedWindowsError())
 
 @unwrap_spec(filename='fsencode', access=r_uint, share=r_uint,
              disposition=r_uint, flags=r_uint)
@@ -180,7 +182,7 @@
                          disposition, flags, rwin32.NULL_HANDLE)
 
     if handle == rwin32.INVALID_HANDLE_VALUE:
-        raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
+        raise wrap_oserror(space, rwin32.lastSavedWindowsError())
 
     return w_handle(space, handle)
 
diff --git a/pypy/module/_vmprof/interp_vmprof.py 
b/pypy/module/_vmprof/interp_vmprof.py
--- a/pypy/module/_vmprof/interp_vmprof.py
+++ b/pypy/module/_vmprof/interp_vmprof.py
@@ -50,8 +50,8 @@
     return OperationError(w_VMProfError, space.newtext(e.msg))
 
 
-@unwrap_spec(fileno=int, period=float)
-def enable(space, fileno, period):
+@unwrap_spec(fileno=int, period=float, memory=int, lines=int, native=int)
+def enable(space, fileno, period, memory, lines, native):
     """Enable vmprof.  Writes go to the given 'fileno', a file descriptor
     opened for writing.  *The file descriptor must remain open at least
     until disable() is called.*
@@ -65,7 +65,7 @@
     #                             "with vmprof will crash"),
     #               space.w_RuntimeWarning)
     try:
-        rvmprof.enable(fileno, period)
+        rvmprof.enable(fileno, period, memory, native)
     except rvmprof.VMProfError as e:
         raise VMProfError(space, e)
 
diff --git a/pypy/module/_vmprof/test/test__vmprof.py 
b/pypy/module/_vmprof/test/test__vmprof.py
--- a/pypy/module/_vmprof/test/test__vmprof.py
+++ b/pypy/module/_vmprof/test/test__vmprof.py
@@ -24,10 +24,11 @@
             i += 5 * WORD # header
             assert s[i    ] == 5    # MARKER_HEADER
             assert s[i + 1] == 0    # 0
-            assert s[i + 2] == 2    # VERSION_THREAD_ID
-            assert s[i + 3] == 4    # len('pypy')
-            assert s[i + 4: i + 8] == b'pypy'
-            i += 8
+            assert s[i + 2] == 6    # VERSION_TIMESTAMP
+            assert s[i + 3] == 8    # PROFILE_RPYTHON
+            assert s[i + 4] == 4    # len('pypy')
+            assert s[i + 5: i + 9] == b'pypy'
+            i += 9
             while i < len(s):
                 if s[i] == 3:
                     break
@@ -41,6 +42,17 @@
                     _, size = struct.unpack("ll", s[i:i + 2 * WORD])
                     count += 1
                     i += 2 * WORD + size
+                elif s[i] == '\x06':
+                    print(s[i:i+24])
+                    i += 1+8+8+8
+                elif s[i] == '\x07':
+                    i += 1
+                    # skip string
+                    size, = struct.unpack("l", s[i:i + WORD])
+                    i += WORD+size
+                    # skip string
+                    size, = struct.unpack("l", s[i:i + WORD])
+                    i += WORD+size
                 else:
                     raise AssertionError(s[i])
             return count
@@ -48,7 +60,7 @@
         import _vmprof
         gc.collect()  # try to make the weakref list deterministic
         gc.collect()  # by freeing all dead code objects
-        _vmprof.enable(tmpfileno, 0.01)
+        _vmprof.enable(tmpfileno, 0.01, 0, 0, 0)
         _vmprof.disable()
         s = open(self.tmpfilename, 'rb').read()
         no_of_codes = count(s)
@@ -64,7 +76,7 @@
 
         gc.collect()
         gc.collect()
-        _vmprof.enable(tmpfileno2, 0.01)
+        _vmprof.enable(tmpfileno2, 0.01, 0, 0, 0)
 
         exec_("""def foo2():
             pass
@@ -79,9 +91,9 @@
 
     def test_enable_ovf(self):
         import _vmprof
-        raises(_vmprof.VMProfError, _vmprof.enable, 2, 0)
-        raises(_vmprof.VMProfError, _vmprof.enable, 2, -2.5)
-        raises(_vmprof.VMProfError, _vmprof.enable, 2, 1e300)
-        raises(_vmprof.VMProfError, _vmprof.enable, 2, 1e300 * 1e300)
+        raises(_vmprof.VMProfError, _vmprof.enable, 2, 0, 0, 0, 0)
+        raises(_vmprof.VMProfError, _vmprof.enable, 2, -2.5, 0, 0, 0)
+        raises(_vmprof.VMProfError, _vmprof.enable, 2, 1e300, 0, 0, 0)
+        raises(_vmprof.VMProfError, _vmprof.enable, 2, 1e300 * 1e300, 0, 0, 0)
         NaN = (1e300*1e300) / (1e300*1e300)
-        raises(_vmprof.VMProfError, _vmprof.enable, 2, NaN)
+        raises(_vmprof.VMProfError, _vmprof.enable, 2, NaN, 0, 0, 0)
diff --git a/pypy/module/_vmprof/test/test_direct.py 
b/pypy/module/_vmprof/test/test_direct.py
--- a/pypy/module/_vmprof/test/test_direct.py
+++ b/pypy/module/_vmprof/test/test_direct.py
@@ -43,7 +43,7 @@
 }
 
 
-""" + open(str(srcdir.join("vmprof_get_custom_offset.h"))).read(), 
include_dirs=[str(srcdir)])
+""" + open(str(srcdir.join("shared/vmprof_get_custom_offset.h"))).read(), 
include_dirs=[str(srcdir)])
 
 class TestDirect(object):
     def test_infrastructure(self):
diff --git a/pypy/module/_winreg/interp_winreg.py 
b/pypy/module/_winreg/interp_winreg.py
--- a/pypy/module/_winreg/interp_winreg.py
+++ b/pypy/module/_winreg/interp_winreg.py
@@ -2,7 +2,7 @@
 from pypy.interpreter.baseobjspace import W_Root, BufferInterfaceNotFound
 from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
-from pypy.interpreter.error import OperationError, oefmt, wrap_windowserror
+from pypy.interpreter.error import OperationError, oefmt, wrap_oserror
 from rpython.rtyper.lltypesystem import rffi, lltype
 from rpython.rlib import rwinreg, rwin32
 from rpython.rlib.rarithmetic import r_uint, intmask
@@ -110,7 +110,7 @@
     elif isinstance(w_hkey, W_HKEY):
         return w_hkey.hkey
     elif space.isinstance_w(w_hkey, space.w_int):
-        if space.is_true(space.lt(w_hkey, space.wrap(0))):
+        if space.is_true(space.lt(w_hkey, space.newint(0))):
             return rffi.cast(rwinreg.HKEY, space.int_w(w_hkey))
         return rffi.cast(rwinreg.HKEY, space.uint_w(w_hkey))
     else:
@@ -702,7 +702,7 @@
     try:
         return space.newunicode(rwinreg.ExpandEnvironmentStrings(source))
     except WindowsError as e:
-        raise wrap_windowserror(space, e)
+        raise wrap_oserror(space, e)
 
 def DisableReflectionKey(space, w_key):
     """Disables registry reflection for 32-bit processes running on a 64-bit
diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py
--- a/pypy/module/cpyext/__init__.py
+++ b/pypy/module/cpyext/__init__.py
@@ -4,7 +4,6 @@
 
 class Module(MixedModule):
     interpleveldefs = {
-        'load_module': 'api.load_extension_module',
     }
 
     appleveldefs = {
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
@@ -565,7 +565,7 @@
     'PyUnicode_FromFormat', 'PyUnicode_FromFormatV', 
'PyUnicode_AsWideCharString',
     'PyUnicode_GetSize', 'PyUnicode_GetLength',
     'PyModule_AddObject', 'PyModule_AddIntConstant', 
'PyModule_AddStringConstant',
-    'PyModule_GetDef',
+    'PyModule_GetDef', 'PyModuleDef_Init',
     'Py_BuildValue', 'Py_VaBuildValue', 'PyTuple_Pack',
     '_PyArg_Parse_SizeT', '_PyArg_ParseTuple_SizeT',
     '_PyArg_ParseTupleAndKeywords_SizeT', '_PyArg_VaParse_SizeT',
@@ -651,7 +651,7 @@
     global all_exceptions
     all_exceptions = list(exceptions.Module.interpleveldefs)
     for exc_name in all_exceptions:
-        if exc_name in ('EnvironmentError', 'IOError'):
+        if exc_name in ('EnvironmentError', 'IOError', 'WindowsError'):
             # FIXME: aliases of OSError cause a clash of names via
             # export_struct
             continue
@@ -1489,8 +1489,7 @@
     copy_header_files(cts, trunk_include, use_micronumpy)
 
 
-@unwrap_spec(path='fsencode', name='text')
-def load_extension_module(space, path, name):
+def create_extension_module(space, w_spec):
     # note: this is used both to load CPython-API-style C extension
     # modules (cpyext) and to load CFFI-style extension modules
     # (_cffi_backend).  Any of the two can be disabled at translation
@@ -1498,6 +1497,9 @@
     # order of things here.
     from rpython.rlib import rdynload
 
+    name = space.text_w(space.getattr(w_spec, space.newtext("name")))
+    path = space.text_w(space.getattr(w_spec, space.newtext("origin")))
+
     if os.sep not in path:
         path = os.curdir + os.sep + path      # force a '/' in the path
     basename = name.split('.')[-1]
@@ -1535,7 +1537,7 @@
         except KeyError:
             pass
         else:
-            return load_cpyext_module(space, name, path, dll, initptr)
+            return create_cpyext_module(space, w_spec, name, path, dll, 
initptr)
         if look_for is not None:
             look_for += ' or ' + also_look_for
         else:
@@ -1549,8 +1551,9 @@
 
 initfunctype = lltype.Ptr(lltype.FuncType([], PyObject))
 
-def load_cpyext_module(space, name, path, dll, initptr):
+def create_cpyext_module(space, w_spec, name, path, dll, initptr):
     from rpython.rlib import rdynload
+    from pypy.module.cpyext.pyobject import get_w_obj_and_decref
 
     space.getbuiltinmodule("cpyext")    # mandatory to init cpyext
     state = space.fromcache(State)
@@ -1562,25 +1565,54 @@
     state.package_context = name, path
     try:
         initfunc = rffi.cast(initfunctype, initptr)
-        w_mod = generic_cpy_call(space, initfunc)
+        initret = generic_cpy_call_dont_convert_result(space, initfunc)
         state.check_and_raise_exception()
+        if not initret.c_ob_type:
+            raise oefmt(space.w_SystemError,
+                        "init function of %s returned uninitialized object",
+                        name)
+        # This should probably compare by identity with PyModuleDef_Type from
+        # modsupport.c, but I didn't find a way to do that.
+        tp_name_nonconst = rffi.cast(rffi.CCHARP, initret.c_ob_type.c_tp_name)
+        if rffi.charp2str(tp_name_nonconst) == "moduledef":
+            from pypy.module.cpyext.modsupport import \
+                    create_module_from_def_and_spec
+            return create_module_from_def_and_spec(space, initret, w_spec,
+                                                   name)
     finally:
         state.package_context = old_context
+    w_mod = get_w_obj_and_decref(space, initret)
     state.fixup_extension(w_mod, name, path)
     return w_mod
 
+def exec_extension_module(space, w_mod):
+    from pypy.module.cpyext.modsupport import exec_def
+    if not space.config.objspace.usemodules.cpyext:
+        return
+    if not isinstance(w_mod, Module):
+        return
+    space.getbuiltinmodule("cpyext")
+    mod_as_pyobj = rawrefcount.from_obj(PyObject, w_mod)
+    if mod_as_pyobj:
+        return exec_def(space, w_mod, mod_as_pyobj)
+
 @specialize.ll()
 def generic_cpy_call(space, func, *args):
     FT = lltype.typeOf(func).TO
-    return make_generic_cpy_call(FT, False)(space, func, *args)
+    return make_generic_cpy_call(FT, False, True)(space, func, *args)
 
 @specialize.ll()
 def generic_cpy_call_expect_null(space, func, *args):
     FT = lltype.typeOf(func).TO
-    return make_generic_cpy_call(FT, True)(space, func, *args)
+    return make_generic_cpy_call(FT, True, True)(space, func, *args)
+
+@specialize.ll()
+def generic_cpy_call_dont_convert_result(space, func, *args):
+    FT = lltype.typeOf(func).TO
+    return make_generic_cpy_call(FT, False, False)(space, func, *args)
 
 @specialize.memo()
-def make_generic_cpy_call(FT, expect_null):
+def make_generic_cpy_call(FT, expect_null, convert_result):
     from pypy.module.cpyext.pyobject import make_ref, from_ref
     from pypy.module.cpyext.pyobject import is_pyobj, as_pyobj
     from pypy.module.cpyext.pyobject import get_w_obj_and_decref
@@ -1634,8 +1666,9 @@
             keepalive_until_here(*keepalives)
 
         if is_PyObject(RESULT_TYPE):
-            if not is_pyobj(result):
+            if not convert_result or not is_pyobj(result):
                 ret = result
+                has_result = bool(ret)
             else:
                 # The object reference returned from a C function
                 # that is called from Python must be an owned reference
@@ -1644,10 +1677,10 @@
                     ret = get_w_obj_and_decref(space, result)
                 else:
                     ret = None
+                has_result = ret is not None
 
             # Check for exception consistency
             has_error = PyErr_Occurred(space) is not None
-            has_result = ret is not None
             if has_error and has_result:
                 raise oefmt(space.w_SystemError,
                             "An exception was set, but function returned a "
diff --git a/pypy/module/cpyext/include/modsupport.h 
b/pypy/module/cpyext/include/modsupport.h
--- a/pypy/module/cpyext/include/modsupport.h
+++ b/pypy/module/cpyext/include/modsupport.h
@@ -87,9 +87,9 @@
 #ifdef _WIN32
 /* explicitly export since PyAPI_FUNC is usually dllimport */
 #ifdef __cplusplus
-#define PyMODINIT_FUNC extern "C" __declspec(dllexport) void
+#define PyMODINIT_FUNC extern "C" __declspec(dllexport) PyObject*
 #else
-#define PyMODINIT_FUNC __declspec(dllexport) void
+#define PyMODINIT_FUNC __declspec(dllexport) PyObject*
 #endif
 #else
 #ifdef __cplusplus
diff --git a/pypy/module/cpyext/include/moduleobject.h 
b/pypy/module/cpyext/include/moduleobject.h
--- a/pypy/module/cpyext/include/moduleobject.h
+++ b/pypy/module/cpyext/include/moduleobject.h
@@ -8,6 +8,8 @@
 
 #include "cpyext_moduleobject.h"
 
+PyAPI_FUNC(PyObject *) PyModuleDef_Init(struct PyModuleDef*);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/pypy/module/cpyext/modsupport.py b/pypy/module/cpyext/modsupport.py
--- a/pypy/module/cpyext/modsupport.py
+++ b/pypy/module/cpyext/modsupport.py
@@ -1,7 +1,7 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import (
     cpython_api, METH_STATIC, METH_CLASS, METH_COEXIST, CANNOT_FAIL, cts,
-    parse_dir, bootstrap_function)
+    parse_dir, bootstrap_function, generic_cpy_call)
 from pypy.module.cpyext.pyobject import PyObject, as_pyobj, make_typedescr
 from pypy.interpreter.module import Module
 from pypy.module.cpyext.methodobject import (
@@ -14,6 +14,7 @@
 cts.parse_header(parse_dir / 'cpyext_moduleobject.h')
 PyModuleDef = cts.gettype('PyModuleDef *')
 PyModuleObject = cts.gettype('PyModuleObject *')
+PyModuleDef_Slot = cts.gettype('PyModuleDef_Slot')
 
 @bootstrap_function
 def init_moduleobject(space):
@@ -64,6 +65,89 @@
     return w_mod
 
 
+createfunctype = lltype.Ptr(lltype.FuncType([PyObject, PyModuleDef], PyObject))
+execfunctype = lltype.Ptr(lltype.FuncType([PyObject], rffi.INT_real))
+
+
+def create_module_from_def_and_spec(space, moddef, w_spec, name):
+    moddef = rffi.cast(PyModuleDef, moddef)
+    if moddef.c_m_size < 0:
+        raise oefmt(space.w_SystemError,
+                    "module %s: m_size may not be negative for multi-phase "
+                    "initialization", name)
+    createf = lltype.nullptr(rffi.VOIDP.TO)
+    has_execution_slots = False
+    cur_slot = rffi.cast(rffi.CArrayPtr(PyModuleDef_Slot), moddef.c_m_slots)
+    if cur_slot:
+        while True:
+            slot = rffi.cast(lltype.Signed, cur_slot[0].c_slot)
+            if slot == 0:
+                break
+            elif slot == 1:
+                if createf:
+                    raise oefmt(space.w_SystemError,
+                                "module %s has multiple create slots", name)
+                createf = cur_slot[0].c_value
+            elif slot < 0 or slot > 2:
+                raise oefmt(space.w_SystemError,
+                            "module %s uses unknown slot ID %d", name, slot)
+            else:
+                has_execution_slots = True
+            cur_slot = rffi.ptradd(cur_slot, 1)
+    if createf:
+        createf = rffi.cast(createfunctype, createf)
+        w_mod = generic_cpy_call(space, createf, w_spec, moddef)
+    else:
+        w_mod = Module(space, space.newtext(name))
+    if isinstance(w_mod, Module):
+        mod = rffi.cast(PyModuleObject, as_pyobj(space, w_mod))
+        #mod.c_md_state = None
+        mod.c_md_def = moddef
+    else:
+        if moddef.c_m_size > 0 or moddef.c_m_traverse or moddef.c_m_clear or \
+           moddef.c_m_free:
+            raise oefmt(space.w_SystemError,
+                        "module %s is not a module object, but requests "
+                        "module state", name)
+        if has_execution_slots:
+            raise oefmt(space.w_SystemError,
+                        "module %s specifies execution slots, but did not "
+                        "create a ModuleType instance", name)
+    dict_w = {}
+    convert_method_defs(space, dict_w, moddef.c_m_methods, None, w_mod, name)
+    for key, w_value in dict_w.items():
+        space.setattr(w_mod, space.newtext(key), w_value)
+    if moddef.c_m_doc:
+        doc = rffi.charp2str(rffi.cast(rffi.CCHARP, moddef.c_m_doc))
+        space.setattr(w_mod, space.newtext('__doc__'), space.newtext(doc))
+    return w_mod
+
+
+def exec_def(space, w_mod, mod_as_pyobj):
+    from pypy.module.cpyext.pyerrors import PyErr_Occurred
+    mod = rffi.cast(PyModuleObject, mod_as_pyobj)
+    moddef = mod.c_md_def
+    cur_slot = rffi.cast(rffi.CArrayPtr(PyModuleDef_Slot), moddef.c_m_slots)
+    while cur_slot and rffi.cast(lltype.Signed, cur_slot[0].c_slot):
+        if rffi.cast(lltype.Signed, cur_slot[0].c_slot) == 2:
+            execf = rffi.cast(execfunctype, cur_slot[0].c_value)
+            res = generic_cpy_call(space, execf, w_mod)
+            has_error = PyErr_Occurred(space) is not None
+            if rffi.cast(lltype.Signed, res):
+                if has_error:
+                    state = space.fromcache(State)
+                    state.check_and_raise_exception()
+                else:
+                    raise oefmt(space.w_SystemError,
+                                "execution of module %S failed without "
+                                "setting an exception", w_mod.w_name)
+            if has_error:
+                raise oefmt(space.w_SystemError,
+                            "execution of module %S raised unreported "
+                            "exception", w_mod.w_name)
+        cur_slot = rffi.ptradd(cur_slot, 1)
+
+
 def convert_method_defs(space, dict_w, methods, w_type, w_self=None, 
name=None):
     w_name = space.newtext_or_none(name)
     methods = rffi.cast(rffi.CArrayPtr(PyMethodDef), methods)
diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py
--- a/pypy/module/cpyext/slotdefs.py
+++ b/pypy/module/cpyext/slotdefs.py
@@ -4,10 +4,10 @@
 
 from rpython.rtyper.lltypesystem import rffi, lltype
 from rpython.rlib.rarithmetic import widen
-from rpython.rlib import rgc # Force registration of gc.collect
+from rpython.rlib import rgc  # Force registration of gc.collect
 from pypy.module.cpyext.api import (
     slot_function, generic_cpy_call, PyObject, Py_ssize_t,
-    pypy_decl, Py_buffer, Py_bufferP, PyTypeObjectPtr, cts)
+    Py_buffer, Py_bufferP, PyTypeObjectPtr, cts)
 from pypy.module.cpyext.typeobjectdefs import (
     unaryfunc, ternaryfunc, binaryfunc,
     getattrfunc, getattrofunc, setattrofunc, lenfunc, ssizeargfunc, inquiry,
@@ -794,6 +794,16 @@
         return 0
     return buff_w
 
+missing_wrappers = ['wrap_indexargfunc', 'wrap_del']
+for name in missing_wrappers:
+    assert name not in globals()
+    def missing_wrapper(space, w_self, w_args, func):
+        print "cpyext: missing slot wrapper " + name
+        raise NotImplementedError("Slot wrapper " + name)
+    missing_wrapper.__name__ = name
+    globals()[name] = missing_wrapper
+
+
 PyWrapperFlag_KEYWORDS = 1
 
 class TypeSlot:
@@ -811,7 +821,7 @@
     if WRAPPER is None:
         wrapper = None
     else:
-        wrapper = globals().get(WRAPPER, Ellipsis)
+        wrapper = globals()[WRAPPER]
 
     # irregular interface, because of tp_getattr/tp_getattro confusion
     if NAME == "__getattr__":
@@ -825,17 +835,9 @@
     function = getattr(userslot, FUNCTION or '!missing', None)
     assert FLAGS == 0 or FLAGS == PyWrapperFlag_KEYWORDS
     if FLAGS:
-        if wrapper is Ellipsis:
-            @func_renamer(WRAPPER)
-            def wrapper(space, w_self, w_args, func, w_kwds):
-                raise NotImplementedError("Wrapper for slot " + NAME)
         wrapper1 = None
         wrapper2 = wrapper
     else:
-        if wrapper is Ellipsis:
-            @func_renamer(WRAPPER)
-            def wrapper(space, w_self, w_args, func):
-                raise NotImplementedError("Wrapper for slot " + NAME)
         wrapper1 = wrapper
         wrapper2 = None
     return TypeSlot(NAME, SLOT, function, wrapper1, wrapper2, DOC)
diff --git a/pypy/module/cpyext/src/modsupport.c 
b/pypy/module/cpyext/src/modsupport.c
--- a/pypy/module/cpyext/src/modsupport.c
+++ b/pypy/module/cpyext/src/modsupport.c
@@ -602,3 +602,26 @@
     }
     return ((PyModuleObject *)m)->md_def;
 }
+
+PyTypeObject PyModuleDef_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0)
+    "moduledef",                                /* tp_name */
+    sizeof(struct PyModuleDef),                 /* tp_size */
+    0,                                          /* tp_itemsize */
+};
+
+static Py_ssize_t max_module_number;
+
+PyObject*
+PyModuleDef_Init(struct PyModuleDef* def)
+{
+    if (PyType_Ready(&PyModuleDef_Type) < 0)
+         return NULL;
+    if (def->m_base.m_index == 0) {
+        max_module_number++;
+        Py_REFCNT(def) = 1;
+        Py_TYPE(def) = &PyModuleDef_Type;
+        def->m_base.m_index = max_module_number;
+    }
+    return (PyObject*)def;
+}
diff --git a/pypy/module/cpyext/test/buffer_test.c 
b/pypy/module/cpyext/test/buffer_test.c
--- a/pypy/module/cpyext/test/buffer_test.c
+++ b/pypy/module/cpyext/test/buffer_test.c
@@ -344,7 +344,6 @@
 #endif
     if (m == NULL)
         INITERROR;
-    PyMyArrayType.tp_new = PyType_GenericNew;
     if (PyType_Ready(&PyMyArrayType) < 0)
         INITERROR;
     Py_INCREF(&PyMyArrayType);
diff --git a/pypy/module/cpyext/test/comparisons.c 
b/pypy/module/cpyext/test/comparisons.c
--- a/pypy/module/cpyext/test/comparisons.c
+++ b/pypy/module/cpyext/test/comparisons.c
@@ -68,7 +68,7 @@
     0,                                              /* tp_dictoffset */
     0,                                              /* tp_init */
     0,                                              /* tp_alloc */
-    0,                                              /* tp_new */
+    PyType_GenericNew,                              /* tp_new */
     0                                               /* tp_free */
 };
 
@@ -87,7 +87,6 @@
 {
     PyObject *m, *d;
 
-    CmpType.tp_new = PyType_GenericNew;
     if (PyType_Ready(&CmpType) < 0)
         return NULL;
     m = PyModule_Create(&moduledef);
diff --git a/pypy/module/cpyext/test/foo.c b/pypy/module/cpyext/test/foo.c
--- a/pypy/module/cpyext/test/foo.c
+++ b/pypy/module/cpyext/test/foo.c
@@ -36,14 +36,14 @@
     Py_ssize_t foo_ssizet;
 } fooobject;
 
-static PyTypeObject footype;
+static PyTypeObject fooType;
 
 static fooobject *
 newfooobject(void)
 {
     fooobject *foop;
 
-    foop = PyObject_New(fooobject, &footype);
+    foop = PyObject_New(fooobject, &fooType);
     if (foop == NULL)
         return NULL;
 
@@ -160,6 +160,28 @@
     return PyObject_GenericSetAttr((PyObject *)self, name, value);
 }
 
+static PyObject *
+new_fooType(PyTypeObject * t, PyObject *args, PyObject *kwds)
+{
+    PyObject * o;
+    /* copied from numpy scalartypes.c for inherited classes */
+    if (t->tp_bases && (PyTuple_GET_SIZE(t->tp_bases) > 1))
+    {
+        PyTypeObject *sup; 
+        /* We are inheriting from a Python type as well so 
+           give it first dibs on conversion */
+        sup = (PyTypeObject *)PyTuple_GET_ITEM(t->tp_bases, 1);
+        /* Prevent recursion */ 
+        if (new_fooType != sup->tp_new) 
+        {
+            o = sup->tp_new(t, args, kwds);
+            return o;
+        }
+    }
+    o = t->tp_alloc(t, 0);
+    return o;   
+};
+
 static PyMemberDef foo_members[] = {
     {"int_member", T_INT, offsetof(fooobject, foo), 0,
      "A helpful docstring."},
@@ -194,7 +216,7 @@
 
 PyDoc_STRVAR(foo_doc, "foo is for testing.");
 
-static PyTypeObject footype = {
+static PyTypeObject fooType = {
     PyVarObject_HEAD_INIT(NULL, 0)
     "foo.foo",               /*tp_name*/
     sizeof(fooobject),       /*tp_size*/
@@ -592,7 +614,7 @@
 
     0,          /*tp_init*/
     0,          /*tp_alloc  will be set to PyType_GenericAlloc in module init*/
-    0,          /*tp_new*/
+    PyType_GenericNew, /*tp_new*/
     0,          /*tp_free  Low-level free-memory routine */
     0,          /*tp_is_gc For PyObject_IS_GC */
     0,          /*tp_bases*/
@@ -648,6 +670,37 @@
     return PyInt_FromLong(tf);
 }
 
+static PyTypeObject GetType1 = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "foo.GetType1",          /*tp_name*/
+    sizeof(PyObject),        /*tp_size*/
+};
+static PyTypeObject GetType2 = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "foo.GetType2",          /*tp_name*/
+    sizeof(PyObject),        /*tp_size*/
+};
+static PyObject *gettype1, *gettype2;
+
+static PyObject *gettype1_getattr(PyObject *self, char *name)
+{
+    char buf[200];
+    strcpy(buf, "getattr:");
+    strcat(buf, name);
+    return PyBytes_FromString(buf);
+}
+static PyObject *gettype2_getattro(PyObject *self, PyObject *name)
+{
+    char buf[200];
+    PyObject* temp;
+    temp = PyUnicode_AsASCIIString(name);
+    if (temp == NULL) return NULL;
+    strcpy(buf, "getattro:");
+    strcat(buf, PyBytes_AS_STRING(temp));
+    return PyBytes_FromString(buf);
+}
+
+
 /* List of functions exported by this module */
 
 static PyMethodDef foo_functions[] = {
@@ -706,13 +759,14 @@
     if (module == NULL)
         INITERROR;
 
-    footype.tp_new = PyType_GenericNew;
-
     UnicodeSubtype.tp_base = &PyUnicode_Type;
     UnicodeSubtype2.tp_base = &UnicodeSubtype;
     MetaType.tp_base = &PyType_Type;
 
-    if (PyType_Ready(&footype) < 0)
+    fooType.tp_new = &new_fooType;
+    InitErrType.tp_new = PyType_GenericNew;
+
+    if (PyType_Ready(&fooType) < 0)
         INITERROR;
     if (PyType_Ready(&UnicodeSubtype) < 0)
         INITERROR;
@@ -725,8 +779,6 @@
     if (PyType_Ready(&SimplePropertyType) < 0)
         INITERROR;
 
-    SimplePropertyType.tp_new = PyType_GenericNew;
-    InitErrType.tp_new = PyType_GenericNew;
 
     Py_TYPE(&CustomType) = &MetaType;
     if (PyType_Ready(&CustomType) < 0)
@@ -744,11 +796,23 @@
     if (PyType_Ready(&TupleLike) < 0)
         INITERROR;
 
+    GetType1.tp_flags = Py_TPFLAGS_DEFAULT;
+    GetType1.tp_getattr = &gettype1_getattr;
+    if (PyType_Ready(&GetType1) < 0)
+        INITERROR;
+    gettype1 = PyObject_New(PyObject, &GetType1);
+
+    GetType2.tp_flags = Py_TPFLAGS_DEFAULT;
+    GetType2.tp_getattro = &gettype2_getattro;
+    if (PyType_Ready(&GetType2) < 0)
+        INITERROR;
+    gettype2 = PyObject_New(PyObject, &GetType2);
+
 
     d = PyModule_GetDict(module);
     if (d == NULL)
         INITERROR;
-    if (PyDict_SetItemString(d, "fooType", (PyObject *)&footype) < 0)
+    if (PyDict_SetItemString(d, "fooType", (PyObject *)&fooType) < 0)
         INITERROR;
     if (PyDict_SetItemString(d, "UnicodeSubtype", (PyObject *) 
&UnicodeSubtype) < 0)
         INITERROR;
@@ -766,6 +830,10 @@
         INITERROR;
     if (PyDict_SetItemString(d, "TupleLike", (PyObject *) &TupleLike) < 0)
         INITERROR;
+    if (PyDict_SetItemString(d, "gettype1", gettype1) < 0)
+        INITERROR;
+    if (PyDict_SetItemString(d, "gettype2", gettype2) < 0)
+        INITERROR;
 #if PY_MAJOR_VERSION >=3
     return module;
 #endif
diff --git a/pypy/module/cpyext/test/multiphase.c 
b/pypy/module/cpyext/test/multiphase.c
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/multiphase.c
@@ -0,0 +1,28 @@
+#include "Python.h"
+
+static struct PyModuleDef multiphase_def;
+
+static PyObject *check_getdef_same(PyObject *self, PyObject *args) {
+    return PyBool_FromLong(PyModule_GetDef(self) == &multiphase_def);
+}
+
+static PyMethodDef methods[] = {
+    {"check_getdef_same", check_getdef_same, METH_NOARGS},
+    {NULL}
+};
+
+static PyModuleDef multiphase_def = {
+    PyModuleDef_HEAD_INIT, /* m_base */
+    "multiphase",          /* m_name */
+    "example docstring",   /* m_doc */
+    0,                     /* m_size */
+    methods,               /* m_methods */
+    NULL,                  /* m_slots */
+    NULL,                  /* m_traverse */
+    NULL,                  /* m_clear */
+    NULL,                  /* m_free */
+};
+
+PyMODINIT_FUNC PyInit_multiphase(void) {
+    return PyModuleDef_Init(&multiphase_def);
+}
diff --git a/pypy/module/cpyext/test/test_classobject.py 
b/pypy/module/cpyext/test/test_classobject.py
--- a/pypy/module/cpyext/test/test_classobject.py
+++ b/pypy/module/cpyext/test/test_classobject.py
@@ -27,15 +27,3 @@
         InstanceMethod.testmethod.attribute = "test"
         assert testfunction.attribute == "test"
         raises(AttributeError, setattr, inst.testmethod, "attribute", "test")
-
-    def test_pyclass_new_no_bases(self):
-        module = self.import_extension('foo', [
-            ("new_foo", "METH_O",
-             """
-                 return PyClass_New(NULL, PyDict_New(), args);
-             """)])
-        FooClass = module.new_foo("FooClass")
-        class Cls1:
-            pass
-        assert type(FooClass) is type(Cls1)
-        assert FooClass.__bases__ == Cls1.__bases__
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
@@ -40,9 +40,11 @@
 
     def load_module(self, mod, name):
         space = self.space
-        api.load_extension_module(space, mod, name)
-        return space.getitem(
-            space.sys.get('modules'), space.wrap(name))
+        w_path = space.newtext(mod)
+        w_name = space.newtext(name)
+        return space.appexec([w_name, w_path], '''(name, path):
+            import imp
+            return imp.load_dynamic(name, path)''')
 
 
 def get_cpyext_info(space):
diff --git a/pypy/module/cpyext/test/test_memoryobject.py 
b/pypy/module/cpyext/test/test_memoryobject.py
--- a/pypy/module/cpyext/test/test_memoryobject.py
+++ b/pypy/module/cpyext/test/test_memoryobject.py
@@ -187,6 +187,10 @@
                           " on too long format string"
         finally:
             warnings.resetwarnings()
+        # calling get_buffer_info on x creates a memory leak,
+        # which is detected as an error at test teardown:
+        # Exception TypeError: "'NoneType' object is not callable"
+        #         in <bound method ConcreteArray.__del__ ...> ignored
 
     def test_releasebuffer(self):
         if not self.runappdirect:
diff --git a/pypy/module/cpyext/test/test_module.py 
b/pypy/module/cpyext/test/test_module.py
--- a/pypy/module/cpyext/test/test_module.py
+++ b/pypy/module/cpyext/test/test_module.py
@@ -25,12 +25,85 @@
         module = self.import_extension('foo', [
             ("check_getdef_same", "METH_NOARGS",
              """
-                 return PyBool_FromLong(PyModule_GetDef(mod_global) == 
&moduledef);
+                 return PyBool_FromLong(PyModule_GetDef(self) == &moduledef);
              """
             )], prologue="""
             static struct PyModuleDef moduledef;
-            static PyObject *mod_global;
-            """, more_init="""
-               mod_global = mod;
             """)
         assert module.check_getdef_same()
+
+
+class AppTestMultiPhase(AppTestCpythonExtensionBase):
+    def test_basic(self):
+        from types import ModuleType
+        module = self.import_module(name='multiphase')
+        assert isinstance(module, ModuleType)
+        assert module.__name__ == 'multiphase'
+        assert module.__doc__ == "example docstring"
+
+    def test_getdef(self):
+        from types import ModuleType
+        module = self.import_module(name='multiphase')
+        assert module.check_getdef_same()
+
+    def test_slots(self):
+        from types import ModuleType
+        body = """
+        static PyModuleDef multiphase_def;
+
+        static PyObject* multiphase_create(PyObject *spec, PyModuleDef *def) {
+            PyObject *module = PyModule_New("altname");
+            PyObject_SetAttrString(module, "create_spec", spec);
+            PyObject_SetAttrString(module, "create_def_eq",
+                                   PyBool_FromLong(def == &multiphase_def));
+            return module;
+        }
+
+        static int multiphase_exec(PyObject* module) {
+            Py_INCREF(Py_True);
+            PyObject_SetAttrString(module, "exec_called", Py_True);
+            return 0;
+        }
+
+        static PyModuleDef_Slot multiphase_slots[] = {
+            {Py_mod_create, multiphase_create},
+            {Py_mod_exec, multiphase_exec},
+            {0, NULL}
+        };
+
+        static PyModuleDef multiphase_def = {
+            PyModuleDef_HEAD_INIT,                      /* m_base */
+            "multiphase",                               /* m_name */
+            "example docstring",                        /* m_doc */
+            0,                                          /* m_size */
+            NULL,                                       /* m_methods */
+            multiphase_slots,                           /* m_slots */
+            NULL,                                       /* m_traverse */
+            NULL,                                       /* m_clear */
+            NULL,                                       /* m_free */
+        };
+        """
+        init = """
+        return PyModuleDef_Init(&multiphase_def);
+        """
+        module = self.import_module(name='multiphase', body=body, init=init)
+        assert module.create_spec
+        assert module.create_spec is module.__spec__
+        assert module.create_def_eq
+        assert module.exec_called
+
+    def test_forget_init(self):
+        from types import ModuleType
+        body = """
+        static PyModuleDef multiphase_def = {
+            PyModuleDef_HEAD_INIT,                      /* m_base */
+            "multiphase",                               /* m_name */
+            "example docstring",                        /* m_doc */
+            0,                                          /* m_size */
+        };
+        """
+        init = """
+        return (PyObject *) &multiphase_def;
+        """
+        raises(SystemError, self.import_module, name='multiphase', body=body,
+               init=init)
diff --git a/pypy/module/cpyext/test/test_typeobject.py 
b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -16,12 +16,12 @@
         assert 'foo' in sys.modules
         assert "copy" in dir(module.fooType)
         obj = module.new()
-        print(obj.foo)
+        #print(obj.foo)
         assert obj.foo == 42
-        print("Obj has type", type(obj))
+        #print("Obj has type", type(obj))
         assert type(obj) is module.fooType
-        print("type of obj has type", type(type(obj)))
-        print("type of type of obj has type", type(type(type(obj))))
+        #print("type of obj has type", type(type(obj)))
+        #print("type of type of obj has type", type(type(type(obj))))
         assert module.fooType.__doc__ == "foo is for testing."
 
     def test_typeobject_method_descriptor(self):
@@ -949,6 +949,8 @@
             pass
         class foo(f2, f1):
             pass
+
+        x = foo()
         assert bar.__base__ is f2
         # On cpython, the size changes.
         if '__pypy__' in sys.builtin_module_names:
@@ -1159,8 +1161,8 @@
                   ((PyHeapTypeObject*)Base2)->ht_name = dummyname;
                   ((PyHeapTypeObject*)Base12)->ht_name = dummyname;
                 }
-                #endif 
-                #endif 
+                #endif
+                #endif
                 Base1->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | 
Py_TPFLAGS_HEAPTYPE;
                 Base2->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | 
Py_TPFLAGS_HEAPTYPE;
                 Base12->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE;
@@ -1198,24 +1200,13 @@
         bases = module.foo(C)
         assert bases == (A, B)
 
-    def test_multiple_inheritance_old_style_base(self):
-        module = self.import_extension('foo', [
-           ("foo", "METH_O",
-            '''
-                PyTypeObject *tp;
-                tp = (PyTypeObject*)args;
-                Py_INCREF(tp->tp_bases);
-                return tp->tp_bases;
-            '''
-            )])
-        # used to segfault after some iterations
-        for i in range(11):
-            print i
-            class A(object):
-                pass
-            class B:
-                pass
-            class C(A, B):
-                pass
-            bases = module.foo(C)
-            assert bases == (A, B)
+    def test_getattr_getattro(self):
+        module = self.import_module(name='foo')
+        assert module.gettype2.dcba == b'getattro:dcba'
+        assert (type(module.gettype2).__getattribute__(module.gettype2, 'dcBA')
+            == b'getattro:dcBA')
+        assert module.gettype1.abcd == b'getattr:abcd'
+        # GetType1 objects have a __getattribute__ method, but this
+        # doesn't call tp_getattr at all, also on CPython
+        raises(AttributeError, type(module.gettype1).__getattribute__,
+                               module.gettype1, 'dcBA')
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -682,10 +682,6 @@
         if pto.c_tp_itemsize < pto.c_tp_base.c_tp_itemsize:
             pto.c_tp_itemsize = pto.c_tp_base.c_tp_itemsize
 
-    if space.is_w(w_type, space.w_object):
-        # will be filled later on with the correct value
-        # may not be 0
-        pto.c_tp_new = cts.cast('newfunc', 1)
     update_all_slots(space, w_type, pto)
     if not pto.c_tp_new:
         base_object_pyo = make_ref(space, space.w_object)
diff --git a/pypy/module/exceptions/__init__.py 
b/pypy/module/exceptions/__init__.py
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to