[pypy-commit] pypy py3k-clock_get_info: merge py3k

pjenvey pypy.commits at gmail.com
Fri May 27 21:20:09 EDT 2016


Author: Philip Jenvey <pjenvey at underboss.org>
Branch: py3k-clock_get_info
Changeset: r84768:fa4ea2faa429
Date: 2016-05-27 18:16 -0700
http://bitbucket.org/pypy/pypy/changeset/fa4ea2faa429/

Log:	merge py3k

diff too long, truncating to 2000 out of 2645 lines

diff --git a/lib-python/3/ensurepip/__init__.py b/lib-python/3/ensurepip/__init__.py
new file mode 100644
--- /dev/null
+++ b/lib-python/3/ensurepip/__init__.py
@@ -0,0 +1,210 @@
+import os
+import os.path
+import pkgutil
+import sys
+import tempfile
+
+
+__all__ = ["version", "bootstrap"]
+
+
+_SETUPTOOLS_VERSION = "21.2.1"
+
+_PIP_VERSION = "8.1.2"
+
+# pip currently requires ssl support, so we try to provide a nicer
+# error message when that is missing (http://bugs.python.org/issue19744)
+_MISSING_SSL_MESSAGE = ("pip {} requires SSL/TLS".format(_PIP_VERSION))
+try:
+    import ssl
+except ImportError:
+    ssl = None
+    def _require_ssl_for_pip():
+        raise RuntimeError(_MISSING_SSL_MESSAGE)
+else:
+    def _require_ssl_for_pip():
+        pass
+
+_PROJECTS = [
+    ("setuptools", _SETUPTOOLS_VERSION),
+    ("pip", _PIP_VERSION),
+]
+
+
+def _run_pip(args, additional_paths=None):
+    # Add our bundled software to the sys.path so we can import it
+    if additional_paths is not None:
+        sys.path = additional_paths + sys.path
+
+    # Install the bundled software
+    import pip
+    pip.main(args)
+
+
+def version():
+    """
+    Returns a string specifying the bundled version of pip.
+    """
+    return _PIP_VERSION
+
+def _disable_pip_configuration_settings():
+    # We deliberately ignore all pip environment variables
+    # when invoking pip
+    # See http://bugs.python.org/issue19734 for details
+    keys_to_remove = [k for k in os.environ if k.startswith("PIP_")]
+    for k in keys_to_remove:
+        del os.environ[k]
+    # We also ignore the settings in the default pip configuration file
+    # See http://bugs.python.org/issue20053 for details
+    os.environ['PIP_CONFIG_FILE'] = os.devnull
+
+
+def bootstrap(*, root=None, upgrade=False, user=False,
+              altinstall=False, default_pip=False,
+              verbosity=0):
+    """
+    Bootstrap pip into the current Python installation (or the given root
+    directory).
+
+    Note that calling this function will alter both sys.path and os.environ.
+    """
+    if altinstall and default_pip:
+        raise ValueError("Cannot use altinstall and default_pip together")
+
+    _require_ssl_for_pip()
+    _disable_pip_configuration_settings()
+
+    # By default, installing pip and setuptools installs all of the
+    # following scripts (X.Y == running Python version):
+    #
+    #   pip, pipX, pipX.Y, easy_install, easy_install-X.Y
+    #
+    # pip 1.5+ allows ensurepip to request that some of those be left out
+    if altinstall:
+        # omit pip, pipX and easy_install
+        os.environ["ENSUREPIP_OPTIONS"] = "altinstall"
+    elif not default_pip:
+        # omit pip and easy_install
+        os.environ["ENSUREPIP_OPTIONS"] = "install"
+
+    with tempfile.TemporaryDirectory() as tmpdir:
+        # Put our bundled wheels into a temporary directory and construct the
+        # additional paths that need added to sys.path
+        additional_paths = []
+        for project, version in _PROJECTS:
+            wheel_name = "{}-{}-py2.py3-none-any.whl".format(project, version)
+            whl = pkgutil.get_data(
+                "ensurepip",
+                "_bundled/{}".format(wheel_name),
+            )
+            with open(os.path.join(tmpdir, wheel_name), "wb") as fp:
+                fp.write(whl)
+
+            additional_paths.append(os.path.join(tmpdir, wheel_name))
+
+        # Construct the arguments to be passed to the pip command
+        args = ["install", "--no-index", "--find-links", tmpdir]
+        if root:
+            args += ["--root", root]
+        if upgrade:
+            args += ["--upgrade"]
+        if user:
+            args += ["--user"]
+        if verbosity:
+            args += ["-" + "v" * verbosity]
+
+        _run_pip(args + [p[0] for p in _PROJECTS], additional_paths)
+
+def _uninstall_helper(*, verbosity=0):
+    """Helper to support a clean default uninstall process on Windows
+
+    Note that calling this function may alter os.environ.
+    """
+    # Nothing to do if pip was never installed, or has been removed
+    try:
+        import pip
+    except ImportError:
+        return
+
+    # If the pip version doesn't match the bundled one, leave it alone
+    if pip.__version__ != _PIP_VERSION:
+        msg = ("ensurepip will only uninstall a matching version "
+               "({!r} installed, {!r} bundled)")
+        print(msg.format(pip.__version__, _PIP_VERSION), file=sys.stderr)
+        return
+
+    _require_ssl_for_pip()
+    _disable_pip_configuration_settings()
+
+    # Construct the arguments to be passed to the pip command
+    args = ["uninstall", "-y", "--disable-pip-version-check"]
+    if verbosity:
+        args += ["-" + "v" * verbosity]
+
+    _run_pip(args + [p[0] for p in reversed(_PROJECTS)])
+
+
+def _main(argv=None):
+    if ssl is None:
+        print("Ignoring ensurepip failure: {}".format(_MISSING_SSL_MESSAGE),
+              file=sys.stderr)
+        return
+
+    import argparse
+    parser = argparse.ArgumentParser(prog="python -m ensurepip")
+    parser.add_argument(
+        "--version",
+        action="version",
+        version="pip {}".format(version()),
+        help="Show the version of pip that is bundled with this Python.",
+    )
+    parser.add_argument(
+        "-v", "--verbose",
+        action="count",
+        default=0,
+        dest="verbosity",
+        help=("Give more output. Option is additive, and can be used up to 3 "
+              "times."),
+    )
+    parser.add_argument(
+        "-U", "--upgrade",
+        action="store_true",
+        default=False,
+        help="Upgrade pip and dependencies, even if already installed.",
+    )
+    parser.add_argument(
+        "--user",
+        action="store_true",
+        default=False,
+        help="Install using the user scheme.",
+    )
+    parser.add_argument(
+        "--root",
+        default=None,
+        help="Install everything relative to this alternate root directory.",
+    )
+    parser.add_argument(
+        "--altinstall",
+        action="store_true",
+        default=False,
+        help=("Make an alternate install, installing only the X.Y versioned"
+              "scripts (Default: pipX, pipX.Y, easy_install-X.Y)"),
+    )
+    parser.add_argument(
+        "--default-pip",
+        action="store_true",
+        default=False,
+        help=("Make a default pip install, installing the unqualified pip "
+              "and easy_install in addition to the versioned scripts"),
+    )
+
+    args = parser.parse_args(argv)
+
+    bootstrap(
+        root=args.root,
+        upgrade=args.upgrade,
+        user=args.user,
+        verbosity=args.verbosity,
+        altinstall=args.altinstall,
+        default_pip=args.default_pip,
+    )
diff --git a/lib-python/3/ensurepip/__main__.py b/lib-python/3/ensurepip/__main__.py
new file mode 100644
--- /dev/null
+++ b/lib-python/3/ensurepip/__main__.py
@@ -0,0 +1,4 @@
+import ensurepip
+
+if __name__ == "__main__":
+    ensurepip._main()
diff --git a/lib-python/3/ensurepip/_bundled/pip-8.1.2-py2.py3-none-any.whl b/lib-python/3/ensurepip/_bundled/pip-8.1.2-py2.py3-none-any.whl
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cc49227a0c7e13757f4863a9b7ace1eb56c3ce61
GIT binary patch

[cut]

diff --git a/lib-python/3/ensurepip/_bundled/setuptools-21.2.1-py2.py3-none-any.whl b/lib-python/3/ensurepip/_bundled/setuptools-21.2.1-py2.py3-none-any.whl
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fe36464f79ba87960c33f3bdff817deb9e4e5f7c
GIT binary patch

[cut]

