about summary refs log tree commit diff
path: root/nixpkgs/pkgs/development/interpreters/python
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2021-01-15 10:30:44 +0000
committerAlyssa Ross <hi@alyssa.is>2021-01-15 10:30:44 +0000
commite0794be8a0d11e90461e5a9c85012a36b93ec976 (patch)
treeefd9cbc55ea3322867bf601c4d536758a3dd5fcc /nixpkgs/pkgs/development/interpreters/python
parent3538874082ded7647b1ccec0343c7c1e882cfef3 (diff)
parent1a57d96edd156958b12782e8c8b6a374142a7248 (diff)
downloadnixlib-e0794be8a0d11e90461e5a9c85012a36b93ec976.tar
nixlib-e0794be8a0d11e90461e5a9c85012a36b93ec976.tar.gz
nixlib-e0794be8a0d11e90461e5a9c85012a36b93ec976.tar.bz2
nixlib-e0794be8a0d11e90461e5a9c85012a36b93ec976.tar.lz
nixlib-e0794be8a0d11e90461e5a9c85012a36b93ec976.tar.xz
nixlib-e0794be8a0d11e90461e5a9c85012a36b93ec976.tar.zst
nixlib-e0794be8a0d11e90461e5a9c85012a36b93ec976.zip
Merge commit '1a57d96edd156958b12782e8c8b6a374142a7248'
Diffstat (limited to 'nixpkgs/pkgs/development/interpreters/python')
-rw-r--r--nixpkgs/pkgs/development/interpreters/python/cpython/2.7/default.nix18
-rw-r--r--nixpkgs/pkgs/development/interpreters/python/cpython/3.10/no-ldconfig.patch107
-rw-r--r--nixpkgs/pkgs/development/interpreters/python/cpython/3.7/find_library.patch105
-rw-r--r--nixpkgs/pkgs/development/interpreters/python/cpython/3.9/no-ldconfig.patch44
-rw-r--r--nixpkgs/pkgs/development/interpreters/python/cpython/default.nix34
-rw-r--r--nixpkgs/pkgs/development/interpreters/python/default.nix98
-rw-r--r--nixpkgs/pkgs/development/interpreters/python/hooks/default.nix5
-rw-r--r--nixpkgs/pkgs/development/interpreters/python/hooks/pip-install-hook.sh4
-rw-r--r--nixpkgs/pkgs/development/interpreters/python/hooks/python-namespaces-hook.sh13
-rw-r--r--nixpkgs/pkgs/development/interpreters/python/mk-python-derivation.nix9
-rw-r--r--nixpkgs/pkgs/development/interpreters/python/pypy/default.nix15
-rw-r--r--nixpkgs/pkgs/development/interpreters/python/tests.nix5
-rw-r--r--nixpkgs/pkgs/development/interpreters/python/tests/test_nix_pythonprefix/default.nix2
-rw-r--r--nixpkgs/pkgs/development/interpreters/python/update-python-libraries/default.nix2
-rwxr-xr-xnixpkgs/pkgs/development/interpreters/python/update-python-libraries/update-python-libraries.py73
15 files changed, 454 insertions, 80 deletions
diff --git a/nixpkgs/pkgs/development/interpreters/python/cpython/2.7/default.nix b/nixpkgs/pkgs/development/interpreters/python/cpython/2.7/default.nix
index 2cfaa69a4c8b..e6ab1f218795 100644
--- a/nixpkgs/pkgs/development/interpreters/python/cpython/2.7/default.nix
+++ b/nixpkgs/pkgs/development/interpreters/python/cpython/2.7/default.nix
@@ -18,12 +18,17 @@
 , ucsEncoding ? 4
 # For the Python package set
 , packageOverrides ? (self: super: {})
-, buildPackages
+, pkgsBuildBuild
+, pkgsBuildHost
+, pkgsBuildTarget
+, pkgsHostHost
+, pkgsTargetTarget
 , sourceVersion
 , sha256
 , passthruFun
 , static ? false
 , enableOptimizations ? (!stdenv.isDarwin)
+, pythonAttr ? "python${sourceVersion.major}${sourceVersion.minor}"
 }:
 
 assert x11Support -> tcl != null
@@ -34,8 +39,8 @@ assert x11Support -> tcl != null
 with stdenv.lib;
 
 let
-
-  pythonForBuild = buildPackages.${"python${sourceVersion.major}${sourceVersion.minor}"};
+  buildPackages = pkgsBuildHost;
+  inherit (passthru) pythonForBuild;
 
   passthru = passthruFun rec {
     inherit self sourceVersion packageOverrides;
@@ -44,7 +49,12 @@ let
     executable = libPrefix;
     pythonVersion = with sourceVersion; "${major}.${minor}";
     sitePackages = "lib/${libPrefix}/site-packages";
-    inherit hasDistutilsCxxPatch pythonForBuild;
+    inherit hasDistutilsCxxPatch;
+    pythonOnBuildForBuild = pkgsBuildBuild.${pythonAttr};
+    pythonOnBuildForHost = pkgsBuildHost.${pythonAttr};
+    pythonOnBuildForTarget = pkgsBuildTarget.${pythonAttr};
+    pythonOnHostForHost = pkgsHostHost.${pythonAttr};
+    pythonOnTargetForTarget = pkgsTargetTarget.${pythonAttr} or {};
   } // {
     inherit ucsEncoding;
   };
