diff --git a/Makefile.am b/Makefile.am index dc5cf9babc..7ef8d4d61e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -380,6 +380,7 @@ AUX_FILES = \ gnu/packages/aux-files/linux-libre/4.4-i686.conf \ gnu/packages/aux-files/linux-libre/4.4-x86_64.conf \ gnu/packages/aux-files/pack-audit.c \ + gnu/packages/aux-files/python/sitecustomize.py \ gnu/packages/aux-files/run-in-namespace.c # Templates, examples. diff --git a/gnu/packages/aux-files/python/sitecustomize.py b/gnu/packages/aux-files/python/sitecustomize.py new file mode 100644 index 0000000000..65d3c7d554 --- /dev/null +++ b/gnu/packages/aux-files/python/sitecustomize.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# GNU Guix --- Functional package management for GNU +# Copyright © 2021 Maxim Cournoyer +# +# This file is part of GNU Guix. +# +# GNU Guix is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or (at +# your option) any later version. +# +# GNU Guix is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Guix. If not, see . + +import os +import sys + +python_root = os.path.realpath(sys.executable).split('/bin/')[0] +major_minor = '{}.{}'.format(sys.version_info[0], sys.version_info[1]) +site_packages_prefix = 'lib/python' + major_minor + '/site-packages' +python_site = python_root + '/' + site_packages_prefix + +try: + all_sites_raw = os.environ['GUIX_PYTHONPATH'].split(':') +except KeyError: + all_sites_raw = [] +# Normalize paths, otherwise a trailing slash would cause it to not match. +all_sites_norm = [os.path.normpath(p) for p in all_sites_raw] +matching_sites = [p for p in all_sites_norm + if p.endswith(site_packages_prefix)] + +# Insert sites matching the current version into sys.path, right before +# Python's own site. +sys_path_absolute = [os.path.realpath(p) for p in sys.path] +index = sys_path_absolute.index(python_site) +sys.path = sys.path[:index] + matching_sites + sys.path[index:] diff --git a/gnu/packages/commencement.scm b/gnu/packages/commencement.scm index 3e91179c71..22ec5a04ec 100644 --- a/gnu/packages/commencement.scm +++ b/gnu/packages/commencement.scm @@ -9,6 +9,7 @@ ;;; Copyright © 2019, 2020 Marius Bakke ;;; Copyright © 2020 Timothy Sample ;;; Copyright © 2020 Guy Fleury Iteriteka +;;; Copyright © 2021 Maxim Cournoyer ;;; ;;; This file is part of GNU Guix. ;;; @@ -54,6 +55,7 @@ #:use-module (guix download) #:use-module (guix build-system gnu) #:use-module (guix build-system trivial) + #:use-module (guix gexp) #:use-module ((guix licenses) #:prefix license:) #:use-module (guix memoization) #:use-module (guix utils) @@ -3095,7 +3097,9 @@ memoized as a function of '%current-system'." (inputs `(,@(%boot0-inputs) ("expat" ,expat-sans-tests))) ;remove OpenSSL, zlib, etc. - (native-inputs '()) ;and pkg-config + (native-inputs ;and pkg-config + `(("sitecustomize.py" ,(local-file (search-auxiliary-file + "python/sitecustomize.py"))))) (arguments `(#:implicit-inputs? #f #:guile ,%bootstrap-guile @@ -3136,8 +3140,12 @@ memoized as a function of '%current-system'." (substitute* "Lib/plat-generic/regen" (("/usr/include/") (string-append libc "/include/"))))))) - '()))) - ((#:tests? _ #f) #f)))))) + '()) + (replace 'install-sitecustomize.py + ,(customize-site version)))) + ((#:tests? _ #f) #f)))) + (native-search-paths + (list (guix-pythonpath-search-path version))))) (define/system-dependent ld-wrapper-boot0 ;; The first 'ld' wrapper, defined with 'define/system-dependent' because diff --git a/gnu/packages/python.scm b/gnu/packages/python.scm index d3df1a4dab..258e0749f0 100644 --- a/gnu/packages/python.scm +++ b/gnu/packages/python.scm @@ -96,13 +96,41 @@ #:use-module (gnu packages tcl) #:use-module (gnu packages tls) #:use-module (gnu packages xml) + #:use-module (guix gexp) #:use-module (guix packages) #:use-module (guix download) #:use-module (guix utils) #:use-module (guix build-system gnu) #:use-module (guix build-system trivial) #:use-module (srfi srfi-1) - #:use-module (srfi srfi-26)) + #:use-module (srfi srfi-26) + + #:export (customize-site + guix-pythonpath-search-path)) + +(define* (customize-site version) + "Generate a install-sitecustomize.py phase, using VERSION." + `(lambda* (#:key inputs outputs #:allow-other-keys) + (let* ((out (assoc-ref outputs "out")) + (site-packages (string-append + out "/lib/python" + ,(version-major+minor version) + "/site-packages")) + (sitecustomize.py (assoc-ref inputs "sitecustomize.py")) + (dest (string-append site-packages "/sitecustomize.py"))) + (mkdir-p site-packages) + (copy-file sitecustomize.py dest) + ;; Set the correct permissions on the installed file, else the byte + ;; compilation phase fails with a permission denied error. + (chmod dest #o644)))) + +(define (guix-pythonpath-search-path version) + "Generate a GUIX_PYTHONPATH search path specification, using VERSION." + (search-path-specification (variable "GUIX_PYTHONPATH") + (files (list (string-append + "lib/python" + (version-major+minor version) + "/site-packages"))))) (define-public python-2.7 (package @@ -266,8 +294,7 @@ (not (string-prefix? "test_support." file)))))) - (call-with-output-file "__init__.py" (const #t)) - #t))))))) + (call-with-output-file "__init__.py" (const #t))))))))) (add-after 'remove-tests 'rebuild-bytecode (lambda* (#:key outputs #:allow-other-keys) (let ((out (assoc-ref outputs "out"))) @@ -313,7 +340,9 @@ "/site-packages"))) (install-file tkinter.so target) (delete-file tkinter.so))))) - #t)))))) + #t))) + (add-after 'install 'install-sitecustomize.py + ,(customize-site version))))) (inputs `(("bzip2" ,bzip2) ("expat" ,expat) @@ -327,15 +356,15 @@ ("tk" ,tk))) ; for tkinter (native-inputs `(("pkg-config" ,pkg-config) + ("sitecustomize.py" ,(local-file (search-auxiliary-file + "python/sitecustomize.py"))) ;; When cross-compiling, a native version of Python itself is needed. ,@(if (%current-target-system) `(("python2" ,this-package) ("which" ,which)) '()))) (native-search-paths - (list (search-path-specification - (variable "PYTHONPATH") - (files '("lib/python2.7/site-packages"))))) + (list (guix-pythonpath-search-path version))) (home-page "https://www.python.org") (synopsis "High-level, dynamically-typed programming language") (description @@ -438,8 +467,7 @@ data types.") (setenv "TZDIR" (string-append (assoc-ref (or native-inputs inputs) "tzdata") - "/share/zoneinfo")) - #t)) + "/share/zoneinfo")))) (replace 'rebuild-bytecode (lambda* (#:key outputs #:allow-other-keys) (let ((out (assoc-ref outputs "out"))) @@ -462,8 +490,9 @@ data types.") ;; Don't build lib2to3, because it's Python 2 code. "-x" "lib2to3/.*" ,out)))) - (list "none" "-O" "-OO")) - #t))))))) + (list "none" "-O" "-OO"))))) + (replace 'install-sitecustomize.py + ,(customize-site version)))))) (native-inputs `(("tzdata" ,tzdata-for-tests) ,@(if (%current-target-system) @@ -471,11 +500,7 @@ data types.") '()) ,@(package-native-inputs python-2))) (native-search-paths - (list (search-path-specification - (variable "PYTHONPATH") - (files (list (string-append "lib/python" - (version-major+minor version) - "/site-packages")))) + (list (guix-pythonpath-search-path version) ;; Used to locate tzdata by the zoneinfo module introduced in ;; Python 3.9. (search-path-specification diff --git a/guix/build/python-build-system.scm b/guix/build/python-build-system.scm index aad86258c7..c6c88e6577 100644 --- a/guix/build/python-build-system.scm +++ b/guix/build/python-build-system.scm @@ -167,9 +167,7 @@ "Return the path of the current output's Python site-package." (let* ((out (python-output outputs)) (python (assoc-ref inputs "python"))) - (string-append out "/lib/python" - (python-version python) - "/site-packages/"))) + (string-append out "/lib/python" (python-version python) "/site-packages"))) (define (add-installed-pythonpath inputs outputs) "Prepend the Python site-package of OUTPUT to PYTHONPATH. This is useful