diff --git a/lib-python/3/ensurepip/_uninstall.py b/lib-python/3/ensurepip/_uninstall.py
new file mode 100644
--- /dev/null
+++ b/lib-python/3/ensurepip/_uninstall.py
@@ -0,0 +1,30 @@
+"""Basic pip uninstallation support, helper for the Windows uninstaller"""
+
+import argparse
+import ensurepip
+
+
+def _main(argv=None):
+    parser = argparse.ArgumentParser(prog="python -m ensurepip._uninstall")
+    parser.add_argument(
+        "--version",
+        action="version",
+        version="pip {}".format(ensurepip.version()),
+        help="Show the version of pip this will attempt to uninstall.",
+    )
+    parser.add_argument(
+        "-v", "--verbose",
+        action="count",
+        default=0,
+        dest="verbosity",
+        help=("Give more output. Option is additive, and can be used up to 3 "
+              "times."),
+    )
+
+    args = parser.parse_args(argv)
+
+    ensurepip._uninstall_helper(verbosity=args.verbosity)
+
+
+if __name__ == "__main__":
+    _main()
diff --git a/lib-python/3/importlib/_bootstrap.py b/lib-python/3/importlib/_bootstrap.py
--- a/lib-python/3/importlib/_bootstrap.py
+++ b/lib-python/3/importlib/_bootstrap.py
@@ -768,7 +768,7 @@
         else:
             registry_key = cls.REGISTRY_KEY
         key = registry_key.format(fullname=fullname,
-                                  sys_version=sys.version[:3])
+                                  sys_version='%d.%d' % sys.version_info[:2])
         try:
             with cls._open_registry(key) as hkey:
                 filepath = _winreg.QueryValue(hkey, "")
diff --git a/lib-python/3/subprocess.py b/lib-python/3/subprocess.py
--- a/lib-python/3/subprocess.py
+++ b/lib-python/3/subprocess.py
@@ -976,15 +976,18 @@
             c2pread, c2pwrite = -1, -1
             errread, errwrite = -1, -1
 
+            ispread = False
             if stdin is None:
                 p2cread = _winapi.GetStdHandle(_winapi.STD_INPUT_HANDLE)
                 if p2cread is None:
                     p2cread, _ = _winapi.CreatePipe(None, 0)
                     p2cread = Handle(p2cread)
                     _winapi.CloseHandle(_)
+                    ispread = True
             elif stdin == PIPE:
                 p2cread, p2cwrite = _winapi.CreatePipe(None, 0)
                 p2cread, p2cwrite = Handle(p2cread), Handle(p2cwrite)
+                ispread = True
             elif stdin == DEVNULL:
                 p2cread = msvcrt.get_osfhandle(self._get_devnull())
             elif isinstance(stdin, int):
@@ -992,17 +995,20 @@
             else:
                 # Assuming file-like object
                 p2cread = msvcrt.get_osfhandle(stdin.fileno())
-            p2cread = self._make_inheritable(p2cread)
+            p2cread = self._make_inheritable(p2cread, ispread)
 
+            ispwrite = False
             if stdout is None:
                 c2pwrite = _winapi.GetStdHandle(_winapi.STD_OUTPUT_HANDLE)
                 if c2pwrite is None:
                     _, c2pwrite = _winapi.CreatePipe(None, 0)
                     c2pwrite = Handle(c2pwrite)
                     _winapi.CloseHandle(_)
+                    ispwrite = True
             elif stdout == PIPE:
                 c2pread, c2pwrite = _winapi.CreatePipe(None, 0)
                 c2pread, c2pwrite = Handle(c2pread), Handle(c2pwrite)
+                ispwrite = True
             elif stdout == DEVNULL:
                 c2pwrite = msvcrt.get_osfhandle(self._get_devnull())
             elif isinstance(stdout, int):
@@ -1010,17 +1016,20 @@
             else:
                 # Assuming file-like object
                 c2pwrite = msvcrt.get_osfhandle(stdout.fileno())
-            c2pwrite = self._make_inheritable(c2pwrite)
+            c2pwrite = self._make_inheritable(c2pwrite, ispwrite)
 
+            ispwrite = False
             if stderr is None:
                 errwrite = _winapi.GetStdHandle(_winapi.STD_ERROR_HANDLE)
                 if errwrite is None:
                     _, errwrite = _winapi.CreatePipe(None, 0)
                     errwrite = Handle(errwrite)
                     _winapi.CloseHandle(_)
+                    ispwrite = True
             elif stderr == PIPE:
                 errread, errwrite = _winapi.CreatePipe(None, 0)
                 errread, errwrite = Handle(errread), Handle(errwrite)
+                ispwrite = True
             elif stderr == STDOUT:
                 errwrite = c2pwrite
             elif stderr == DEVNULL:
@@ -1030,19 +1039,23 @@
             else:
                 # Assuming file-like object
                 errwrite = msvcrt.get_osfhandle(stderr.fileno())
-            errwrite = self._make_inheritable(errwrite)
+            errwrite = self._make_inheritable(errwrite, ispwrite)
 
             return (p2cread, p2cwrite,
                     c2pread, c2pwrite,
                     errread, errwrite)
 
 
-        def _make_inheritable(self, handle):
+        def _make_inheritable(self, handle, close=False):
             """Return a duplicate of handle, which is inheritable"""
             h = _winapi.DuplicateHandle(
                 _winapi.GetCurrentProcess(), handle,
                 _winapi.GetCurrentProcess(), 0, 1,
                 _winapi.DUPLICATE_SAME_ACCESS)
+            # PyPy: If the initial handle was obtained with CreatePipe,
+            # close it.
+            if close:
+                handle.Close()
             return Handle(h)
 
 