diff --git a/nixpkgs/pkgs/development/interpreters/python/cpython/3.10/no-ldconfig.patch b/nixpkgs/pkgs/development/interpreters/python/cpython/3.10/no-ldconfig.patch
new file mode 100644
index 000000000000..c259aed72b99
--- /dev/null
+++ b/nixpkgs/pkgs/development/interpreters/python/cpython/3.10/no-ldconfig.patch
@@ -0,0 +1,107 @@
+From 084c6dd6352077e64f10cf7aa168f95d800f3819 Mon Sep 17 00:00:00 2001
+From: Jonathan Ringer <jonringer117@gmail.com>
+Date: Mon, 9 Nov 2020 10:24:35 -0800
+Subject: [PATCH] CPython: Don't use ldconfig
+
+---
+ Lib/ctypes/util.py | 77 ++--------------------------------------------
+ 1 file changed, 2 insertions(+), 75 deletions(-)
+
+diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py
+index 0c2510e..7fb98af 100644
+--- a/Lib/ctypes/util.py
++++ b/Lib/ctypes/util.py
+@@ -100,53 +100,7 @@ elif os.name == "posix":
+             return thefile.read(4) == elf_header
+ 
+     def _findLib_gcc(name):
+-        # Run GCC's linker with the -t (aka --trace) option and examine the
+-        # library name it prints out. The GCC command will fail because we
+-        # haven't supplied a proper program with main(), but that does not
+-        # matter.
+-        expr = os.fsencode(r'[^\(\)\s]*lib%s\.[^\(\)\s]*' % re.escape(name))
+-
+-        c_compiler = shutil.which('gcc')
+-        if not c_compiler:
+-            c_compiler = shutil.which('cc')
+-        if not c_compiler:
+-            # No C compiler available, give up
+-            return None
+-
+-        temp = tempfile.NamedTemporaryFile()
+-        try:
+-            args = [c_compiler, '-Wl,-t', '-o', temp.name, '-l' + name]
+-
+-            env = dict(os.environ)
+-            env['LC_ALL'] = 'C'
+-            env['LANG'] = 'C'
+-            try:
+-                proc = subprocess.Popen(args,
+-                                        stdout=subprocess.PIPE,
+-                                        stderr=subprocess.STDOUT,
+-                                        env=env)
+-            except OSError:  # E.g. bad executable
+-                return None
+-            with proc:
+-                trace = proc.stdout.read()
+-        finally:
+-            try:
+-                temp.close()
+-            except FileNotFoundError:
+-                # Raised if the file was already removed, which is the normal
+-                # behaviour of GCC if linking fails
+-                pass
+-        res = re.findall(expr, trace)
+-        if not res:
+-            return None
+-
+-        for file in res:
+-            # Check if the given file is an elf file: gcc can report
+-            # some files that are linker scripts and not actual
+-            # shared objects. See bpo-41976 for more details
+-            if not _is_elf(file):
+-                continue
+-            return os.fsdecode(file)
++        return None
+ 
+ 
+     if sys.platform == "sunos5":
+@@ -268,34 +222,7 @@ elif os.name == "posix":
+     else:
+ 
+         def _findSoname_ldconfig(name):
+-            import struct
+-            if struct.calcsize('l') == 4:
+-                machine = os.uname().machine + '-32'
+-            else:
+-                machine = os.uname().machine + '-64'
+-            mach_map = {
+-                'x86_64-64': 'libc6,x86-64',
+-                'ppc64-64': 'libc6,64bit',
+-                'sparc64-64': 'libc6,64bit',
+-                's390x-64': 'libc6,64bit',
+-                'ia64-64': 'libc6,IA-64',
+-                }
+-            abi_type = mach_map.get(machine, 'libc6')
+-
+-            # XXX assuming GLIBC's ldconfig (with option -p)
+-            regex = r'\s+(lib%s\.[^\s]+)\s+\(%s'
+-            regex = os.fsencode(regex % (re.escape(name), abi_type))
+-            try:
+-                with subprocess.Popen(['/sbin/ldconfig', '-p'],
+-                                      stdin=subprocess.DEVNULL,
+-                                      stderr=subprocess.DEVNULL,
+-                                      stdout=subprocess.PIPE,
+-                                      env={'LC_ALL': 'C', 'LANG': 'C'}) as p:
+-                    res = re.search(regex, p.stdout.read())
+-                    if res:
+-                        return os.fsdecode(res.group(1))
+-            except OSError:
+-                pass
++            return None
+ 
+         def _findLib_ld(name):
+             # See issue #9998 for why this is needed
+-- 
+2.28.0
+
diff --git a/nixpkgs/pkgs/development/interpreters/python/cpython/3.7/find_library.patch b/nixpkgs/pkgs/development/interpreters/python/cpython/3.7/find_library.patch
new file mode 100644
index 000000000000..97fb66662d03
--- /dev/null
+++ b/nixpkgs/pkgs/development/interpreters/python/cpython/3.7/find_library.patch
@@ -0,0 +1,105 @@
+From 9b5a023a5dc3127da15253f7acad71019395ebe1 Mon Sep 17 00:00:00 2001
+From: Pablo Galindo <Pablogsal@gmail.com>
+Date: Thu, 8 Oct 2020 19:50:37 +0100
+Subject: [PATCH] [3.7] bpo-41976: Fix the fallback to gcc of
+ ctypes.util.find_library when using gcc>9 (GH-22598). (GH-22601)
+
+(cherry picked from commit 27ac19cca2c639caaf6fedf3632fe6beb265f24f)
+
+Co-authored-by: Pablo Galindo <Pablogsal@gmail.com>
+---
+ Lib/ctypes/test/test_find.py                  | 12 ++++++-
+ Lib/ctypes/util.py                            | 32 +++++++++++++++----
+ .../2020-10-08-18-22-28.bpo-41976.Svm0wb.rst  |  3 ++
+ 3 files changed, 39 insertions(+), 8 deletions(-)
+ create mode 100644 Misc/NEWS.d/next/Library/2020-10-08-18-22-28.bpo-41976.Svm0wb.rst
+
+diff --git a/Lib/ctypes/test/test_find.py b/Lib/ctypes/test/test_find.py
+index b99fdcba7b28f..92ac1840ad7d4 100644
+--- a/Lib/ctypes/test/test_find.py
++++ b/Lib/ctypes/test/test_find.py
+@@ -1,4 +1,5 @@
+ import unittest
++import unittest.mock
+ import os.path
+ import sys
+ import test.support
+@@ -72,7 +73,7 @@ def test_shell_injection(self):
+ 
+ @unittest.skipUnless(sys.platform.startswith('linux'),
+                      'Test only valid for Linux')
+-class LibPathFindTest(unittest.TestCase):
++class FindLibraryLinux(unittest.TestCase):
+     def test_find_on_libpath(self):
+         import subprocess
+         import tempfile
+@@ -111,6 +112,15 @@ def test_find_on_libpath(self):
+                 # LD_LIBRARY_PATH)
+                 self.assertEqual(find_library(libname), 'lib%s.so' % libname)
+ 
++    def test_find_library_with_gcc(self):
++        with unittest.mock.patch("ctypes.util._findSoname_ldconfig", lambda *args: None):
++            self.assertNotEqual(find_library('c'), None)
++
++    def test_find_library_with_ld(self):
++        with unittest.mock.patch("ctypes.util._findSoname_ldconfig", lambda *args: None), \
++             unittest.mock.patch("ctypes.util._findLib_gcc", lambda *args: None):
++            self.assertNotEqual(find_library('c'), None)
++
+ 
+ if __name__ == "__main__":
+     unittest.main()
+diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py
+index 97973bce001d9..0c2510e1619c8 100644
+--- a/Lib/ctypes/util.py
++++ b/Lib/ctypes/util.py
+@@ -93,6 +93,12 @@ def find_library(name):
+     # Andreas Degert's find functions, using gcc, /sbin/ldconfig, objdump
+     import re, tempfile
+ 
++    def _is_elf(filename):
++        "Return True if the given file is an ELF file"
++        elf_header = b'\x7fELF'
++        with open(filename, 'br') as thefile:
++            return thefile.read(4) == elf_header
++
+     def _findLib_gcc(name):
+         # Run GCC's linker with the -t (aka --trace) option and examine the
+         # library name it prints out. The GCC command will fail because we
+@@ -299,17 +312,22 @@ def _findLib_ld(name):
+                                      stderr=subprocess.PIPE,
+                                      universal_newlines=True)
+                 out, _ = p.communicate()
+-                res = re.search(expr, os.fsdecode(out))
+-                if res:
+-                    result = res.group(0)
+-            except Exception as e:
++                res = re.findall(expr, os.fsdecode(out))
++                for file in res:
++                    # Check if the given file is an elf file: gcc can report
++                    # some files that are linker scripts and not actual
++                    # shared objects. See bpo-41976 for more details
++                    if not _is_elf(file):
++                        continue
++                    return os.fsdecode(file)
++            except Exception:
+                 pass  # result will be None
+             return result
+ 
+         def find_library(name):
+             # See issue #9998
+             return _findSoname_ldconfig(name) or \
+-                   _get_soname(_findLib_gcc(name) or _findLib_ld(name))
++                   _get_soname(_findLib_gcc(name)) or _get_soname(_findLib_ld(name))
+ 
+ ################################################################
+ # test code
+diff --git a/Misc/NEWS.d/next/Library/2020-10-08-18-22-28.bpo-41976.Svm0wb.rst b/Misc/NEWS.d/next/Library/2020-10-08-18-22-28.bpo-41976.Svm0wb.rst
+new file mode 100644
+index 0000000000000..c8b3fc771845e
+--- /dev/null
++++ b/Misc/NEWS.d/next/Library/2020-10-08-18-22-28.bpo-41976.Svm0wb.rst
+@@ -0,0 +1,3 @@
++Fixed a bug that was causing :func:`ctypes.util.find_library` to return
++``None`` when triying to locate a library in an environment when gcc>=9 is
++available and ``ldconfig`` is not. Patch by Pablo Galindo
diff --git a/nixpkgs/pkgs/development/interpreters/python/cpython/3.9/no-ldconfig.patch b/nixpkgs/pkgs/development/interpreters/python/cpython/3.9/no-ldconfig.patch
index a1f9d68eb166..41d3ab52345b 100644
--- a/nixpkgs/pkgs/development/interpreters/python/cpython/3.9/no-ldconfig.patch
+++ b/nixpkgs/pkgs/development/interpreters/python/cpython/3.9/no-ldconfig.patch
@@ -1,19 +1,19 @@
-From 597e73f2a4b2f0b508127931b36d5540d6941823 Mon Sep 17 00:00:00 2001
-From: Frederik Rietdijk <fridh@fridh.nl>
-Date: Mon, 28 Aug 2017 09:24:06 +0200
+From 66f492d2eda94bd64db833839a325caf6ba0fed5 Mon Sep 17 00:00:00 2001
+From: Greg Roodt <greg@canva.com>
+Date: Wed, 9 Dec 2020 17:59:24 +1100
 Subject: [PATCH] Don't use ldconfig
 
 ---
