diff mbox series

[bug#41472] gnu: Add pypy3.

Message ID 20200523065648.GA1418@noor.fritz.box
State Accepted
Headers show
Series [bug#41472] gnu: Add pypy3. | expand

Checks

Context Check Description
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch fail View Laminar job

Commit Message

Lars-Dominik Braun May 23, 2020, 6:56 a.m. UTC
Hi,

the attached patch adds pypy3, a Python 3 JIT. As you can see this is a
lot of work, because pypy’s build system is rather unconventional.  I’m
not adding pypy2, because Python 2 is essentially EOL.

I’ve tried fixing as many testcases as possible, but there are some I
don’t know how to fix. Thus I’m disabling the test suite, although
everything is in place to run it. pypy itself works fine though, the
build is reproducible and passes `guix lint`.

One thing I don’t like right now is the dependency on gcc-toolchain
(i.e. gcc and binutils) in distutils. I don’t know how to avoid that,
since building CFFI modules won’t work without patching.

I guess the next step would be figuring out how to add “pypy3-foo”
variants for our Python packages, right?

Cheers,
Lars

Comments

Ludovic Courtès May 29, 2020, 4 p.m. UTC | #1
Hi,

Lars-Dominik Braun <lars@6xq.net> skribis:

> the attached patch adds pypy3, a Python 3 JIT. As you can see this is a
> lot of work, because pypy’s build system is rather unconventional.  I’m
> not adding pypy2, because Python 2 is essentially EOL.
>
> I’ve tried fixing as many testcases as possible, but there are some I
> don’t know how to fix. Thus I’m disabling the test suite, although
> everything is in place to run it. pypy itself works fine though, the
> build is reproducible and passes `guix lint`.

Yay!

> One thing I don’t like right now is the dependency on gcc-toolchain
> (i.e. gcc and binutils) in distutils. I don’t know how to avoid that,
> since building CFFI modules won’t work without patching.

Is CFFI able to pick ‘gcc’ from $PATH?  If it can do it, we can avoid
hardcoding the absolute file name of GCC and instead leave it up to the
user to add GCC to their environment when they want to use CFFI.

> I guess the next step would be figuring out how to add “pypy3-foo”
> variants for our Python packages, right?

Maybe.  Is it generally applicable?  I hear that many core Python
packages require CPython, which makes it hard to migrate to a different
implementation.

>>From bdf71850523b42e9d710618d0e0d9ea9fbfe9f87 Mon Sep 17 00:00:00 2001
> From: Lars-Dominik Braun <lars@6xq.net>
> Date: Fri, 22 May 2020 16:02:26 +0200
> Subject: [PATCH] gnu: Add pypy3.
>
> * gnu/packages/python.scm (pypy3): New public variable.
> * gnu/packages/patches/pypy3-7.3.1-fix-tests.patch: New file.
> * gnu/local.mk (dist_patch_DATA): Add it

[...]

> +(define-public pypy3
> +  (package
> +    (name "pypy3")
> +    ;; if you intend to upgrade this package, enable the tests and check
> +    ;; the results for anything abnormal

The advice seems to be very general; did you mean that people should
look for something specific in the build log, for example because test
failures are silently ignored?

Nitpick: please use uppercase at the beginning and period at the end.


[...]

> +       ("dash" ,dash)                   ; used as /bin/sh

I’d suggest ‘bash-minimal’ here, to be consistent with the other
packages.


[...]

> +    (home-page "https://www.pypy.org/")
> +    (synopsis "Python 3.6 JIT")

Maybe “Python implementation with just-in-time compilation”?

> +    (description "This package provides a Python 3.6 just-in-time compiler.")

Maybe remove “3.6” since it’s likely to become stale.  Bonus points if
you can expound a little bit.  :-)

Thanks!

Ludo’.
diff mbox series

Patch

From bdf71850523b42e9d710618d0e0d9ea9fbfe9f87 Mon Sep 17 00:00:00 2001
From: Lars-Dominik Braun <lars@6xq.net>
Date: Fri, 22 May 2020 16:02:26 +0200
Subject: [PATCH] gnu: Add pypy3.

* gnu/packages/python.scm (pypy3): New public variable.
* gnu/packages/patches/pypy3-7.3.1-fix-tests.patch: New file.
* gnu/local.mk (dist_patch_DATA): Add it
---
 gnu/local.mk                                  |   1 +
 .../patches/pypy3-7.3.1-fix-tests.patch       | 278 ++++++++++++++++++
 gnu/packages/python.scm                       | 157 ++++++++++
 3 files changed, 436 insertions(+)
 create mode 100644 gnu/packages/patches/pypy3-7.3.1-fix-tests.patch

diff --git a/gnu/local.mk b/gnu/local.mk
index 91f094ce0f..2407825cd4 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1440,6 +1440,7 @@  dist_patch_DATA =						\
   %D%/packages/patches/python-unittest2-python3-compat.patch	\
   %D%/packages/patches/python-unittest2-remove-argparse.patch	\
   %D%/packages/patches/python-waitress-fix-tests.patch		\
+  %D%/packages/patches/pypy3-7.3.1-fix-tests.patch		\
   %D%/packages/patches/qemu-glibc-2.27.patch 			\
   %D%/packages/patches/qrcodegen-cpp-make-install.patch		\
   %D%/packages/patches/qt4-ldflags.patch			\
diff --git a/gnu/packages/patches/pypy3-7.3.1-fix-tests.patch b/gnu/packages/patches/pypy3-7.3.1-fix-tests.patch
new file mode 100644
index 0000000000..464aad967f
--- /dev/null
+++ b/gnu/packages/patches/pypy3-7.3.1-fix-tests.patch
@@ -0,0 +1,278 @@ 
+Fix a few testcases. Adapted from python-3-fix-tests.patch.
+
+diff -Naur pypy3.6-v7.3.1-src.orig/lib-python/3/ctypes/test/test_callbacks.py pypy3.6-v7.3.1-src/lib-python/3/ctypes/test/test_callbacks.py
+--- pypy3.6-v7.3.1-src.orig/lib-python/3/ctypes/test/test_callbacks.py	1970-01-01 01:00:01.000000000 +0100
++++ pypy3.6-v7.3.1-src/lib-python/3/ctypes/test/test_callbacks.py	2020-05-21 14:19:14.827288853 +0200
+@@ -4,6 +4,7 @@
+ from ctypes import *
+ from ctypes.test import need_symbol
+ import _ctypes_test
++import platform
+ 
+ class Callbacks(unittest.TestCase):
+     functype = CFUNCTYPE
+@@ -178,6 +179,8 @@
+ 
+         self.assertLess(diff, 0.01, "%s not less than 0.01" % diff)
+ 
++    @unittest.skipIf(platform.machine() in ['mips64'],
++                     "This test fails on this platform")
+     def test_issue_8959_a(self):
+         from ctypes.util import find_library
+         libc_path = find_library("c")
+diff -Naur pypy3.6-v7.3.1-src.orig/lib-python/3/ctypes/test/test_libc.py pypy3.6-v7.3.1-src/lib-python/3/ctypes/test/test_libc.py
+--- pypy3.6-v7.3.1-src.orig/lib-python/3/ctypes/test/test_libc.py	1970-01-01 01:00:01.000000000 +0100
++++ pypy3.6-v7.3.1-src/lib-python/3/ctypes/test/test_libc.py	2020-05-21 14:19:14.827288853 +0200
+@@ -2,6 +2,7 @@
+ 
+ from ctypes import *
+ import _ctypes_test
++import platform
+ 
+ lib = CDLL(_ctypes_test.__file__)
+ 
+@@ -17,6 +18,8 @@
+         import math
+         self.assertEqual(lib.my_sqrt(2.0), math.sqrt(2.0))
+ 
++    @unittest.skipIf(platform.machine() in ['mips64'],
++                     "This test fails on this platform")
+     def test_qsort(self):
+         comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char))
+         lib.my_qsort.argtypes = c_void_p, c_size_t, c_size_t, comparefunc
+diff -Naur pypy3.6-v7.3.1-src.orig/lib-python/3/distutils/tests/test_archive_util.py pypy3.6-v7.3.1-src/lib-python/3/distutils/tests/test_archive_util.py
+--- pypy3.6-v7.3.1-src.orig/lib-python/3/distutils/tests/test_archive_util.py	1970-01-01 01:00:01.000000000 +0100
++++ pypy3.6-v7.3.1-src/lib-python/3/distutils/tests/test_archive_util.py	2020-05-21 14:19:14.827288853 +0200
+@@ -333,6 +333,7 @@
+         self.assertEqual(os.path.basename(res), 'archive.tar.xz')
+         self.assertEqual(self._tarinfo(res), self._created_files)
+ 
++    @unittest.skipIf(True, "getgrgid(0)[0] raises a KeyError on Guix")
+     def test_make_archive_owner_group(self):
+         # testing make_archive with owner and group, with various combinations
+         # this works even if there's not gid/uid support
+@@ -362,6 +363,7 @@
+ 
+     @unittest.skipUnless(ZLIB_SUPPORT, "Requires zlib")
+     @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
++    @unittest.skipIf(True, "getgrgid(0)[0] raises a KeyError on Guix")
+     def test_tarfile_root_owner(self):
+         tmpdir =  self._create_files()
+         base_name = os.path.join(self.mkdtemp(), 'archive')
+diff -Naur pypy3.6-v7.3.1-src.orig/lib-python/3/distutils/tests/test_sdist.py pypy3.6-v7.3.1-src/lib-python/3/distutils/tests/test_sdist.py
+--- pypy3.6-v7.3.1-src.orig/lib-python/3/distutils/tests/test_sdist.py	1970-01-01 01:00:01.000000000 +0100
++++ pypy3.6-v7.3.1-src/lib-python/3/distutils/tests/test_sdist.py	2020-05-21 14:19:14.827288853 +0200
+@@ -443,6 +443,7 @@
+                      "The tar command is not found")
+     @unittest.skipIf(find_executable('gzip') is None,
+                      "The gzip command is not found")
++    @unittest.skipIf(True, "getgrgid(0)[0] raises a KeyError on Guix")
+     def test_make_distribution_owner_group(self):
+         # now building a sdist
+         dist, cmd = self.get_cmd()
+diff -Naur pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_asyncio/test_base_events.py pypy3.6-v7.3.1-src/lib-python/3/test/test_asyncio/test_base_events.py
+--- pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_asyncio/test_base_events.py	1970-01-01 01:00:01.000000000 +0100
++++ pypy3.6-v7.3.1-src/lib-python/3/test/test_asyncio/test_base_events.py	2020-05-21 14:19:14.827288853 +0200
+@@ -1296,6 +1296,8 @@
+         self._test_create_connection_ip_addr(m_socket, False)
+ 
+     @patch_socket
++    @unittest.skipUnless(support.is_resource_enabled('network'),
++                         'network is not enabled')
+     def test_create_connection_service_name(self, m_socket):
+         m_socket.getaddrinfo = socket.getaddrinfo
+         sock = m_socket.socket.return_value
+diff -Naur pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_generators.py pypy3.6-v7.3.1-src/lib-python/3/test/test_generators.py
+--- pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_generators.py	1970-01-01 01:00:01.000000000 +0100
++++ pypy3.6-v7.3.1-src/lib-python/3/test/test_generators.py	2020-05-21 14:19:14.827288853 +0200
+@@ -35,6 +35,7 @@
+         else:
+             return "FAILED"
+ 
++    @unittest.skipIf(True, 'Keyboard interrupts do not work in the Guix build environment')
+     def test_raise_and_yield_from(self):
+         gen = self.generator1()
+         gen.send(None)
+diff -Naur pypy3.6-v7.3.1-src.orig/lib-python/3/test/_test_multiprocessing.py pypy3.6-v7.3.1-src/lib-python/3/test/_test_multiprocessing.py
+--- pypy3.6-v7.3.1-src.orig/lib-python/3/test/_test_multiprocessing.py	1970-01-01 01:00:01.000000000 +0100
++++ pypy3.6-v7.3.1-src/lib-python/3/test/_test_multiprocessing.py	2020-05-21 14:19:14.827288853 +0200
+@@ -1212,6 +1212,7 @@
+         if pid is not None:
+             os.kill(pid, signal.SIGINT)
+ 
++    @unittest.skipIf(True, "This fails for unknown reasons on Guix")
+     def test_wait_result(self):
+         if isinstance(self, ProcessesMixin) and sys.platform != 'win32':
+             pid = os.getpid()
+diff -Naur pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_normalization.py pypy3.6-v7.3.1-src/lib-python/3/test/test_normalization.py
+--- pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_normalization.py	1970-01-01 01:00:01.000000000 +0100
++++ pypy3.6-v7.3.1-src/lib-python/3/test/test_normalization.py	2020-05-21 14:19:14.827288853 +0200
+@@ -2,6 +2,7 @@
+ import unittest
+ 
+ from http.client import HTTPException
++from urllib.error import URLError
+ import sys
+ from unicodedata import normalize, unidata_version
+ 
+@@ -43,6 +44,8 @@
+         except PermissionError:
+             self.skipTest(f"Permission error when downloading {TESTDATAURL} "
+                           f"into the test data directory")
++        except URLError:
++            self.skipTest("DNS lookups are not enabled.")
+         except (OSError, HTTPException):
+             self.fail(f"Could not retrieve {TESTDATAURL}")
+ 
+diff -Naur pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_pathlib.py pypy3.6-v7.3.1-src/lib-python/3/test/test_pathlib.py
+--- pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_pathlib.py	1970-01-01 01:00:01.000000000 +0100
++++ pypy3.6-v7.3.1-src/lib-python/3/test/test_pathlib.py	2020-05-21 14:19:14.827288853 +0200
+@@ -2130,8 +2130,7 @@
+         self.assertEqual(given, expect)
+         self.assertEqual(set(p.rglob("FILEd*")), set())
+ 
+-    @unittest.skipUnless(hasattr(pwd, 'getpwall'),
+-                         'pwd module does not expose getpwall()')
++    @unittest.skipIf(True, "Guix builder home is '/' which causes trouble for these tests")
+     def test_expanduser(self):
+         P = self.cls
+         support.import_module('pwd')
+diff -Naur pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_pdb.py pypy3.6-v7.3.1-src/lib-python/3/test/test_pdb.py
+--- pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_pdb.py	1970-01-01 01:00:01.000000000 +0100
++++ pypy3.6-v7.3.1-src/lib-python/3/test/test_pdb.py	2020-05-21 14:20:24.377203281 +0200
+@@ -1136,11 +1136,11 @@
+     > <doctest test.test_pdb.test_pdb_issue_20766[0]>(6)test_function()
+     -> print('pdb %d: %s' % (i, sess._previous_sigint_handler))
+     (Pdb) continue
+-    pdb 1: <built-in function default_int_handler>
++    pdb 1: Handlers.SIG_IGN
+     > <doctest test.test_pdb.test_pdb_issue_20766[0]>(6)test_function()
+     -> print('pdb %d: %s' % (i, sess._previous_sigint_handler))
+     (Pdb) continue
+-    pdb 2: <built-in function default_int_handler>
++    pdb 2: Handlers.SIG_IGN
+     """
+ 
+ class PdbTestCase(unittest.TestCase):
+diff -Naur pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_regrtest.py pypy3.6-v7.3.1-src/lib-python/3/test/test_regrtest.py
+--- pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_regrtest.py	1970-01-01 01:00:01.000000000 +0100
++++ pypy3.6-v7.3.1-src/lib-python/3/test/test_regrtest.py	2020-05-21 14:19:14.827288853 +0200
+@@ -766,6 +766,7 @@
+         output = self.run_tests('--fromfile', filename)
+         self.check_executed_tests(output, tests)
+ 
++    @unittest.skipIf(True, 'Keyboard interrupts do not work in the Guix build environment.')
+     def test_interrupted(self):
+         code = TEST_INTERRUPTED
+         test = self.create_test('sigint', code=code)
+diff -Naur pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_resource.py pypy3.6-v7.3.1-src/lib-python/3/test/test_resource.py
+--- pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_resource.py	1970-01-01 01:00:01.000000000 +0100
++++ pypy3.6-v7.3.1-src/lib-python/3/test/test_resource.py	2020-05-21 14:19:14.827288853 +0200
+@@ -146,6 +146,7 @@
+ 
+     @unittest.skipUnless(hasattr(resource, 'prlimit'), 'no prlimit')
+     @support.requires_linux_version(2, 6, 36)
++    @unittest.skipIf(True, "Bug: the PermissionError is not raised")
+     def test_prlimit(self):
+         self.assertRaises(TypeError, resource.prlimit)
+         self.assertRaises(ProcessLookupError, resource.prlimit,
+diff -Naur pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_shutil.py pypy3.6-v7.3.1-src/lib-python/3/test/test_shutil.py
+--- pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_shutil.py	1970-01-01 01:00:01.000000000 +0100
++++ pypy3.6-v7.3.1-src/lib-python/3/test/test_shutil.py	2020-05-21 14:19:14.827288853 +0200
+@@ -1138,6 +1138,7 @@
+         self.assertRaises(ValueError, make_archive, base_name, 'xxx')
+ 
+     @support.requires_zlib
++    @unittest.skipIf(True, "getgrgid(0)[0] raises a KeyError on Guix")
+     def test_make_archive_owner_group(self):
+         # testing make_archive with owner and group, with various combinations
+         # this works even if there's not gid/uid support
+@@ -1166,6 +1167,7 @@
+ 
+ 
+     @support.requires_zlib
++    @unittest.skipIf(True, "getgrgid(0)[0] raises a KeyError on Guix")
+     @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
+     def test_tarfile_root_owner(self):
+         root_dir, base_dir = self._create_files()
+diff -Naur pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_socket.py pypy3.6-v7.3.1-src/lib-python/3/test/test_socket.py
+--- pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_socket.py	1970-01-01 01:00:01.000000000 +0100
++++ pypy3.6-v7.3.1-src/lib-python/3/test/test_socket.py	2020-05-21 14:19:14.827288853 +0200
+@@ -815,6 +815,8 @@
+         if not fqhn in all_host_names:
+             self.fail("Error testing host resolution mechanisms. (fqdn: %s, all: %s)" % (fqhn, repr(all_host_names)))
+ 
++    @unittest.skipUnless(support.is_resource_enabled('network'),
++                         'network is not enabled')
+     def test_host_resolution(self):
+         for addr in [support.HOST, '10.0.0.1', '255.255.255.255']:
+             self.assertEqual(socket.gethostbyname(addr), addr)
+@@ -934,6 +936,8 @@
+             self.assertRaises(OverflowError, socket.htonl, k)
+             self.assertRaises(OverflowError, socket.htons, k)
+ 
++    @unittest.skipUnless(os.path.exists("/etc/services"),
++                         "getservbyname uses /etc/services, which is not in the chroot")
+     def testGetServBy(self):
+         eq = self.assertEqual
+         # Find one service that exists, then check all the related interfaces.
+@@ -1278,6 +1282,8 @@
+             raise
+         self.assertRaises(TypeError, s.ioctl, socket.SIO_LOOPBACK_FAST_PATH, None)
+ 
++    @unittest.skipUnless(os.path.exists("/etc/gai.conf"),
++                         "getaddrinfo() will fail")
+     def testGetaddrinfo(self):
+         try:
+             socket.getaddrinfo('localhost', 80)
+@@ -1357,6 +1363,8 @@
+         # only IP addresses are allowed
+         self.assertRaises(OSError, socket.getnameinfo, ('mail.python.org',0), 0)
+ 
++    @unittest.skipUnless(os.path.exists("/etc/gai.conf"),
++                         "getaddrinfo() will fail")
+     @unittest.skipUnless(support.is_resource_enabled('network'),
+                          'network is not enabled')
+     def test_idna(self):
+diff -Naur pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_spwd.py pypy3.6-v7.3.1-src/lib-python/3/test/test_spwd.py
+--- pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_spwd.py	1970-01-01 01:00:01.000000000 +0100
++++ pypy3.6-v7.3.1-src/lib-python/3/test/test_spwd.py	2020-05-21 14:19:14.827288853 +0200
+@@ -5,8 +5,7 @@
+ spwd = support.import_module('spwd')
+ 
+ 
+-@unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
+-                     'root privileges required')
++@unittest.skipUnless(os.path.exists("/etc/shadow"), 'spwd tests require /etc/shadow')
+ class TestSpwdRoot(unittest.TestCase):
+ 
+     def test_getspall(self):
+@@ -56,8 +55,7 @@
+             self.assertRaises(TypeError, spwd.getspnam, bytes_name)
+ 
+ 
+-@unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() != 0,
+-                     'non-root user required')
++@unittest.skipUnless(os.path.exists("/etc/shadow"), 'spwd tests require /etc/shadow')
+ class TestSpwdNonRoot(unittest.TestCase):
+ 
+     def test_getspnam_exception(self):
+diff -Naur pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_tarfile.py pypy3.6-v7.3.1-src/lib-python/3/test/test_tarfile.py
+--- pypy3.6-v7.3.1-src.orig/lib-python/3/test/test_tarfile.py	1970-01-01 01:00:01.000000000 +0100
++++ pypy3.6-v7.3.1-src/lib-python/3/test/test_tarfile.py	2020-05-21 14:19:14.827288853 +0200
+@@ -2491,9 +2491,12 @@
+         import pwd, grp
+     except ImportError:
+         return False
+-    if pwd.getpwuid(0)[0] != 'root':
+-        return False
+-    if grp.getgrgid(0)[0] != 'root':
++    try:
++        if pwd.getpwuid(0)[0] != 'root':
++            return False
++        if grp.getgrgid(0)[0] != 'root':
++            return False
++    except KeyError:
+         return False
+     return True
+ 
diff --git a/gnu/packages/python.scm b/gnu/packages/python.scm
index 1ec002df73..5300c345d4 100644
--- a/gnu/packages/python.scm
+++ b/gnu/packages/python.scm
@@ -80,12 +80,17 @@ 
   #:use-module (gnu packages)
   #:use-module (gnu packages base)
   #:use-module (gnu packages bash)
+  #:use-module (gnu packages certs)
+  #:use-module (gnu packages check)
   #:use-module (gnu packages compression)
   #:use-module (gnu packages dbm)
   #:use-module (gnu packages hurd)
   #:use-module (gnu packages libffi)
+  #:use-module (gnu packages ncurses)
   #:use-module (gnu packages pkg-config)
+  #:use-module (gnu packages python-xyz)
   #:use-module (gnu packages readline)
+  #:use-module (gnu packages shells)
   #:use-module (gnu packages sqlite)
   #:use-module (gnu packages tcl)
   #:use-module (gnu packages tls)
@@ -631,3 +636,155 @@  run within just 256k of code space and 16k of RAM.  MicroPython aims to be as
 compatible with normal Python as possible to allow you to transfer code with
 ease from the desktop to a microcontroller or embedded system.")
     (license license:expat)))
+
+(define-public pypy3
+  (package
+    (name "pypy3")
+    ;; if you intend to upgrade this package, enable the tests and check
+    ;; the results for anything abnormal
+    (version "7.3.1")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append "https://bitbucket.org/pypy/pypy/downloads/" ;
+                                  "pypy3.6-v" version "-src.tar.bz2"))
+              (sha256
+               (base32
+                "10zsk8jby8j6visk5mzikpb1cidvz27qq4pfpa26jv53klic6b0c"))
+              (patches (search-patches "pypy3-7.3.1-fix-tests.patch"))))
+    (build-system gnu-build-system)
+    (native-inputs
+     `(("python-2" ,python-2)
+       ("pkg-config" ,pkg-config)
+       ("tar" ,tar)                     ; required for package.py
+       ("python2-pycparser" ,python2-pycparser)
+       ("python2-hypothesis" ,python2-hypothesis)
+       ("nss-certs" ,nss-certs)         ; for ssl tests
+       ("gzip" ,gzip)))
+    (inputs
+     `(("libffi" ,libffi)
+       ("zlib" ,zlib)
+       ("ncurses" ,ncurses)
+       ("openssl" ,openssl)
+       ("expat" ,expat)
+       ("bzip2" ,bzip2)
+       ("sqlite" ,sqlite)
+       ("gdbm" ,gdbm)
+       ("tcl" ,tcl)
+       ("tk" ,tk)
+       ("glibc" ,glibc)
+       ("dash" ,dash)                   ; used as /bin/sh
+       ("xz" ,xz)))                     ; liblzma
+    (arguments
+     `(#:tests? #f ; disabled for now, there are simply too many unfixable tests failing
+       #:modules ((ice-9 ftw) (ice-9 match)
+                  (guix build utils) (guix build gnu-build-system))
+       #:phases (modify-phases %standard-phases
+                  (delete 'configure)
+                  (add-after 'unpack 'patch-source
+                    (lambda* (#:key inputs outputs #:allow-other-keys)
+                      (substitute* '("rpython/rlib/clibffi.py")
+                        ;; find_library does not work for libc
+                        (("ctypes\\.util\\.find_library\\('c'\\)") "'libc.so'"))
+                      (substitute* '("lib_pypy/cffi/_pycparser/ply/cpp.py")
+                        ;; make reproducible (XXX: unused?)
+                        (("time\\.localtime\\(\\)") "time.gmtime(0)"))
+                      (substitute* '("pypy/module/sys/version.py")
+                        ;; make reproducible
+                        (("t\\.gmtime\\(\\)") "t.gmtime(0)"))
+                      (substitute* '("lib_pypy/_tkinter/tklib_build.py")
+                        ;; link to versioned libtcl and libtk
+                        (("linklibs = \\['tcl', 'tk'\\]")
+                         "linklibs = ['tcl8.6', 'tk8.6']")
+                        (("incdirs = \\[\\]")
+                         (string-append "incdirs = ['"
+                                        (assoc-ref inputs "tcl")
+                                        "/include', '"
+                                        (assoc-ref inputs "tk")
+                                        "/include']")))
+                      (substitute* '("lib_pypy/_curses_build.py")
+                        ;; find curses
+                        (("/usr/local") (assoc-ref inputs "ncurses")))
+                      (substitute* '("lib_pypy/_sqlite3_build.py")
+                        ;; always use search paths
+                        (("sys\\.platform\\.startswith\\('freebsd'\\)") "True")
+                        ;; find sqlite3
+                        (("/usr/local") (assoc-ref inputs "sqlite"))
+                        (("libname = 'sqlite3'")
+                         (string-append "libname = '"
+                                        (assoc-ref inputs "sqlite")
+                                        "/lib/libsqlite3.so.0'")))
+                      (substitute* '("lib-python/3/subprocess.py")
+                        ;; fix shell path
+                        (("/bin/sh")
+                         (string-append (assoc-ref inputs "dash") "/bin/dash")))
+                      ;; this does not look like a good idea, since it depends
+                      ;; on the gcc toolchain, on the other hand cffi modules
+                      ;; will not be built without this
+                      (substitute* '("lib-python/3/distutils/unixccompiler.py")
+                        (("\"cc\"")
+                         (string-append "\"" (assoc-ref inputs "gcc")
+                                        "/bin/gcc\""))
+                        (("\"c\\+\\+\"")
+                         (string-append "\"" (assoc-ref inputs "gcc")
+                                        "/bin/g++\""))
+                        (("\"ar\"")
+                         (string-append "\"" (assoc-ref inputs "binutils")
+                                        "/bin/ar\"")))
+                      #t))
+                  (add-after
+                      'unpack 'set-source-file-times-to-1980
+                    ;; copied from python package, required by zip testcase
+                    (lambda _
+                      (let ((circa-1980 (* 10 366 24 60 60)))
+                        (ftw "." (lambda (file stat flag)
+                                   (utime file circa-1980 circa-1980)
+                                   #t))
+                        #t)))
+                  (replace 'build
+                    (lambda* (#:key inputs #:allow-other-keys)
+                      (with-directory-excursion "pypy/goal"
+                        ;; build with jit optimization
+                        (invoke "python2"
+                                "../../rpython/bin/rpython"
+                                (string-append "--make-jobs="
+                                               (number->string (parallel-job-count)))
+                                "-Ojit"
+                                "targetpypystandalone"))
+                      ;; build c modules and package everything, so tests work
+                      (with-directory-excursion "pypy/tool/release"
+                        (unsetenv "PYTHONPATH") ; do not use the system’s python libs:
+                                        ; AttributeError: module 'enum' has no
+                                        ; attribute 'IntFlag'
+                        (invoke "python2" "package.py"
+                                "--archive-name" "pypy-dist"
+                                "--builddir" (getcwd)))))
+                  (replace 'check
+                    (lambda* (#:key tests? #:allow-other-keys)
+                      (if tests?
+                          (begin
+                            (setenv "HOME" "/tmp") ; test_with_pip tries to
+                                        ; access ~/.cache/pip
+                            ;; Run library tests only (no interpreter unit
+                            ;; tests). This is what Gentoo does.
+                            (invoke
+                             "python2"
+                             "pypy/test_all.py"
+                             "--pypy=pypy/tool/release/pypy-dist/bin/pypy3"
+                             "lib-python"))
+                          (format #t "test suite not run~%"))
+                      #t))
+                  (replace 'install
+                    (lambda* (#:key inputs outputs #:allow-other-keys)
+                      (with-directory-excursion "pypy/tool/release"
+                        (copy-recursively "pypy-dist" (assoc-ref outputs "out")))
+                      #t)))))
+    (home-page "https://www.pypy.org/")
+    (synopsis "Python 3.6 JIT")
+    (description "This package provides a Python 3.6 just-in-time compiler.")
+    (license (list license:expat        ; pypy itself; _pytest/
+                   license:psfl ; python standard library in lib-python/
+                   license:asl2.0 ; dotviewer/font/ and some of lib-python/
+                   license:gpl3+ ; ./rpython/rlib/rvmprof/src/shared/libbacktrace/dwarf2.*
+                   license:bsd-3 ; lib_pypy/cffi/_pycparser/ply/
+                   (license:non-copyleft
+                    "http://www.unicode.org/copyright.html")))))
-- 
2.26.2