diff --git a/lib-python/3/test/test_ensurepip.py b/lib-python/3/test/test_ensurepip.py
new file mode 100644
--- /dev/null
+++ b/lib-python/3/test/test_ensurepip.py
@@ -0,0 +1,360 @@
+import unittest
+import unittest.mock
+import test.support
+import os
+import os.path
+import contextlib
+import sys
+
+import ensurepip
+import ensurepip._uninstall
+
+# pip currently requires ssl support, so we ensure we handle
+# it being missing (http://bugs.python.org/issue19744)
+ensurepip_no_ssl = test.support.import_fresh_module("ensurepip",
+                                                    blocked=["ssl"])
+try:
+    import ssl
+except ImportError:
+    def requires_usable_pip(f):
+        deco = unittest.skip(ensurepip._MISSING_SSL_MESSAGE)
+        return deco(f)
+else:
+    def requires_usable_pip(f):
+        return f
+
+class TestEnsurePipVersion(unittest.TestCase):
+
+    def test_returns_version(self):
+        self.assertEqual(ensurepip._PIP_VERSION, ensurepip.version())
+
+class EnsurepipMixin:
+
+    def setUp(self):
+        run_pip_patch = unittest.mock.patch("ensurepip._run_pip")
+        self.run_pip = run_pip_patch.start()
+        self.addCleanup(run_pip_patch.stop)
+
+        # Avoid side effects on the actual os module
+        real_devnull = os.devnull
+        os_patch = unittest.mock.patch("ensurepip.os")
+        patched_os = os_patch.start()
+        self.addCleanup(os_patch.stop)
+        patched_os.devnull = real_devnull
+        patched_os.path = os.path
+        self.os_environ = patched_os.environ = os.environ.copy()
+
+
+class TestBootstrap(EnsurepipMixin, unittest.TestCase):
+
+    @requires_usable_pip
+    def test_basic_bootstrapping(self):
+        ensurepip.bootstrap()
+
+        self.run_pip.assert_called_once_with(
+            [
+                "install", "--no-index", "--find-links",
+                unittest.mock.ANY, "setuptools", "pip",
+            ],
+            unittest.mock.ANY,
+        )
+
+        additional_paths = self.run_pip.call_args[0][1]
+        self.assertEqual(len(additional_paths), 2)
+
+    @requires_usable_pip
+    def test_bootstrapping_with_root(self):
+        ensurepip.bootstrap(root="/foo/bar/")
+
+        self.run_pip.assert_called_once_with(
+            [
+                "install", "--no-index", "--find-links",
+                unittest.mock.ANY, "--root", "/foo/bar/",
+                "setuptools", "pip",
+            ],
+            unittest.mock.ANY,
+        )
+
+    @requires_usable_pip
+    def test_bootstrapping_with_user(self):
+        ensurepip.bootstrap(user=True)
+
+        self.run_pip.assert_called_once_with(
+            [
+                "install", "--no-index", "--find-links",
+                unittest.mock.ANY, "--user", "setuptools", "pip",
+            ],
+            unittest.mock.ANY,
+        )
+
+    @requires_usable_pip
+    def test_bootstrapping_with_upgrade(self):
+        ensurepip.bootstrap(upgrade=True)
+
+        self.run_pip.assert_called_once_with(
+            [
+                "install", "--no-index", "--find-links",
+                unittest.mock.ANY, "--upgrade", "setuptools", "pip",
+            ],
+            unittest.mock.ANY,
+        )
+
+    @requires_usable_pip
+    def test_bootstrapping_with_verbosity_1(self):
+        ensurepip.bootstrap(verbosity=1)
+
+        self.run_pip.assert_called_once_with(
+            [
+                "install", "--no-index", "--find-links",
+                unittest.mock.ANY, "-v", "setuptools", "pip",
+            ],
+            unittest.mock.ANY,
+        )
+
+    @requires_usable_pip
+    def test_bootstrapping_with_verbosity_2(self):
+        ensurepip.bootstrap(verbosity=2)
+
+        self.run_pip.assert_called_once_with(
+            [
+                "install", "--no-index", "--find-links",
+                unittest.mock.ANY, "-vv", "setuptools", "pip",
+            ],
+            unittest.mock.ANY,
+        )
+
+    @requires_usable_pip
+    def test_bootstrapping_with_verbosity_3(self):
+        ensurepip.bootstrap(verbosity=3)
+
+        self.run_pip.assert_called_once_with(
+            [
+                "install", "--no-index", "--find-links",
+                unittest.mock.ANY, "-vvv", "setuptools", "pip",
+            ],
+            unittest.mock.ANY,
+        )
+
+    @requires_usable_pip
+    def test_bootstrapping_with_regular_install(self):
+        ensurepip.bootstrap()
+        self.assertEqual(self.os_environ["ENSUREPIP_OPTIONS"], "install")
+
+    @requires_usable_pip
+    def test_bootstrapping_with_alt_install(self):
+        ensurepip.bootstrap(altinstall=True)
+        self.assertEqual(self.os_environ["ENSUREPIP_OPTIONS"], "altinstall")
+
+    @requires_usable_pip
+    def test_bootstrapping_with_default_pip(self):
+        ensurepip.bootstrap(default_pip=True)
+        self.assertNotIn("ENSUREPIP_OPTIONS", self.os_environ)
+
+    def test_altinstall_default_pip_conflict(self):
+        with self.assertRaises(ValueError):
+            ensurepip.bootstrap(altinstall=True, default_pip=True)
+        self.assertFalse(self.run_pip.called)
+
+    @requires_usable_pip
+    def test_pip_environment_variables_removed(self):
+        # ensurepip deliberately ignores all pip environment variables
+        # See http://bugs.python.org/issue19734 for details
+        self.os_environ["PIP_THIS_SHOULD_GO_AWAY"] = "test fodder"
+        ensurepip.bootstrap()
+        self.assertNotIn("PIP_THIS_SHOULD_GO_AWAY", self.os_environ)
+
+    @requires_usable_pip
+    def test_pip_config_file_disabled(self):
+        # ensurepip deliberately ignores the pip config file
+        # See http://bugs.python.org/issue20053 for details
+        ensurepip.bootstrap()
+        self.assertEqual(self.os_environ["PIP_CONFIG_FILE"], os.devnull)
+
+ at contextlib.contextmanager
+def fake_pip(version=ensurepip._PIP_VERSION):
+    if version is None:
+        pip = None
+    else:
+        class FakePip():
+            __version__ = version
+        pip = FakePip()
+    sentinel = object()
+    orig_pip = sys.modules.get("pip", sentinel)
+    sys.modules["pip"] = pip
+    try:
+        yield pip
+    finally:
+        if orig_pip is sentinel:
+            del sys.modules["pip"]
+        else:
+            sys.modules["pip"] = orig_pip
+
+class TestUninstall(EnsurepipMixin, unittest.TestCase):
+
+    def test_uninstall_skipped_when_not_installed(self):
+        with fake_pip(None):
+            ensurepip._uninstall_helper()
+        self.assertFalse(self.run_pip.called)
+
+    def test_uninstall_skipped_with_warning_for_wrong_version(self):
+        with fake_pip("not a valid version"):
+            with test.support.captured_stderr() as stderr:
+                ensurepip._uninstall_helper()
+        warning = stderr.getvalue().strip()
+        self.assertIn("only uninstall a matching version", warning)
+        self.assertFalse(self.run_pip.called)
+
+
+    @requires_usable_pip
+    def test_uninstall(self):
+        with fake_pip():
+            ensurepip._uninstall_helper()
+
+        self.run_pip.assert_called_once_with(
+            [
+                "uninstall", "-y", "--disable-pip-version-check", "pip",
+                "setuptools",
+            ]
+        )
+
+    @requires_usable_pip
+    def test_uninstall_with_verbosity_1(self):
+        with fake_pip():
+            ensurepip._uninstall_helper(verbosity=1)
+
+        self.run_pip.assert_called_once_with(
+            [
+                "uninstall", "-y", "--disable-pip-version-check", "-v", "pip",
+                "setuptools",
+            ]
+        )
+
+    @requires_usable_pip
+    def test_uninstall_with_verbosity_2(self):
+        with fake_pip():
+            ensurepip._uninstall_helper(verbosity=2)
+
+        self.run_pip.assert_called_once_with(
+            [
+                "uninstall", "-y", "--disable-pip-version-check", "-vv", "pip",
+                "setuptools",
+            ]
+        )
+
+    @requires_usable_pip
+    def test_uninstall_with_verbosity_3(self):
+        with fake_pip():
+            ensurepip._uninstall_helper(verbosity=3)
+
+        self.run_pip.assert_called_once_with(
+            [
+                "uninstall", "-y", "--disable-pip-version-check", "-vvv",
+                "pip", "setuptools",
+            ]
+        )
+
+    @requires_usable_pip
+    def test_pip_environment_variables_removed(self):
+        # ensurepip deliberately ignores all pip environment variables
+        # See http://bugs.python.org/issue19734 for details
+        self.os_environ["PIP_THIS_SHOULD_GO_AWAY"] = "test fodder"
+        with fake_pip():
+            ensurepip._uninstall_helper()
+        self.assertNotIn("PIP_THIS_SHOULD_GO_AWAY", self.os_environ)
+
+    @requires_usable_pip
+    def test_pip_config_file_disabled(self):
+        # ensurepip deliberately ignores the pip config file
+        # See http://bugs.python.org/issue20053 for details
+        with fake_pip():
+            ensurepip._uninstall_helper()
+        self.assertEqual(self.os_environ["PIP_CONFIG_FILE"], os.devnull)
+
+
+class TestMissingSSL(EnsurepipMixin, unittest.TestCase):
+
+    def setUp(self):
+        sys.modules["ensurepip"] = ensurepip_no_ssl
+        @self.addCleanup
+        def restore_module():
+            sys.modules["ensurepip"] = ensurepip
+        super().setUp()
+
+    def test_bootstrap_requires_ssl(self):
+        self.os_environ["PIP_THIS_SHOULD_STAY"] = "test fodder"
+        with self.assertRaisesRegex(RuntimeError, "requires SSL/TLS"):
+            ensurepip_no_ssl.bootstrap()
+        self.assertFalse(self.run_pip.called)
+        self.assertIn("PIP_THIS_SHOULD_STAY", self.os_environ)
+
+    def test_uninstall_requires_ssl(self):
+        self.os_environ["PIP_THIS_SHOULD_STAY"] = "test fodder"
+        with self.assertRaisesRegex(RuntimeError, "requires SSL/TLS"):
+            with fake_pip():
+                ensurepip_no_ssl._uninstall_helper()
+        self.assertFalse(self.run_pip.called)
+        self.assertIn("PIP_THIS_SHOULD_STAY", self.os_environ)
+
+    def test_main_exits_early_with_warning(self):
+        with test.support.captured_stderr() as stderr:
+            ensurepip_no_ssl._main(["--version"])
+        warning = stderr.getvalue().strip()
+        self.assertTrue(warning.endswith("requires SSL/TLS"), warning)
+        self.assertFalse(self.run_pip.called)
+
+# Basic testing of the main functions and their argument parsing
+
+EXPECTED_VERSION_OUTPUT = "pip " + ensurepip._PIP_VERSION
+
+class TestBootstrappingMainFunction(EnsurepipMixin, unittest.TestCase):
+
+    @requires_usable_pip
+    def test_bootstrap_version(self):
+        with test.support.captured_stderr() as stdout:
+            with self.assertRaises(SystemExit):
+                ensurepip._main(["--version"])
+        result = stdout.getvalue().strip()
+        self.assertEqual(result, EXPECTED_VERSION_OUTPUT)
+        self.assertFalse(self.run_pip.called)
+
+    @requires_usable_pip
+    def test_basic_bootstrapping(self):
+        ensurepip._main([])
+
+        self.run_pip.assert_called_once_with(
+            [
+                "install", "--no-index", "--find-links",
+                unittest.mock.ANY, "setuptools", "pip",
+            ],
+            unittest.mock.ANY,
+        )
+
+        additional_paths = self.run_pip.call_args[0][1]
+        self.assertEqual(len(additional_paths), 2)
+
+class TestUninstallationMainFunction(EnsurepipMixin, unittest.TestCase):
+
+    def test_uninstall_version(self):
+        with test.support.captured_stderr() as stdout:
+            with self.assertRaises(SystemExit):
+                ensurepip._uninstall._main(["--version"])
+        result = stdout.getvalue().strip()
+        self.assertEqual(result, EXPECTED_VERSION_OUTPUT)
+        self.assertFalse(self.run_pip.called)
+
+    @requires_usable_pip
+    def test_basic_uninstall(self):
+        with fake_pip():
+            ensurepip._uninstall._main([])
+
+        self.run_pip.assert_called_once_with(
+            [
+                "uninstall", "-y", "--disable-pip-version-check", "pip",
+                "setuptools",
+            ]
+        )
+
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/lib-python/conftest.py b/lib-python/conftest.py
--- a/lib-python/conftest.py
+++ b/lib-python/conftest.py
@@ -196,6 +196,7 @@
     RegrTest('test_dummy_threading.py', core=True),
     RegrTest('test_dynamic.py'),
     RegrTest('test_email', skip="XXX is a directory"),