- Lib/ctypes/util.py | 70 ++----------------------------------------------------
- 1 file changed, 2 insertions(+), 68 deletions(-)
+ Lib/ctypes/util.py | 77 ++--------------------------------------------
+ 1 file changed, 2 insertions(+), 75 deletions(-)
 
 diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py
-index 5e8b31a854..7b45ce6c15 100644
+index 0c2510e161..7fb98af308 100644
 --- a/Lib/ctypes/util.py
 +++ b/Lib/ctypes/util.py
-@@ -94,46 +94,7 @@ elif os.name == "posix":
-     import re, tempfile
- 
+@@ -100,53 +100,7 @@ elif os.name == "posix":
+             return thefile.read(4) == elf_header
+
      def _findLib_gcc(name):
 -        # Run GCC's linker with the -t (aka --trace) option and examine the
 -        # library name it prints out. The GCC command will fail because we
@@ -51,17 +51,24 @@ index 5e8b31a854..7b45ce6c15 100644
 -                # Raised if the file was already removed, which is the normal
 -                # behaviour of GCC if linking fails
 -                pass
--        res = re.search(expr, trace)
+-        res = re.findall(expr, trace)
 -        if not res:
 -            return None
--        return os.fsdecode(res.group(0))
+-
+-        for file in res:
+-            # Check if the given file is an elf file: gcc can report
+-            # some files that are linker scripts and not actual
+-            # shared objects. See bpo-41976 for more details
+-            if not _is_elf(file):
+-                continue
+-            return os.fsdecode(file)
 +        return None
