[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Supporting upstream supported Python versions

From: Ricardo Wurmus
Subject: Re: Supporting upstream supported Python versions
Date: Wed, 01 Jun 2022 09:50:39 +0200
User-agent: mu4e 1.6.10; emacs 28.1


> From: jgart <>
> To: Guix Devel <>
> Subject: Supporting upstream supported Python versions
> Message-ID: <20220517003848.GB18763@gac>
> What is the opinion on supporting current upstream supported versions
> of python?
> The master branch only has 3.9 but I'd like to have substitutes available
> for 3.7, 3.8 and 3.10:

The Guix Past channel now also has python-3.8.

I recently needed to be able to build a profile with Python packages
that were built with Python 3.8, but without replacing each and every
instance of Python (because I don’t want to build librsvg, gtk+, etc).

Here’s the manifest I came up with:

--8<---------------cut here---------------start------------->8---
;;; Manifest to build the latest Python packages with Python 3.8.
(use-modules (guix packages)           ; for "package", "package-arguments"...
             (guix build-system python)
             (guix utils)
             (ice-9 match))

;; The list of Python packages (or rather specifications) that we want
;; to build with an older Python.
(define packages
  (list "python-numpy"

(define old-python
  (specification->package "python@3.8"))

(define old-python-wrapper
  ;; We use wrap-python3 to create a "python" executable.  Python
  ;; itself only comes with "python3".  Python 3.8 is available in the
  ;; guix-past channel.
  ((@@ (gnu packages python) wrap-python3) old-python))

(define (python-package? package)
  (or (eq? python-build-system
           (package-build-system package))
      ;; Special cases: packages that produce Python modules but don't
      ;; use the Python build system.
      (member (package-name package)
              (list "pybind11"))))

;; I'd love to just use modify-inputs here, but this python-wrapper vs
;; python complication forces me to do this manually.
(define (replace-python-in-inputs inputs python-wrapper python)
  "Some packages have an explicit Python in the inputs, or use a
separate output of the Python package.  We use PYTHON-WRAPPER wherever
the \"python\" executable may be needed and the plain PYTHON package
where we need selected outputs."
  (map (match-lambda
         (("python" package out) `("python" ,python ,out))
         (("python" package) `("python" ,python-wrapper))
         (anything anything))

(define (package-with-different-python pkg python-wrapper python)
  "Return a new package based on PKG that uses PYTHON during the build."
  (package/inherit pkg
     (if (eq? (package-build-system pkg)
          (package-arguments pkg)
          `(#:python ,python-wrapper
            #:tests? #false))   ;running tests is slow, so why bother?
         (package-arguments pkg)))
     (replace-python-in-inputs (package-native-inputs pkg)
                               python-wrapper python))
     (replace-python-in-inputs (package-inputs pkg)
                               python-wrapper python))
     (replace-python-in-inputs (package-propagated-inputs pkg)
                               python-wrapper python))))

;; This is a recursive package transformer.  When given a package
;; "pkg" it checks if it is a Python package by looking at its build
;; system; if that is the case, it will return a package variant that
;; is built with the old Python.  It does this recursively, so all
;; dependencies are also modified.
(define use-old-python
   (lambda (pkg)
     (if (python-package? pkg)
         (let ((modified (package-with-different-python pkg
           (match (package-name pkg)
             ;; This package also needs a newer version of setuptools;
             ;; Python 3.8 comes with an older version of setuptools.
             ((or "python-importlib-metadata"
              (package/inherit modified
                 (modify-inputs (package-native-inputs modified)
                   (prepend (specification->package "python-setuptools"))))))
             ;; This package expects to export
             ;; _SpecialGenericAlias, but this version of Python does
             ;; not define it.
              (package/inherit modified
                 (substitute-keyword-arguments (package-arguments modified)
                   ((#:phases phases '%standard-phases)
                    `(modify-phases ,phases
                       (add-after 'unpack 'do-not-import-SpecialGenericAlias
                         (lambda _
                           (substitute* ""
             ;; The other packages don't need special treatment.
             (else modified)))
   ;; Stop recursion when we hit a package that is not considered a
   ;; Python package.  This could be a package that uses Python or
   ;; Python modules as inputs but does not itself produce a Python
   ;; module.  This is to avoid needlessly rebuilding big things like
   ;; GTK+.
   (negate python-package?)
   #:deep? #false))

;; Apply the transformer to the list of packages.
(define python-packages-with-old-python
  (map (compose use-old-python specification->package)

;; Build a manifest from the list of modified packages and the old
;; Python variant itself.
 (cons old-python
--8<---------------cut here---------------end--------------->8---


reply via email to

[Prev in Thread] Current Thread [Next in Thread]