+    RegrTest('test_ensurepip.py'),
     RegrTest('test_enumerate.py', core=True),
     RegrTest('test_eof.py', core=True),
     RegrTest('test_epoll.py'),
diff --git a/lib_pypy/_decimal.py b/lib_pypy/_decimal.py
--- a/lib_pypy/_decimal.py
+++ b/lib_pypy/_decimal.py
@@ -161,6 +161,15 @@
 _codecs.register_error('_decimal_encode', _handle_decimaldigits)
 
 
+def _unsafe_check(name, lo, hi, value):
+    if not -_sys.maxsize-1 <= value <= _sys.maxsize:
+        raise OverflowError(
+            "Python int too large to convert to C ssize_t")
+    if not lo <= value <= hi:
+        raise ValueError("valid range for unsafe %s is [%d, %d]" %
+                         (name, lo, hi))
+
+
 # Decimal class
 
 _DEC_MINALLOC = 4
@@ -298,7 +307,8 @@
                 raise ValueError("exponent must be an integer")
             if not -_sys.maxsize-1 <= exponent <= _sys.maxsize:
                 # Compatibility with CPython
-                raise OverflowError()
+                raise OverflowError(
+                    "Python int too large to convert to C ssize_t")
 
         # coefficients
         if not digits and not is_special:
@@ -1501,6 +1511,19 @@
             _mpdec.mpd_free(output)
         return result.decode()
 
+    if _sys.maxsize < 2**63-1:
+        def _unsafe_setprec(self, value):
+            _unsafe_check('prec', 1, 1070000000, value)
+            self._ctx.prec = value
+
+        def _unsafe_setemin(self, value):
+            _unsafe_check('emin', -1070000000, 0, value)
+            self._ctx.emin = value
+
+        def _unsafe_setemax(self, value):
+            _unsafe_check('emax', 0, 1070000000, value)
+            self._ctx.emax = value
+
 
 class _SignalDict(_collections.abc.MutableMapping):
 