- 
- 
+
+
      if sys.platform == "sunos5":
-@@ -255,34 +216,7 @@ elif os.name == "posix":
+@@ -268,34 +222,7 @@ elif os.name == "posix":
      else:
- 
+
          def _findSoname_ldconfig(name):
 -            import struct
 -            if struct.calcsize('l') == 4:
@@ -92,9 +99,8 @@ index 5e8b31a854..7b45ce6c15 100644
 -            except OSError:
 -                pass
 +            return None
- 
+
          def _findLib_ld(name):
              # See issue #9998 for why this is needed
--- 
-2.15.0
-
+--
+2.24.3 (Apple Git-128)
diff --git a/nixpkgs/pkgs/development/interpreters/python/cpython/default.nix b/nixpkgs/pkgs/development/interpreters/python/cpython/default.nix
index b25d613eb7f3..c67ede82003a 100644
--- a/nixpkgs/pkgs/development/interpreters/python/cpython/default.nix
+++ b/nixpkgs/pkgs/development/interpreters/python/cpython/default.nix
@@ -14,12 +14,16 @@
 , self
 , configd
 , autoreconfHook
+, autoconf-archive
 , python-setup-hook
 , nukeReferences
 # For the Python package set
 , packageOverrides ? (self: super: {})
-, buildPackages
-, pythonForBuild ? buildPackages.${"python${sourceVersion.major}${sourceVersion.minor}"}
+, pkgsBuildBuild
+, pkgsBuildHost
+, pkgsBuildTarget
+, pkgsHostHost
+, pkgsTargetTarget
 , sourceVersion
 , sha256
 , passthruFun
@@ -35,6 +39,7 @@
 # Not using optimizations on Darwin
 # configure: error: llvm-profdata is required for a --enable-optimizations build but could not be found.
 , enableOptimizations ? (!stdenv.isDarwin)
+, pythonAttr ? "python${sourceVersion.major}${sourceVersion.minor}"
 }:
 
 # Note: this package is used for bootstrapping fetchurl, and thus
@@ -52,6 +57,8 @@ assert bluezSupport -> bluez != null;
 with stdenv.lib;
 
 let
+  buildPackages = pkgsBuildHost;
+  inherit (passthru) pythonForBuild;
 
   passthru = passthruFun rec {
     inherit self sourceVersion packageOverrides;
@@ -60,13 +67,20 @@ let
     executable = libPrefix;
     pythonVersion = with sourceVersion; "${major}.${minor}";
     sitePackages = "lib/${libPrefix}/site-packages";
-    inherit hasDistutilsCxxPatch pythonForBuild;
+    inherit hasDistutilsCxxPatch;
+    pythonOnBuildForBuild = pkgsBuildBuild.${pythonAttr};
+    pythonOnBuildForHost = pkgsBuildHost.${pythonAttr};
+    pythonOnBuildForTarget = pkgsBuildTarget.${pythonAttr};
+    pythonOnHostForHost = pkgsHostHost.${pythonAttr};
+    pythonOnTargetForTarget = pkgsTargetTarget.${pythonAttr} or {};
   };
 
   version = with sourceVersion; "${major}.${minor}.${patch}${suffix}";
 
   nativeBuildInputs = optionals (!stdenv.isDarwin) [
     autoreconfHook
+  ] ++ optionals (!stdenv.isDarwin && passthru.pythonAtLeast "3.10") [
+    autoconf-archive # needed for AX_CHECK_COMPILE_FLAG
   ] ++ [
     nukeReferences
   ] ++ optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
@@ -82,8 +96,6 @@ let
 
   hasDistutilsCxxPatch = !(stdenv.cc.isGNU or false);
 
-  inherit pythonForBuild;
-
   pythonForBuildInterpreter = if stdenv.hostPlatform == stdenv.buildPlatform then
     "$out/bin/python"
   else pythonForBuild.interpreter;
@@ -153,6 +165,9 @@ in with passthru; stdenv.mkDerivation {
   ] ++ [
     # LDSHARED now uses $CC instead of gcc. Fixes cross-compilation of extension modules.
     ./3.8/0001-On-all-posix-systems-not-just-Darwin-set-LDSHARED-if.patch
+  ] ++ optionals (isPy37 || isPy38) [
+    # Backport a fix for ctypes.util.find_library.
+    ./3.7/find_library.patch
   ];
 
   postPatch = ''