diff --git a/lib_pypy/_libmpdec/vccompat.h b/lib_pypy/_libmpdec/vccompat.h
new file mode 100644
--- /dev/null
+++ b/lib_pypy/_libmpdec/vccompat.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2008-2016 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef VCCOMPAT_H
+#define VCCOMPAT_H
+
+
+/* Visual C fixes: no stdint.h, no snprintf ... */
+#ifdef _MSC_VER
+  #include "vcstdint.h"
+  #undef inline
+  #define inline __inline
+  #undef random
+  #define random rand
+  #undef srandom
+  #define srandom srand
+  #undef snprintf
+  #define snprintf sprintf_s
+  #define HAVE_SNPRINTF
+  #undef strncasecmp
+  #define strncasecmp _strnicmp
+  #undef strcasecmp
+  #define strcasecmp _stricmp
+  #undef strtoll
+  #define strtoll _strtoi64
+  #define strdup _strdup
+  #define PRIi64 "I64i"
+  #define PRIu64 "I64u"
+  #define PRIi32 "I32i"
+  #define PRIu32 "I32u"
+#endif
+
+
+#endif /* VCCOMPAT_H */
+
+
+
diff --git a/lib_pypy/_libmpdec/vcdiv64.asm b/lib_pypy/_libmpdec/vcdiv64.asm
new file mode 100644
--- /dev/null
+++ b/lib_pypy/_libmpdec/vcdiv64.asm
@@ -0,0 +1,48 @@
+;
+; Copyright (c) 2008-2016 Stefan Krah. All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+;
+; 1. Redistributions of source code must retain the above copyright
+;    notice, this list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright
+;    notice, this list of conditions and the following disclaimer in the
+;    documentation and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+; ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+; OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+; SUCH DAMAGE.
+;
+
+
+PUBLIC    _mpd_div_words
+_TEXT    SEGMENT
+q$ = 8
+r$ = 16
+hi$ = 24
+lo$ = 32
+d$ = 40
+_mpd_div_words PROC
+    mov    r10, rdx
+    mov    rdx, r8
+    mov    rax, r9
+    div    QWORD PTR d$[rsp]
+    mov    QWORD PTR [r10], rdx
+    mov    QWORD PTR [rcx], rax
+    ret    0
+_mpd_div_words ENDP
+_TEXT    ENDS
+END
+
+
diff --git a/lib_pypy/_libmpdec/vcstdint.h b/lib_pypy/_libmpdec/vcstdint.h
new file mode 100644
--- /dev/null
+++ b/lib_pypy/_libmpdec/vcstdint.h
@@ -0,0 +1,232 @@
+// ISO C9x  compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+//  Copyright (c) 2006-2008 Alexander Chemeris
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//   1. Redistributions of source code must retain the above copyright notice,
+//      this list of conditions and the following disclaimer.
+//
+//   2. Redistributions in binary form must reproduce the above copyright
+//      notice, this list of conditions and the following disclaimer in the
+//      documentation and/or other materials provided with the distribution.
+//
+//   3. The name of the author may be used to endorse or promote products
+//      derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include <limits.h>
+
+// For Visual Studio 6 in C++ mode wrap <wchar.h> include with 'extern "C++" {}'
+// or compiler give many errors like this:
+//   error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#if (_MSC_VER < 1300) && defined(__cplusplus)
+   extern "C++" {
+#endif
+#     include <wchar.h>
+#if (_MSC_VER < 1300) && defined(__cplusplus)
+   }
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+#  if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+#     define _W64 __w64
+#  else
+#     define _W64
+#  endif
+#endif
+
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+typedef __int8            int8_t;
+typedef __int16           int16_t;
+typedef __int32           int32_t;
+typedef __int64           int64_t;
+typedef unsigned __int8   uint8_t;
+typedef unsigned __int16  uint16_t;
+typedef unsigned __int32  uint32_t;
+typedef unsigned __int64  uint64_t;
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t    int_least8_t;
+typedef int16_t   int_least16_t;
+typedef int32_t   int_least32_t;
+typedef int64_t   int_least64_t;
+typedef uint8_t   uint_least8_t;
+typedef uint16_t  uint_least16_t;
+typedef uint32_t  uint_least32_t;
+typedef uint64_t  uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t    int_fast8_t;
+typedef int16_t   int_fast16_t;
+typedef int32_t   int_fast32_t;
+typedef int64_t   int_fast64_t;
+typedef uint8_t   uint_fast8_t;
+typedef uint16_t  uint_fast16_t;
+typedef uint32_t  uint_fast32_t;
+typedef uint64_t  uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+   typedef __int64           intptr_t;
+   typedef unsigned __int64  uintptr_t;
+#else // _WIN64 ][
+   typedef _W64 int               intptr_t;
+   typedef _W64 unsigned int      uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t   intmax_t;
+typedef uint64_t  uintmax_t;
+
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [   See footnote 220 at page 257 and footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN     ((int8_t)_I8_MIN)
+#define INT8_MAX     _I8_MAX
+#define INT16_MIN    ((int16_t)_I16_MIN)
+#define INT16_MAX    _I16_MAX
+#define INT32_MIN    ((int32_t)_I32_MIN)
+#define INT32_MAX    _I32_MAX
+#define INT64_MIN    ((int64_t)_I64_MIN)
+#define INT64_MAX    _I64_MAX
+#define UINT8_MAX    _UI8_MAX
+#define UINT16_MAX   _UI16_MAX
+#define UINT32_MAX   _UI32_MAX
+#define UINT64_MAX   _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN    INT8_MIN
+#define INT_LEAST8_MAX    INT8_MAX
+#define INT_LEAST16_MIN   INT16_MIN
+#define INT_LEAST16_MAX   INT16_MAX
+#define INT_LEAST32_MIN   INT32_MIN
+#define INT_LEAST32_MAX   INT32_MAX
+#define INT_LEAST64_MIN   INT64_MIN
+#define INT_LEAST64_MAX   INT64_MAX
+#define UINT_LEAST8_MAX   UINT8_MAX
+#define UINT_LEAST16_MAX  UINT16_MAX
+#define UINT_LEAST32_MAX  UINT32_MAX
+#define UINT_LEAST64_MAX  UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN    INT8_MIN
+#define INT_FAST8_MAX    INT8_MAX
+#define INT_FAST16_MIN   INT16_MIN
+#define INT_FAST16_MAX   INT16_MAX
+#define INT_FAST32_MIN   INT32_MIN
+#define INT_FAST32_MAX   INT32_MAX
+#define INT_FAST64_MIN   INT64_MIN
+#define INT_FAST64_MAX   INT64_MAX
+#define UINT_FAST8_MAX   UINT8_MAX
+#define UINT_FAST16_MAX  UINT16_MAX
+#define UINT_FAST32_MAX  UINT32_MAX
+#define UINT_FAST64_MAX  UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+#  define INTPTR_MIN   INT64_MIN
+#  define INTPTR_MAX   INT64_MAX
+#  define UINTPTR_MAX  UINT64_MAX
+#else // _WIN64 ][
+#  define INTPTR_MIN   INT32_MIN
+#  define INTPTR_MAX   INT32_MAX
+#  define UINTPTR_MAX  UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN   INT64_MIN
+#define INTMAX_MAX   INT64_MAX
+#define UINTMAX_MAX  UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+#  define PTRDIFF_MIN  _I64_MIN
+#  define PTRDIFF_MAX  _I64_MAX
+#else  // _WIN64 ][
+#  define PTRDIFF_MIN  _I32_MIN
+#  define PTRDIFF_MAX  _I32_MAX
+#endif  // _WIN64 ]
+
+#define SIG_ATOMIC_MIN  INT_MIN
+#define SIG_ATOMIC_MAX  INT_MAX
+
+#ifndef SIZE_MAX // [
+#  ifdef _WIN64 // [
+#     define SIZE_MAX  _UI64_MAX
+#  else // _WIN64 ][
+#     define SIZE_MAX  _UI32_MAX
+#  endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
+#ifndef WCHAR_MIN // [
+#  define WCHAR_MIN  0
+#endif  // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+#  define WCHAR_MAX  _UI16_MAX
+#endif  // WCHAR_MAX ]
+
+#define WINT_MIN  0
+#define WINT_MAX  _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [   See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val)  val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val)  val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+#define INTMAX_C   INT64_C
+#define UINTMAX_C  UINT64_C
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+
+#endif // _MSC_STDINT_H_ ]
diff --git a/lib_pypy/_subprocess.py b/lib_pypy/_subprocess.py
deleted file mode 100644
--- a/lib_pypy/_subprocess.py
+++ /dev/null
@@ -1,214 +0,0 @@
-"""
-Support routines for subprocess module.
-Currently, this extension module is only required when using the
-subprocess module on Windows.
-"""
-
-
-# Declare external Win32 functions
-
-import ctypes
-
-_kernel32 = ctypes.WinDLL('kernel32')
-
-_CloseHandle = _kernel32.CloseHandle
-_CloseHandle.argtypes = [ctypes.c_int]
-_CloseHandle.restype = ctypes.c_int
-
-_CreatePipe = _kernel32.CreatePipe
-_CreatePipe.argtypes = [ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int),
-                        ctypes.c_void_p, ctypes.c_int]
-_CreatePipe.restype = ctypes.c_int
-
-_GetCurrentProcess = _kernel32.GetCurrentProcess
-_GetCurrentProcess.argtypes = []
-_GetCurrentProcess.restype = ctypes.c_int
-
-GetVersion = _kernel32.GetVersion
-GetVersion.argtypes = []
-GetVersion.restype = ctypes.c_int
-
-_DuplicateHandle = _kernel32.DuplicateHandle
-_DuplicateHandle.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_int,
-                             ctypes.POINTER(ctypes.c_int),
-                             ctypes.c_int, ctypes.c_int, ctypes.c_int]
-_DuplicateHandle.restype = ctypes.c_int
-
-_WaitForSingleObject = _kernel32.WaitForSingleObject
-_WaitForSingleObject.argtypes = [ctypes.c_int, ctypes.c_uint]
-_WaitForSingleObject.restype = ctypes.c_int
-
-_GetExitCodeProcess = _kernel32.GetExitCodeProcess
-_GetExitCodeProcess.argtypes = [ctypes.c_int, ctypes.POINTER(ctypes.c_int)]
-_GetExitCodeProcess.restype = ctypes.c_int
-
-_TerminateProcess = _kernel32.TerminateProcess
-_TerminateProcess.argtypes = [ctypes.c_int, ctypes.c_int]
-_TerminateProcess.restype = ctypes.c_int
-
-_GetStdHandle = _kernel32.GetStdHandle
-_GetStdHandle.argtypes = [ctypes.c_int]
-_GetStdHandle.restype = ctypes.c_int
-
-class _STARTUPINFO(ctypes.Structure):
-    _fields_ = [('cb',         ctypes.c_int),
-                ('lpReserved', ctypes.c_void_p),
-                ('lpDesktop',  ctypes.c_char_p),
-                ('lpTitle',    ctypes.c_char_p),
-                ('dwX',        ctypes.c_int),
-                ('dwY',        ctypes.c_int),
-                ('dwXSize',    ctypes.c_int),
-                ('dwYSize',    ctypes.c_int),
-                ('dwXCountChars', ctypes.c_int),
-                ('dwYCountChars', ctypes.c_int),
-                ("dwFillAttribute", ctypes.c_int),
-                ("dwFlags", ctypes.c_int),
-                ("wShowWindow", ctypes.c_short),
-                ("cbReserved2", ctypes.c_short),
-                ("lpReserved2", ctypes.c_void_p),
-                ("hStdInput", ctypes.c_int),
-                ("hStdOutput", ctypes.c_int),
-                ("hStdError", ctypes.c_int)
-                ]
-
-class _PROCESS_INFORMATION(ctypes.Structure):
-    _fields_ = [("hProcess", ctypes.c_int),
-                ("hThread", ctypes.c_int),
-                ("dwProcessID", ctypes.c_int),
-                ("dwThreadID", ctypes.c_int)]
-
-_CreateProcess = _kernel32.CreateProcessW
-_CreateProcess.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_void_p, ctypes.c_void_p,
-                           ctypes.c_int, ctypes.c_int, ctypes.c_wchar_p, ctypes.c_wchar_p,
-                           ctypes.POINTER(_STARTUPINFO), ctypes.POINTER(_PROCESS_INFORMATION)]
-_CreateProcess.restype = ctypes.c_int
-
-del ctypes
-
-# Now the _subprocess module implementation
-
-from ctypes import c_int as _c_int, byref as _byref, WinError as _WinError
-
-class _handle:
-    def __init__(self, handle):
-        self.handle = handle
-
-    def __int__(self):
-        return self.handle
-
-    def __del__(self):
-        if self.handle is not None:
-            _CloseHandle(self.handle)
-
-    def Detach(self):
-        handle, self.handle = self.handle, None
-        return handle
-
-    def Close(self):
-        if self.handle not in (-1, None):
-            _CloseHandle(self.handle)
-            self.handle = None
-
-def CreatePipe(attributes, size):
-    read = _c_int()
-    write = _c_int()
-
-    res = _CreatePipe(_byref(read), _byref(write), None, size)
-
-    if not res:
-        raise _WinError()
-
-    return _handle(read.value), _handle(write.value)
-
-def GetCurrentProcess():
-    return _handle(_GetCurrentProcess())
-
-def DuplicateHandle(source_process, source, target_process, access, inherit, options=0):
-    target = _c_int()
-
-    res = _DuplicateHandle(int(source_process), int(source), int(target_process),
-                           _byref(target),
-                           access, inherit, options)
-
-    if not res:
-        raise _WinError()
-
-    return _handle(target.value)
-
-def CreateProcess(name, command_line, process_attr, thread_attr,
-                  inherit, flags, env, start_dir, startup_info):
-    si = _STARTUPINFO()
-    if startup_info is not None:
-        si.dwFlags = startup_info.dwFlags
-        si.wShowWindow = startup_info.wShowWindow
-        if startup_info.hStdInput:
-            si.hStdInput = int(startup_info.hStdInput)
-        if startup_info.hStdOutput:
-            si.hStdOutput = int(startup_info.hStdOutput)
-        if startup_info.hStdError:
-            si.hStdError = int(startup_info.hStdError)
-
-    pi = _PROCESS_INFORMATION()
-    flags |= CREATE_UNICODE_ENVIRONMENT
-
-    if env is not None:
-        envbuf = ""
-        for k, v in env.items():
-            envbuf += "%s=%s\0" % (k, v)
-        envbuf += '\0'
-    else:
-        envbuf = None
-
-    res = _CreateProcess(name, command_line, None, None, inherit, flags, envbuf,
-                        start_dir, _byref(si), _byref(pi))
-
-    if not res:
-        raise _WinError()
-
-    return _handle(pi.hProcess), _handle(pi.hThread), pi.dwProcessID, pi.dwThreadID
-
-def WaitForSingleObject(handle, milliseconds):
-    res = _WaitForSingleObject(int(handle), milliseconds)
-
-    if res < 0:
-        raise _WinError()
-
-    return res
-
-def GetExitCodeProcess(handle):
-    code = _c_int()
-
-    res = _GetExitCodeProcess(int(handle), _byref(code))
-
-    if not res:
-        raise _WinError()
-
-    return code.value
-
-def TerminateProcess(handle, exitcode):
-    res = _TerminateProcess(int(handle), exitcode)
-
-    if not res:
-        raise _WinError()
-
-def GetStdHandle(stdhandle):
-    res = _GetStdHandle(stdhandle)
-
-    if not res:
-        return None
-    else:
-        return res
-
-STD_INPUT_HANDLE = -10
-STD_OUTPUT_HANDLE = -11
-STD_ERROR_HANDLE = -12
-DUPLICATE_SAME_ACCESS = 2
-STARTF_USESTDHANDLES = 0x100
-STARTF_USESHOWWINDOW = 0x001
-SW_HIDE = 0
-INFINITE = 0xffffffff
-WAIT_OBJECT_0 = 0
-CREATE_NEW_CONSOLE = 0x010
-CREATE_NEW_PROCESS_GROUP = 0x200
-CREATE_UNICODE_ENVIRONMENT = 0x400
-STILL_ACTIVE = 259
diff --git a/lib_pypy/_winapi.py b/lib_pypy/_winapi.py
new file mode 100644
--- /dev/null
+++ b/lib_pypy/_winapi.py
@@ -0,0 +1,237 @@
+"""
+Support routines for subprocess module.
+Currently, this extension module is only required when using the
+subprocess module on Windows.
+"""
+
+import sys
+if sys.platform != 'win32':
+    raise ImportError("The '_subprocess' module is only available on Windows")
+
+# Declare external Win32 functions
+
+import ctypes
+
+_kernel32 = ctypes.WinDLL('kernel32')
+
+_CloseHandle = _kernel32.CloseHandle
+_CloseHandle.argtypes = [ctypes.c_int]
+_CloseHandle.restype = ctypes.c_int
+
+_CreatePipe = _kernel32.CreatePipe
+_CreatePipe.argtypes = [ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int),
+                        ctypes.c_void_p, ctypes.c_int]
+_CreatePipe.restype = ctypes.c_int
+
+_GetCurrentProcess = _kernel32.GetCurrentProcess
+_GetCurrentProcess.argtypes = []
+_GetCurrentProcess.restype = ctypes.c_int
+
+GetVersion = _kernel32.GetVersion
+GetVersion.argtypes = []
+GetVersion.restype = ctypes.c_int
+
+_DuplicateHandle = _kernel32.DuplicateHandle
+_DuplicateHandle.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_int,
+                             ctypes.POINTER(ctypes.c_int),
+                             ctypes.c_int, ctypes.c_int, ctypes.c_int]
+_DuplicateHandle.restype = ctypes.c_int
+
+_WaitForSingleObject = _kernel32.WaitForSingleObject
+_WaitForSingleObject.argtypes = [ctypes.c_int, ctypes.c_uint]
+_WaitForSingleObject.restype = ctypes.c_int
+
+_GetExitCodeProcess = _kernel32.GetExitCodeProcess
+_GetExitCodeProcess.argtypes = [ctypes.c_int, ctypes.POINTER(ctypes.c_int)]
+_GetExitCodeProcess.restype = ctypes.c_int
+
+_TerminateProcess = _kernel32.TerminateProcess
+_TerminateProcess.argtypes = [ctypes.c_int, ctypes.c_int]
+_TerminateProcess.restype = ctypes.c_int
+
+_GetStdHandle = _kernel32.GetStdHandle
+_GetStdHandle.argtypes = [ctypes.c_int]
+_GetStdHandle.restype = ctypes.c_int
+
+_GetModuleFileNameW = _kernel32.GetModuleFileNameW
+_GetModuleFileNameW.argtypes = [ctypes.c_int, ctypes.c_wchar_p, ctypes.c_uint]
+_GetModuleFileNameW.restype = ctypes.c_int
+
+class _STARTUPINFO(ctypes.Structure):
+    _fields_ = [('cb',         ctypes.c_int),
+                ('lpReserved', ctypes.c_void_p),
+                ('lpDesktop',  ctypes.c_char_p),
+                ('lpTitle',    ctypes.c_char_p),
+                ('dwX',        ctypes.c_int),
+                ('dwY',        ctypes.c_int),
+                ('dwXSize',    ctypes.c_int),
+                ('dwYSize',    ctypes.c_int),
+                ('dwXCountChars', ctypes.c_int),
+                ('dwYCountChars', ctypes.c_int),
+                ("dwFillAttribute", ctypes.c_int),
+                ("dwFlags", ctypes.c_int),
+                ("wShowWindow", ctypes.c_short),
+                ("cbReserved2", ctypes.c_short),
+                ("lpReserved2", ctypes.c_void_p),
+                ("hStdInput", ctypes.c_int),
+                ("hStdOutput", ctypes.c_int),
+                ("hStdError", ctypes.c_int)
+                ]
+
+class _PROCESS_INFORMATION(ctypes.Structure):
+    _fields_ = [("hProcess", ctypes.c_int),
+                ("hThread", ctypes.c_int),
+                ("dwProcessID", ctypes.c_int),
+                ("dwThreadID", ctypes.c_int)]
+
+_CreateProcess = _kernel32.CreateProcessW
+_CreateProcess.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_void_p, ctypes.c_void_p,
+                           ctypes.c_int, ctypes.c_int, ctypes.c_wchar_p, ctypes.c_wchar_p,
+                           ctypes.POINTER(_STARTUPINFO), ctypes.POINTER(_PROCESS_INFORMATION)]
+_CreateProcess.restype = ctypes.c_int
+
+del ctypes
+
+# Now the _winapi module implementation
+
+from ctypes import c_int as _c_int, byref as _byref, WinError as _WinError
+
+class _handle:
+    def __init__(self, handle):
+        self.handle = handle
+
+    def __int__(self):
+        return self.handle
+
+    def __del__(self):
+        if self.handle is not None:
+            _CloseHandle(self.handle)
+
+    def Detach(self):
+        handle, self.handle = self.handle, None
+        return handle
+
+    def Close(self):
+        if self.handle not in (-1, None):
+            _CloseHandle(self.handle)
+            self.handle = None
+
+def CreatePipe(attributes, size):
+    read = _c_int()
+    write = _c_int()
+
+    res = _CreatePipe(_byref(read), _byref(write), None, size)
+
+    if not res:
+        raise _WinError()
+
+    return _handle(read.value), _handle(write.value)
+
+def GetCurrentProcess():
+    return _handle(_GetCurrentProcess())
+
+def DuplicateHandle(source_process, source, target_process, access, inherit, options=0):
+    target = _c_int()
+
+    res = _DuplicateHandle(int(source_process), int(source), int(target_process),
+                           _byref(target),
+                           access, inherit, options)
+
+    if not res:
+        raise _WinError()
+
+    return _handle(target.value)
+
+def CreateProcess(name, command_line, process_attr, thread_attr,
+                  inherit, flags, env, start_dir, startup_info):
+    si = _STARTUPINFO()
+    if startup_info is not None:
+        si.dwFlags = startup_info.dwFlags
+        si.wShowWindow = startup_info.wShowWindow
+        if startup_info.hStdInput:
+            si.hStdInput = int(startup_info.hStdInput)
+        if startup_info.hStdOutput:
+            si.hStdOutput = int(startup_info.hStdOutput)
+        if startup_info.hStdError:
+            si.hStdError = int(startup_info.hStdError)
+
+    pi = _PROCESS_INFORMATION()
+    flags |= CREATE_UNICODE_ENVIRONMENT
+
+    if env is not None:
+        envbuf = ""
+        for k, v in env.items():
+            envbuf += "%s=%s\0" % (k, v)
+        envbuf += '\0'
+    else:
+        envbuf = None
+
+    res = _CreateProcess(name, command_line, None, None, inherit, flags, envbuf,
+                        start_dir, _byref(si), _byref(pi))
+
+    if not res:
+        raise _WinError()
+
+    return _handle(pi.hProcess), _handle(pi.hThread), pi.dwProcessID, pi.dwThreadID
+
+def WaitForSingleObject(handle, milliseconds):
+    res = _WaitForSingleObject(int(handle), milliseconds)
+
+    if res < 0:
+        raise _WinError()
+
+    return res
+
+def GetExitCodeProcess(handle):
+    code = _c_int()
+
+    res = _GetExitCodeProcess(int(handle), _byref(code))
+
+    if not res:
+        raise _WinError()
+
+    return code.value
+
+def TerminateProcess(handle, exitcode):
+    res = _TerminateProcess(int(handle), exitcode)
+
+    if not res:
+        raise _WinError()
+
+def GetStdHandle(stdhandle):
+    res = _GetStdHandle(stdhandle)
+
+    if not res:
+        return None
+    else:
+        return res
+
+def CloseHandle(handle):
+    res = _CloseHandle(handle)
+
+    if not res:
+        raise _WinError()
+
+def GetModuleFileName(module):
+    buf = ctypes.create_unicode_buffer(_MAX_PATH)
+    res = _GetModuleFileNameW(module, buf, _MAX_PATH)
+
+    if not res:
+        raise _WinError()
+    return buf.value
+
+STD_INPUT_HANDLE = -10
+STD_OUTPUT_HANDLE = -11
+STD_ERROR_HANDLE = -12
+DUPLICATE_SAME_ACCESS = 2
+STARTF_USESTDHANDLES = 0x100
+STARTF_USESHOWWINDOW = 0x001
+SW_HIDE = 0
+INFINITE = 0xffffffff
+WAIT_OBJECT_0 = 0
+WAIT_TIMEOUT = 0x102
+CREATE_NEW_CONSOLE = 0x010
+CREATE_NEW_PROCESS_GROUP = 0x200
+CREATE_UNICODE_ENVIRONMENT = 0x400
+STILL_ACTIVE = 259
+_MAX_PATH = 260
diff --git a/lib_pypy/cffi/commontypes.py b/lib_pypy/cffi/commontypes.py
--- a/lib_pypy/cffi/commontypes.py
+++ b/lib_pypy/cffi/commontypes.py
@@ -35,8 +35,11 @@
                                "you call ffi.set_unicode()" % (commontype,))
         else:
             if commontype == cdecl:
-                raise api.FFIError("Unsupported type: %r.  Please file a bug "
-                                   "if you think it should be." % (commontype,))
+                raise api.FFIError(
+                    "Unsupported type: %r.  Please look at "
+        "http://cffi.readthedocs.io/en/latest/cdef.html#ffi-cdef-limitations "
+                    "and file an issue if you think this type should really "
+                    "be supported." % (commontype,))
             result, quals = parser.parse_type_and_quals(cdecl)   # recursive
 
         assert isinstance(result, model.BaseTypeByIdentity)
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1193,8 +1193,7 @@
         elif flag == 'S':
             return False
         else:
-            return (self.lookup(w_obj, '__getitem__') is not None and
-                    self.lookup(w_obj, '__getslice__') is None)
+            return self.lookup(w_obj, '__getitem__') is not None
 
     # The code below only works
     # for the simple case (new-style instance).
diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py
--- a/pypy/module/__builtin__/functional.py
+++ b/pypy/module/__builtin__/functional.py
@@ -117,8 +117,17 @@
         else:
             compare = space.lt
             jitdriver = min_jitdriver
+        any_kwds = bool(args.keywords)
         args_w = args.arguments_w
         if len(args_w) > 1:
+            if unroll and len(args_w) == 2 and not any_kwds:
+                # a fast path for the common case, useful for interpreted
+                # mode and to reduce the length of the jit trace
+                w0, w1 = args_w
+                if space.is_true(compare(w1, w0)):
+                    return w1
+                else:
+                    return w0
             w_sequence = space.newtuple(args_w)
         elif len(args_w):
             w_sequence = args_w[0]