@@ -291,13 +306,6 @@ in with passthru; stdenv.mkDerivation {
     find $out -name "*.py" | ${pythonForBuildInterpreter} -OO -m compileall -q -f -x "lib2to3" -i -
     '' + optionalString stripBytecode ''
     find $out -type d -name __pycache__ -print0 | xargs -0 -I {} rm -rf "{}"
-    '' + ''
-    # *strip* shebang from libpython gdb script - it should be dual-syntax and
-    # interpretable by whatever python the gdb in question is using, which may
-    # not even match the major version of this python. doing this after the
-    # bytecode compilations for the same reason.
-    mkdir -p $out/share/gdb
-    sed '/^#!/d' Tools/gdb/libpython.py > $out/share/gdb/libpython.py
   '';
 
   preFixup = stdenv.lib.optionalString (stdenv.hostPlatform != stdenv.buildPlatform) ''
@@ -315,8 +323,6 @@ in with passthru; stdenv.mkDerivation {
     pythonForBuild buildPackages.bash
   ];
 
-  separateDebugInfo = true;
-
   inherit passthru;
 
   enableParallelBuilding = true;
diff --git a/nixpkgs/pkgs/development/interpreters/python/default.nix b/nixpkgs/pkgs/development/interpreters/python/default.nix
index ce357b6f58e3..2982cdc8856d 100644
--- a/nixpkgs/pkgs/development/interpreters/python/default.nix
+++ b/nixpkgs/pkgs/development/interpreters/python/default.nix
@@ -14,13 +14,70 @@ with pkgs;
     , packageOverrides
     , sitePackages
     , hasDistutilsCxxPatch
-    , pythonForBuild
-    , self
+    , pythonOnBuildForBuild
+    , pythonOnBuildForHost
+    , pythonOnBuildForTarget
+    , pythonOnHostForHost
+    , pythonOnTargetForTarget
+    , self # is pythonOnHostForTarget
     }: let
-      pythonPackages = callPackage ../../../top-level/python-packages.nix {
-        python = self;
-        overrides = packageOverrides;
-      };
+      pythonPackages = callPackage
+        ({ pkgs, stdenv, python, overrides }: let
+          pythonPackagesFun = import ../../../top-level/python-packages.nix {
+            inherit stdenv pkgs;
+            python = self;
+          };
+          otherSplices = {
+            selfBuildBuild = pythonOnBuildForBuild.pkgs;
+            selfBuildHost = pythonOnBuildForHost.pkgs;
+            selfBuildTarget = pythonOnBuildForTarget.pkgs;
+            selfHostHost = pythonOnHostForHost.pkgs;
+            selfTargetTarget = pythonOnTargetForTarget.pkgs or {}; # There is no Python TargetTarget.
+          };
+          keep = self: {
+            # TODO maybe only define these here so nothing is needed to be kept in sync.
+            inherit (self)
+              isPy27 isPy35 isPy36 isPy37 isPy38 isPy39 isPy3k isPyPy pythonAtLeast pythonOlder
+              python bootstrapped-pip buildPythonPackage buildPythonApplication
+              fetchPypi
+              hasPythonModule requiredPythonModules makePythonPath disabledIf
+              toPythonModule toPythonApplication
+              buildSetupcfg
+
+              eggUnpackHook
+              eggBuildHook
+              eggInstallHook
+              flitBuildHook
+              pipBuildHook
+              pipInstallHook
+              pytestCheckHook
+              pythonCatchConflictsHook
+              pythonImportsCheckHook
+              pythonNamespacesHook
+              pythonRecompileBytecodeHook
+              pythonRemoveBinBytecodeHook
+              pythonRemoveTestsDirHook
+              setuptoolsBuildHook
+              setuptoolsCheckHook
+              venvShellHook
+              wheelUnpackHook
+
+              wrapPython
+
+              pythonPackages
+
+              recursivePthLoader
+            ;
+          };
+        in lib.makeScopeWithSplicing
+          pkgs.splicePackages
+          pkgs.newScope
+          otherSplices
+          keep
+          (lib.extends overrides pythonPackagesFun))
+        {
+          overrides = packageOverrides;
+        };
     in rec {
         isPy27 = pythonVersion == "2.7";
         isPy35 = pythonVersion == "3.5";
@@ -28,6 +85,7 @@ with pkgs;
         isPy37 = pythonVersion == "3.7";
         isPy38 = pythonVersion == "3.8";
         isPy39 = pythonVersion == "3.9";
+        isPy310 = pythonVersion == "3.10";
         isPy2 = lib.strings.substring 0 1 pythonVersion == "2";
         isPy3 = lib.strings.substring 0 1 pythonVersion == "3";
         isPy3k = isPy3;
@@ -41,13 +99,15 @@ with pkgs;
         inherit sourceVersion packageOverrides;
         pythonAtLeast = lib.versionAtLeast pythonVersion;
         pythonOlder = lib.versionOlder pythonVersion;
-        inherit hasDistutilsCxxPatch pythonForBuild;
+        inherit hasDistutilsCxxPatch;
+        # TODO: rename to pythonOnBuild
+        # Not done immediately because its likely used outside Nixpkgs.
+        pythonForBuild = pythonOnBuildForHost.override { inherit packageOverrides; self = pythonForBuild; };
 
         tests = callPackage ./tests.nix {
           python = self;
         };
   };