@@ -127,8 +136,8 @@
                         "%s() expects at least one argument",
                         implementation_of)
         w_key = None
-        kwds = args.keywords
-        if kwds:
+        if any_kwds:
+            kwds = args.keywords
             if kwds[0] == "key" and len(kwds) == 1:
                 w_key = args.keywords_w[0]
             else:
diff --git a/pypy/module/__builtin__/test/test_functional.py b/pypy/module/__builtin__/test/test_functional.py
--- a/pypy/module/__builtin__/test/test_functional.py
+++ b/pypy/module/__builtin__/test/test_functional.py
@@ -585,6 +585,11 @@
         assert min([1, 2, 3]) == 1
         raises(TypeError, min, 1, 2, bar=2)
         raises(TypeError, min, 1, 2, key=lambda x: x, bar=2)
+        assert type(min(1, 1.0)) is int
+        assert type(min(1.0, 1)) is float
+        assert type(min(1, 1.0, 1L)) is int
+        assert type(min(1.0, 1L, 1)) is float
+        assert type(min(1L, 1, 1.0)) is long
 
     def test_max(self):
         assert max(1, 2) == 2
@@ -592,3 +597,8 @@
         assert max([1, 2, 3]) == 3
         raises(TypeError, max, 1, 2, bar=2)
         raises(TypeError, max, 1, 2, key=lambda x: x, bar=2)
+        assert type(max(1, 1.0)) is int
+        assert type(max(1.0, 1)) is float
+        assert type(max(1, 1.0, 1L)) is int
+        assert type(max(1.0, 1L, 1)) is float
+        assert type(max(1L, 1, 1.0)) is long
diff --git a/pypy/module/_cffi_backend/lib_obj.py b/pypy/module/_cffi_backend/lib_obj.py
--- a/pypy/module/_cffi_backend/lib_obj.py
+++ b/pypy/module/_cffi_backend/lib_obj.py
@@ -196,9 +196,13 @@
                 if is_getattr and attr == '__dict__':
                     return self.full_dict_copy()
                 if is_getattr and attr == '__class__':
-                    return self.space.type(self)
+                    # used to be space.type(self).  But HAAAAAACK!
+                    # That makes help() behave correctly.  I couldn't
+                    # find a more reasonable way.  Urgh.
+                    from pypy.interpreter.module import Module
+                    return self.space.gettypeobject(Module.typedef)
                 if is_getattr and attr == '__name__':
-                    return self.descr_repr()
+                    return self.space.wrap("%s.lib" % self.libname)
                 raise oefmt(self.space.w_AttributeError,
                             "cffi library '%s' has no function, constant "
                             "or global variable named '%s'",
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
@@ -1039,8 +1039,8 @@
         assert MYFOO == 42
         assert hasattr(lib, '__dict__')
         assert lib.__all__ == ['MYFOO', 'mybar']   # but not 'myvar'
-        assert lib.__name__ == repr(lib)
-        assert lib.__class__ is type(lib)
+        assert lib.__name__ == '_CFFI_test_import_from_lib.lib'
+        assert lib.__class__ is type(sys)   # !! hack for help()
 
     def test_macro_var_callback(self):
         ffi, lib = self.prepare(
diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py
--- a/pypy/module/cpyext/cdatetime.py
+++ b/pypy/module/cpyext/cdatetime.py
@@ -1,4 +1,5 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rtyper.annlowlevel import llhelper
 from pypy.module.cpyext.pyobject import PyObject, make_ref
 from pypy.module.cpyext.api import (cpython_api, CANNOT_FAIL, cpython_struct,
     PyObjectFields)
@@ -16,6 +17,23 @@
      ('TimeType', PyTypeObjectPtr),
      ('DeltaType', PyTypeObjectPtr),
      ('TZInfoType', PyTypeObjectPtr),
+
+     ('Date_FromDate', lltype.Ptr(lltype.FuncType(
+         [rffi.INT_real, rffi.INT_real, rffi.INT_real, PyTypeObjectPtr],
+         PyObject))),
+     ('Time_FromTime', lltype.Ptr(lltype.FuncType(
+         [rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+          PyObject, PyTypeObjectPtr],
+         PyObject))),
+     ('DateTime_FromDateAndTime', lltype.Ptr(lltype.FuncType(
+         [rffi.INT_real, rffi.INT_real, rffi.INT_real,
+          rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+          PyObject, PyTypeObjectPtr],
+         PyObject))),
+     ('Delta_FromDelta', lltype.Ptr(lltype.FuncType(
+         [rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+          PyTypeObjectPtr],
+         PyObject))),
      ))
 
 @cpython_api([], lltype.Ptr(PyDateTime_CAPI))
@@ -45,6 +63,19 @@
     datetimeAPI.c_TZInfoType = rffi.cast(
         PyTypeObjectPtr, make_ref(space, w_type))
 
+    datetimeAPI.c_Date_FromDate = llhelper(
+        _PyDate_FromDate.api_func.functype,
+        _PyDate_FromDate.api_func.get_wrapper(space))
+    datetimeAPI.c_Time_FromTime = llhelper(
+        _PyTime_FromTime.api_func.functype,
+        _PyTime_FromTime.api_func.get_wrapper(space))
+    datetimeAPI.c_DateTime_FromDateAndTime = llhelper(
+        _PyDateTime_FromDateAndTime.api_func.functype,
+        _PyDateTime_FromDateAndTime.api_func.get_wrapper(space))
+    datetimeAPI.c_Delta_FromDelta = llhelper(
+        _PyDelta_FromDelta.api_func.functype,
+        _PyDelta_FromDelta.api_func.get_wrapper(space))
+
     return datetimeAPI
 
 PyDateTime_DateStruct = lltype.ForwardReference()
@@ -94,36 +125,40 @@
 make_check_function("PyDelta_Check", "timedelta")
 make_check_function("PyTZInfo_Check", "tzinfo")
 
-# Constructors
+# Constructors. They are better used as macros.
 
- at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real], PyObject)
-def PyDate_FromDate(space, year, month, day):
+ at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, PyTypeObjectPtr],
+             PyObject)
+def _PyDate_FromDate(space, year, month, day, w_type):
     """Return a datetime.date object with the specified year, month and day.
     """
     year = rffi.cast(lltype.Signed, year)
     month = rffi.cast(lltype.Signed, month)
     day = rffi.cast(lltype.Signed, day)
-    w_datetime = PyImport_Import(space, space.wrap("datetime"))
-    return space.call_method(
-        w_datetime, "date",
+    return space.call_function(
+        w_type,
         space.wrap(year), space.wrap(month), space.wrap(day))
 
- at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real], PyObject)
-def PyTime_FromTime(space, hour, minute, second, usecond):
+ at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+              PyObject, PyTypeObjectPtr], PyObject)
+def _PyTime_FromTime(space, hour, minute, second, usecond, w_tzinfo, w_type):
     """Return a ``datetime.time`` object with the specified hour, minute, second and
     microsecond."""
     hour = rffi.cast(lltype.Signed, hour)
     minute = rffi.cast(lltype.Signed, minute)
     second = rffi.cast(lltype.Signed, second)
     usecond = rffi.cast(lltype.Signed, usecond)
-    w_datetime = PyImport_Import(space, space.wrap("datetime"))
-    return space.call_method(
-        w_datetime, "time",
+    return space.call_function(
+        w_type,
         space.wrap(hour), space.wrap(minute), space.wrap(second),
-        space.wrap(usecond))
+        space.wrap(usecond), w_tzinfo)
 
- at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real], PyObject)
-def PyDateTime_FromDateAndTime(space, year, month, day, hour, minute, second, usecond):
+ at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real,
+              rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+              PyObject, PyTypeObjectPtr], PyObject)
+def _PyDateTime_FromDateAndTime(space, year, month, day,
+                                hour, minute, second, usecond,
+                                w_tzinfo, w_type):
     """Return a datetime.datetime object with the specified year, month, day, hour,
     minute, second and microsecond.
     """
@@ -134,12 +169,11 @@
     minute = rffi.cast(lltype.Signed, minute)
     second = rffi.cast(lltype.Signed, second)
     usecond = rffi.cast(lltype.Signed, usecond)
-    w_datetime = PyImport_Import(space, space.wrap("datetime"))
-    return space.call_method(
-        w_datetime, "datetime",
+    return space.call_function(
+        w_type,
         space.wrap(year), space.wrap(month), space.wrap(day),
         space.wrap(hour), space.wrap(minute), space.wrap(second),
-        space.wrap(usecond))
+        space.wrap(usecond), w_tzinfo)
 
 @cpython_api([PyObject], PyObject)
 def PyDateTime_FromTimestamp(space, w_args):
@@ -161,8 +195,10 @@
     w_method = space.getattr(w_type, space.wrap("fromtimestamp"))
     return space.call(w_method, w_args)
 
- at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real], PyObject)
-def PyDelta_FromDSU(space, days, seconds, useconds):
+ at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+              PyTypeObjectPtr],
+             PyObject)
+def _PyDelta_FromDelta(space, days, seconds, useconds, normalize, w_type):
     """Return a datetime.timedelta object representing the given number of days,
     seconds and microseconds.  Normalization is performed so that the resulting
     number of microseconds and seconds lie in the ranges documented for
@@ -171,9 +207,8 @@
     days = rffi.cast(lltype.Signed, days)
     seconds = rffi.cast(lltype.Signed, seconds)
     useconds = rffi.cast(lltype.Signed, useconds)
-    w_datetime = PyImport_Import(space, space.wrap("datetime"))
-    return space.call_method(
-        w_datetime, "timedelta",
+    return space.call_function(
+        w_type,
         space.wrap(days), space.wrap(seconds), space.wrap(useconds))
 
 # Accessors
diff --git a/pypy/module/cpyext/include/datetime.h b/pypy/module/cpyext/include/datetime.h
--- a/pypy/module/cpyext/include/datetime.h
+++ b/pypy/module/cpyext/include/datetime.h
@@ -12,6 +12,13 @@
     PyTypeObject *TimeType;
     PyTypeObject *DeltaType;
     PyTypeObject *TZInfoType;
+
+    /* constructors */
+    PyObject *(*Date_FromDate)(int, int, int, PyTypeObject*);
+    PyObject *(*DateTime_FromDateAndTime)(int, int, int, int, int, int, int,
+        PyObject*, PyTypeObject*);
+    PyObject *(*Time_FromTime)(int, int, int, int, PyObject*, PyTypeObject*);
+    PyObject *(*Delta_FromDelta)(int, int, int, int, PyTypeObject*);
 } PyDateTime_CAPI;
 
 PyAPI_DATA(PyDateTime_CAPI*) PyDateTimeAPI;
@@ -41,6 +48,22 @@
     PyObject_HEAD
 } PyDateTime_TZInfo;
 
+/* Macros for accessing constructors in a simplified fashion. */
+#define PyDate_FromDate(year, month, day) \
+    PyDateTimeAPI->Date_FromDate(year, month, day, PyDateTimeAPI->DateType)
+
+#define PyDateTime_FromDateAndTime(year, month, day, hour, min, sec, usec) \
+    PyDateTimeAPI->DateTime_FromDateAndTime(year, month, day, hour, \
+        min, sec, usec, Py_None, PyDateTimeAPI->DateTimeType)
+
+#define PyTime_FromTime(hour, minute, second, usecond) \
+    PyDateTimeAPI->Time_FromTime(hour, minute, second, usecond, \
+        Py_None, PyDateTimeAPI->TimeType)
+
+#define PyDelta_FromDSU(days, seconds, useconds) \
+    PyDateTimeAPI->Delta_FromDelta(days, seconds, useconds, 1, \
+        PyDateTimeAPI->DeltaType)
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/pypy/module/cpyext/src/unicodeobject.c b/pypy/module/cpyext/src/unicodeobject.c
--- a/pypy/module/cpyext/src/unicodeobject.c
+++ b/pypy/module/cpyext/src/unicodeobject.c
@@ -6,9 +6,6 @@
 #define Py_ISDIGIT isdigit
 #define Py_ISALPHA isalpha
 
-#define PyObject_Malloc malloc
-#define PyObject_Free free
-
 static void
 makefmt(char *fmt, int longflag, int longlongflag, int size_tflag,
         int zeropad, int width, int precision, char c)
diff --git a/pypy/module/cpyext/test/test_datetime.py b/pypy/module/cpyext/test/test_datetime.py
--- a/pypy/module/cpyext/test/test_datetime.py
+++ b/pypy/module/cpyext/test/test_datetime.py
@@ -4,7 +4,8 @@
 
 class TestDatetime(BaseApiTest):
     def test_date(self, space, api):
-        w_date = api.PyDate_FromDate(2010, 06, 03)
+        date_api = api._PyDateTime_Import()
+        w_date = api._PyDate_FromDate(2010, 06, 03, date_api.c_DateType)
         assert space.unwrap(space.str(w_date)) == '2010-06-03'
 
         assert api.PyDate_Check(w_date)
@@ -15,7 +16,9 @@
         assert api.PyDateTime_GET_DAY(w_date) == 3
 
     def test_time(self, space, api):
-        w_time = api.PyTime_FromTime(23, 15, 40, 123456)
+        date_api = api._PyDateTime_Import()
+        w_time = api._PyTime_FromTime(23, 15, 40, 123456,
+                                      space.w_None, date_api.c_TimeType)
         assert space.unwrap(space.str(w_time)) == '23:15:40.123456'
 
         assert api.PyTime_Check(w_time)
@@ -27,8 +30,10 @@
         assert api.PyDateTime_TIME_GET_MICROSECOND(w_time) == 123456
 
     def test_datetime(self, space, api):
-        w_date = api.PyDateTime_FromDateAndTime(
-            2010, 06, 03, 23, 15, 40, 123456)
+        date_api = api._PyDateTime_Import()
+        w_date = api._PyDateTime_FromDateAndTime(
+            2010, 06, 03, 23, 15, 40, 123456,
+            space.w_None, date_api.c_DateTimeType)
         assert space.unwrap(space.str(w_date)) == '2010-06-03 23:15:40.123456'
 
         assert api.PyDateTime_Check(w_date)
@@ -45,6 +50,7 @@
         assert api.PyDateTime_DATE_GET_MICROSECOND(w_date) == 123456
 
     def test_delta(self, space, api):
+        date_api = api._PyDateTime_Import()
         w_delta = space.appexec(
             [space.wrap(3), space.wrap(15)], """(days, seconds):
             from datetime import timedelta
@@ -53,7 +59,7 @@
         assert api.PyDelta_Check(w_delta)
         assert api.PyDelta_CheckExact(w_delta)
 
-        w_delta = api.PyDelta_FromDSU(10, 20, 30)
+        w_delta = api._PyDelta_FromDelta(10, 20, 30, True, date_api.c_DeltaType)
         assert api.PyDelta_Check(w_delta)
         assert api.PyDelta_CheckExact(w_delta)
 
@@ -118,6 +124,31 @@
                                       datetime.tzinfo)
         module.clear_types()
 
+    def test_constructors(self):
+        module = self.import_extension('foo', [
+            ("new_date", "METH_NOARGS",


More information about the pypy-commit mailing list