-
 in {
 
   python27 = callPackage ./cpython/2.7 {
@@ -94,10 +154,10 @@ in {
     sourceVersion = {
       major = "3";
       minor = "8";
-      patch = "5";
+      patch = "6";
       suffix = "";
     };
-    sha256 = "1c43dbv9lvlp3ynqmgdi4rh8q94swanhqarqrdx62zmigpakw073";
+    sha256 = "qeC3nSeqBW65zOjWOkJ7X5urFGXe4/lC3P2yWoL0q4o=";
     inherit (darwin) configd;
     inherit passthruFun;
   };
@@ -107,10 +167,23 @@ in {
     sourceVersion = {
       major = "3";
       minor = "9";
+      patch = "1";
+      suffix = "";
+    };
+    sha256 = "1zq3k4ymify5ig739zyvx9s2ainvchxb1zpy139z74krr653y74r";
+    inherit (darwin) configd;
+    inherit passthruFun;
+  };
+
+  python310 = callPackage ./cpython {
+    self = python310;
+    sourceVersion = {
+      major = "3";
+      minor = "10";
       patch = "0";
-      suffix = "rc1";
+      suffix = "a3";
     };
-    sha256 = "0w6wvyy9fbvfvrmhvmlb5gq18haagywk9hjkp1knjdarfczag9zv";
+    sha256 = "sha256-sJjJdAdxOUfX7W7VioSGdxlgp2lyMOPZjg42MCd/JYY=";
     inherit (darwin) configd;
     inherit passthruFun;
   };
@@ -118,7 +191,6 @@ in {
   # Minimal versions of Python (built without optional dependencies)
   python3Minimal = (python38.override {
     self = python3Minimal;
-    pythonForBuild = pkgs.buildPackages.python3Minimal;
     # strip down that python version as much as possible
     openssl = null;
     readline = null;
diff --git a/nixpkgs/pkgs/development/interpreters/python/hooks/default.nix b/nixpkgs/pkgs/development/interpreters/python/hooks/default.nix
index d14eb9cbb09d..1a64c79232bc 100644
--- a/nixpkgs/pkgs/development/interpreters/python/hooks/default.nix
+++ b/nixpkgs/pkgs/development/interpreters/python/hooks/default.nix
@@ -1,14 +1,15 @@
 # Hooks for building Python packages.
 { python
 , lib
-, callPackage
 , makeSetupHook
 , disabledIf
 , isPy3k
 , ensureNewerSourcesForZipFilesHook
+, findutils
 }:
 
 let
+  callPackage = python.pythonForBuild.pkgs.callPackage;
   pythonInterpreter = python.pythonForBuild.interpreter;
   pythonSitePackages = python.sitePackages;
   pythonCheckInterpreter = python.interpreter;
@@ -94,7 +95,7 @@ in rec {
     makeSetupHook {
       name = "python-namespaces-hook.sh";
       substitutions = {
-        inherit pythonSitePackages;
+        inherit pythonSitePackages findutils;
       };
     } ./python-namespaces-hook.sh) {};
 
diff --git a/nixpkgs/pkgs/development/interpreters/python/hooks/pip-install-hook.sh b/nixpkgs/pkgs/development/interpreters/python/hooks/pip-install-hook.sh
index 770739b36bde..a4f08b8b14cb 100644
--- a/nixpkgs/pkgs/development/interpreters/python/hooks/pip-install-hook.sh
+++ b/nixpkgs/pkgs/development/interpreters/python/hooks/pip-install-hook.sh
@@ -11,9 +11,7 @@ pipInstallPhase() {
     export PYTHONPATH="$out/@pythonSitePackages@:$PYTHONPATH"
 
     pushd dist || return 1
-    mkdir tmpbuild
-    NIX_PIP_INSTALL_TMPDIR=tmpbuild @pythonInterpreter@ -m pip install ./*.whl --no-index --prefix="$out" --no-cache $pipInstallFlags
-    rm -rf tmpbuild
+    @pythonInterpreter@ -m pip install ./*.whl --no-index --no-warn-script-location --prefix="$out" --no-cache $pipInstallFlags
     popd || return 1
 
     runHook postInstall
diff --git a/nixpkgs/pkgs/development/interpreters/python/hooks/python-namespaces-hook.sh b/nixpkgs/pkgs/development/interpreters/python/hooks/python-namespaces-hook.sh
index 50f21819d176..15d2bd0eb34c 100644
--- a/nixpkgs/pkgs/development/interpreters/python/hooks/python-namespaces-hook.sh
+++ b/nixpkgs/pkgs/development/interpreters/python/hooks/python-namespaces-hook.sh
@@ -17,16 +17,17 @@ pythonNamespacesHook() {
         for pathSegment in ${pathSegments[@]}; do
             constructedPath=${constructedPath}/${pathSegment}
             pathToRemove=${constructedPath}/__init__.py
-            pycachePath=${constructedPath}/__pycache__/__init__*
+            pycachePath=${constructedPath}/__pycache__/
 
+            # remove __init__.py
             if [ -f "$pathToRemove" ]; then
-                echo "Removing $pathToRemove"
-                rm "$pathToRemove"
+                rm -v "$pathToRemove"
             fi
 
-            if [ -f "$pycachePath" ]; then
-                echo "Removing $pycachePath"
-                rm "$pycachePath"
+            # remove __pycache__/ entry, can be interpreter specific. E.g. __init__.cpython-38.pyc
+            # use null characters to perserve potential whitespace in filepath
+            if [ -d "$pycachePath" ]; then
+                @findutils@/bin/find "$pycachePath" -name '__init__*' -exec rm -v "{}" +
             fi
         done
     done
diff --git a/nixpkgs/pkgs/development/interpreters/python/mk-python-derivation.nix b/nixpkgs/pkgs/development/interpreters/python/mk-python-derivation.nix
index c3be76790ebd..670c870f1077 100644
--- a/nixpkgs/pkgs/development/interpreters/python/mk-python-derivation.nix
+++ b/nixpkgs/pkgs/development/interpreters/python/mk-python-derivation.nix
@@ -17,7 +17,6 @@
 , pythonCatchConflictsHook
 , pythonImportsCheckHook
 , pythonNamespacesHook
-, pythonRecompileBytecodeHook
 , pythonRemoveBinBytecodeHook
 , pythonRemoveTestsDirHook
 , setuptoolsBuildHook
@@ -54,7 +53,9 @@
 , disabled ? false
 
 # Raise an error if two packages are installed with the same name
-, catchConflicts ? true
+# TODO: For cross we probably need a different PYTHONPATH, or not
+# add the runtime deps until after buildPhase.
+, catchConflicts ? (python.stdenv.hostPlatform == python.stdenv.buildPlatform)
 
 # Additional arguments to pass to the makeWrapper function, which wraps
 # generated binaries.
@@ -113,7 +114,6 @@ let
       python
       wrapPython
       ensureNewerSourcesForZipFilesHook  # move to wheel installer (pip) or builder (setuptools, flit, ...)?
-      pythonRecompileBytecodeHook  # Remove when solved https://github.com/NixOS/nixpkgs/issues/81441
       pythonRemoveTestsDirHook
     ] ++ lib.optionals catchConflicts [
       setuptools pythonCatchConflictsHook
@@ -167,9 +167,6 @@ let
     # Python packages built through cross-compilation are always for the host platform.
     disallowedReferences = lib.optionals (python.stdenv.hostPlatform != python.stdenv.buildPlatform) [ python.pythonForBuild ];
 
-    # For now, revert recompilation of bytecode.
-    dontUsePythonRecompileBytecode = true;
-
     meta = {
       # default to python's platforms
       platforms = python.meta.platforms;
diff --git a/nixpkgs/pkgs/development/interpreters/python/pypy/default.nix b/nixpkgs/pkgs/development/interpreters/python/pypy/default.nix
index 10073602071a..8feeb3c51bf3 100644
--- a/nixpkgs/pkgs/development/interpreters/python/pypy/default.nix
+++ b/nixpkgs/pkgs/development/interpreters/python/pypy/default.nix
@@ -5,10 +5,16 @@
 , python-setup-hook
 # For the Python package set
 , packageOverrides ? (self: super: {})
+, pkgsBuildBuild
+, pkgsBuildHost
+, pkgsBuildTarget
+, pkgsHostHost
+, pkgsTargetTarget
 , sourceVersion
 , pythonVersion
 , sha256
 , passthruFun
+, pythonAttr ? "pypy${stdenv.lib.substring 0 1 pythonVersion}${stdenv.lib.substring 2 3 pythonVersion}"
 }:
 
 assert zlibSupport -> zlib != null;
@@ -22,9 +28,14 @@ let
     implementation = "pypy";
     libPrefix = "pypy${pythonVersion}";
     executable = "pypy${if isPy3k then "3" else ""}";
-    pythonForBuild = self; # No cross-compiling for now.
     sitePackages = "site-packages";
     hasDistutilsCxxPatch = false;
+
+    pythonOnBuildForBuild = pkgsBuildBuild.${pythonAttr};
+    pythonOnBuildForHost = pkgsBuildHost.${pythonAttr};
+    pythonOnBuildForTarget = pkgsBuildTarget.${pythonAttr};
+    pythonOnHostForHost = pkgsHostHost.${pythonAttr};
+    pythonOnTargetForTarget = pkgsTargetTarget.${pythonAttr} or {};
   };
   pname = passthru.executable;
   version = with sourceVersion; "${major}.${minor}.${patch}";
@@ -151,7 +162,7 @@ in with passthru; stdenv.mkDerivation rec {
     homepage = "http://pypy.org/";
     description = "Fast, compliant alternative implementation of the Python language (${pythonVersion})";
     license = licenses.mit;
-    platforms = [ "i686-linux" "x86_64-linux" "x86_64-darwin" ];
+    platforms = [ "aarch64-linux" "i686-linux" "x86_64-linux" "x86_64-darwin" ];
     maintainers = with maintainers; [ andersk ];
   };
 }
diff --git a/nixpkgs/pkgs/development/interpreters/python/tests.nix b/nixpkgs/pkgs/development/interpreters/python/tests.nix
index dcfa41cc308e..a291919b3277 100644
--- a/nixpkgs/pkgs/development/interpreters/python/tests.nix
+++ b/nixpkgs/pkgs/development/interpreters/python/tests.nix
@@ -1,4 +1,5 @@
-{ python
+{ stdenv
+, python
 , runCommand
 , substituteAll
 , lib
@@ -92,4 +93,4 @@ let
 
 
 
-in environmentTests // integrationTests
+in stdenv.lib.optionalAttrs (stdenv.hostPlatform == stdenv.buildPlatform ) (environmentTests // integrationTests)
diff --git a/nixpkgs/pkgs/development/interpreters/python/tests/test_nix_pythonprefix/default.nix b/nixpkgs/pkgs/development/interpreters/python/tests/test_nix_pythonprefix/default.nix
index 05798cbaf1b8..572cbdccbfb2 100644
--- a/nixpkgs/pkgs/development/interpreters/python/tests/test_nix_pythonprefix/default.nix
+++ b/nixpkgs/pkgs/development/interpreters/python/tests/test_nix_pythonprefix/default.nix
@@ -4,7 +4,7 @@ let
 
   python = let
     packageOverrides = self: super: {
-      typeddep = super.callPackage ./typeddep {};
+      typeddep = self.callPackage ./typeddep {};
     };
   in interpreter.override {inherit packageOverrides; self = python;};
 
diff --git a/nixpkgs/pkgs/development/interpreters/python/update-python-libraries/default.nix b/nixpkgs/pkgs/development/interpreters/python/update-python-libraries/default.nix
index 762ca2bdd34b..81975bc5250e 100644
--- a/nixpkgs/pkgs/development/interpreters/python/update-python-libraries/default.nix
+++ b/nixpkgs/pkgs/development/interpreters/python/update-python-libraries/default.nix
@@ -9,4 +9,4 @@ runCommand "update-python-libraries" {
   cp ${./update-python-libraries.py} $out
   patchShebangs $out
   substituteInPlace $out --replace 'GIT = "git"' 'GIT = "${git}/bin/git"'
-''
\ No newline at end of file
+''
diff --git a/nixpkgs/pkgs/development/interpreters/python/update-python-libraries/update-python-libraries.py b/nixpkgs/pkgs/development/interpreters/python/update-python-libraries/update-python-libraries.py
index b568ee6751d7..9054195ab7e6 100755
--- a/nixpkgs/pkgs/development/interpreters/python/update-python-libraries/update-python-libraries.py
+++ b/nixpkgs/pkgs/development/interpreters/python/update-python-libraries/update-python-libraries.py
@@ -12,11 +12,10 @@ to update all non-pinned libraries in that folder.
 """
 
 import argparse
-import logging
 import os
+import pathlib
 import re
 import requests
-import toolz
 from concurrent.futures import ThreadPoolExecutor as Pool
 from packaging.version import Version as _Version
 from packaging.version import InvalidVersion
@@ -34,6 +33,8 @@ PRERELEASES = False
 
 GIT = "git"
 
+NIXPGKS_ROOT = subprocess.check_output(["git", "rev-parse", "--show-toplevel"]).decode('utf-8').strip()
+
 import logging
 logging.basicConfig(level=logging.INFO)
 
@@ -101,6 +102,7 @@ def _replace_value(attribute, value, text):
     new_text = text.replace(old_line, new_line)
     return new_text
 
+
 def _fetch_page(url):
     r = requests.get(url)
     if r.status_code == requests.codes.ok:
@@ -109,6 +111,19 @@ def _fetch_page(url):
         raise ValueError("request for {} failed".format(url))
 
 
+def _fetch_github(url):
+    headers = {}
+    token = os.environ.get('GITHUB_API_TOKEN')
+    if token:
+        headers["Authorization"] = f"token {token}"
+    r = requests.get(url, headers=headers)
+
+    if r.status_code == requests.codes.ok:
+        return r.json()
+    else:
+        raise ValueError("request for {} failed".format(url))
+
+
 SEMVER = {
     'major' : 0,
     'minor' : 1,
@@ -167,11 +182,45 @@ def _get_latest_version_pypi(package, extension, current_version, target):
             break
     else:
         sha256 = None
-    return version, sha256
+    return version, sha256, None
 
 
 def _get_latest_version_github(package, extension, current_version, target):
-    raise ValueError("updating from GitHub is not yet supported.")
+    def strip_prefix(tag):
+        return re.sub("^[^0-9]*", "", tag)
+
+    def get_prefix(string):
+        matches = re.findall(r"^([^0-9]*)", string)
+        return next(iter(matches), "")
+
+    # when invoked as an updateScript, UPDATE_NIX_ATTR_PATH will be set
+    # this allows us to work with packages which live outside of python-modules
+    attr_path = os.environ.get("UPDATE_NIX_ATTR_PATH", f"python3Packages.{package}")
+    try:
+        homepage = subprocess.check_output(
+            ["nix", "eval", "-f", f"{NIXPGKS_ROOT}/default.nix", "--raw", f"{attr_path}.src.meta.homepage"])\
+            .decode('utf-8')
+    except Exception as e:
+        raise ValueError(f"Unable to determine homepage: {e}")
+    owner_repo = homepage[len("https://github.com/"):]  # remove prefix
+    owner, repo = owner_repo.split("/")
+
+    url = f"https://api.github.com/repos/{owner}/{repo}/releases"
+    all_releases = _fetch_github(url)
+    releases = list(filter(lambda x: not x['prerelease'], all_releases))
+
+    if len(releases) == 0:
+        raise ValueError(f"{homepage} does not contain any stable releases")
+
+    versions = map(lambda x: strip_prefix(x['tag_name']), releases)
+    version = _determine_latest_version(current_version, target, versions)
+
+    release = next(filter(lambda x: strip_prefix(x['tag_name']) == version, releases))
+    prefix = get_prefix(release['tag_name'])
+    sha256 = subprocess.check_output(["nix-prefetch-url", "--type", "sha256", "--unpack", f"{release['tarball_url']}"], stderr=subprocess.DEVNULL)\
+        .decode('utf-8').strip()
+
+    return version, sha256, prefix
 
 
 FETCHERS = {
@@ -240,7 +289,9 @@ def _determine_extension(text, fetcher):
             raise ValueError('url does not point to PyPI.')
 
     elif fetcher == 'fetchFromGitHub':
-        raise ValueError('updating from GitHub is not yet implemented.')
+        if "fetchSubmodules" in text:
+            raise ValueError("fetchFromGitHub fetcher doesn't support submodules")
+        extension = "tar.gz"
 
     return extension
 
@@ -262,7 +313,7 @@ def _update_package(path, target):
 
     extension = _determine_extension(text, fetcher)
 
-    new_version, new_sha256 = FETCHERS[fetcher](pname, extension, version, target)
+    new_version, new_sha256, prefix = FETCHERS[fetcher](pname, extension, version, target)
 
     if new_version == version:
         logging.info("Path {}: no update available for {}.".format(path, pname))
@@ -274,6 +325,10 @@ def _update_package(path, target):
 
     text = _replace_value('version', new_version, text)
     text = _replace_value('sha256', new_sha256, text)
+    if fetcher == 'fetchFromGitHub':
+        text = _replace_value('rev', f"{prefix}${{version}}", text)
+        # incase there's no prefix, just rewrite without interpolation
+        text = text.replace('"${version}";', 'version;')
 
     with open(path, 'w') as f:
         f.write(text)
@@ -333,7 +388,11 @@ def _commit(path, pname, old_version, new_version, pkgs_prefix="python: ", **kwa
 
 def main():
 
-    parser = argparse.ArgumentParser()
+    epilog = """
+environment variables:
+  GITHUB_API_TOKEN\tGitHub API token used when updating github packages
+    """
+    parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, epilog=epilog)
     parser.add_argument('package', type=str, nargs='+')
     parser.add_argument('--target', type=str, choices=SEMVER.keys(), default='major')
     parser.add_argument('--commit', action='store_true', help='Create a commit for each package update')