unofficial mirror of guix-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Lars-Dominik Braun <lars@6xq.net>
To: Tanguy LE CARROUR <tanguy@bioneland.org>
Cc: Guix <guix-devel@gnu.org>
Subject: Re: Questions regarding Python packaging
Date: Sat, 23 Jan 2021 13:34:09 +0100	[thread overview]
Message-ID: <YAwXwV1BNlzL+w47@noor.fritz.box> (raw)
In-Reply-To: <1611303651.35tpgtn1z1.astroid@melmoth.none>

[-- Attachment #1: Type: text/plain, Size: 793 bytes --]

Hi Tanguy,

> Done! :-)
> I've eventually succeeded in ("properly") packaging a software managed
> with Poetry. And I've learned quite a lot on the way!
oh, I see. I’ve actually been trying to replace python-build-system with
a python-build based build. Attached is my current work in progress. I
cannot quite build python-build, because I’m lacking support for
python-flit, but I think the general idea is clear: Remove pip and
setuptools from python (saves almost 20MiB from the closure and avoids
weird conflicts between python’s setuptools and python-setuptools) and
turn them into (almost) ordinary packages. Then use setuptools to
bootstrap itself, bootstrap python-build with setuptools and use
python-build to build evrey other packages using python-build-system.

Cheers,
Lars


[-- Attachment #2: wip-pep-517-build.diff --]
[-- Type: text/plain, Size: 30148 bytes --]

diff --git a/gnu/packages/python-xyz.scm b/gnu/packages/python-xyz.scm
index d08e23936c..a9843bd9cb 100644
--- a/gnu/packages/python-xyz.scm
+++ b/gnu/packages/python-xyz.scm
@@ -1123,14 +1123,14 @@ other machines, such as over the network.")
 (define-public python-setuptools
   (package
     (name "python-setuptools")
-    (version "41.0.1")
+    (version "51.3.1")
     (source
      (origin
       (method url-fetch)
-      (uri (pypi-uri "setuptools" version ".zip"))
+      (uri (pypi-uri "setuptools" version))
       (sha256
        (base32
-        "04sns22y2hhsrwfy1mha2lgslvpjsjsz8xws7h2rh5a7ylkd28m2"))
+        "07qk6ykhq1q4k33x1m96r39f9qpfzp2xfl5ly9zww0180gssrvqc"))
       (modules '((guix build utils)))
       (snippet
        '(begin
@@ -1143,7 +1143,26 @@ other machines, such as over the network.")
     ;; FIXME: Tests require pytest, which itself relies on setuptools.
     ;; One could bootstrap with an internal untested setuptools.
     (arguments
-     `(#:tests? #f))
+     `(#:tests? #f
+       #:need-setuptools #f
+       #:python-build-variant #f
+       #:phases (modify-phases %standard-phases
+                  (replace 'build
+                           (lambda _
+                             (invoke "python" "setup.py" "build")))
+                  (replace 'install
+                           (lambda* (#:key outputs #:allow-other-keys)
+                             (let ((out (assoc-ref outputs "out")))
+                             (invoke "python" "setup.py" "install" "--prefix" out "--single-version-externally-managed" "--root=/"))))
+                  ;; Use this setuptools’ sources to bootstrap themselves.
+                  (add-before 'build 'set-PYTHONPATH
+                    (lambda _
+                      (format #t "current working dir ~s~%" (getcwd))
+                      (setenv "PYTHONPATH"
+                              (string-append ".:" (getenv "PYTHONPATH")))
+                      #t)))))
+    ;; Not required when not building a wheel
+    ;(propagated-inputs `(("python-wheel" ,python-wheel)))
     (home-page "https://pypi.org/project/setuptools/")
     (synopsis
      "Library designed to facilitate packaging Python projects")
@@ -1822,7 +1841,7 @@ Python file, so it can be easily copied into your project.")
   (package
     (inherit python-six)
     (name "python-six-bootstrap")
-    (native-inputs `())
+    (native-inputs '())
     (arguments `(#:tests? #f))))
 
 (define-public python2-six-bootstrap
@@ -5675,7 +5694,8 @@ by pycodestyle.")
              ;; NOTE: Any value works, the variable just has to be present.
              (setenv "SKIP_ONLINE" "1")
              #t)))))
-    (native-inputs `(("unzip" ,unzip)))
+    (native-inputs
+      `(("unzip" ,unzip)))
     (home-page "https://bitbucket.org/pypa/distlib")
     (synopsis "Distribution utilities")
     (description "Distlib is a library which implements low-level functions that
@@ -15272,7 +15292,7 @@ protocols.")
   (package
     (inherit python-attrs)
     (name "python-attrs-bootstrap")
-    (native-inputs `())
+    (native-inputs '())
     (arguments `(#:tests? #f))))
 
 (define-public python2-attrs-bootstrap
@@ -23451,3 +23471,292 @@ Qt applications.")
       "Pivy provides python bindings for Coin, a 3D graphics library with an
 Application Programming Interface based on the Open Inventor 2.1 API.")
     (license license:isc)))
+
+(define-public python-build
+  (package
+    (name "python-build")
+    (version "0.1.0")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "build" version))
+        (sha256
+          (base32
+            "1d6m21lijwm04g50nwgsgj7x3vhblzw7jv05ah8psqgzk20bbch8"))))
+    (build-system python-build-system)
+    (arguments `(#:python-build-variant ,python-build-bootstrap))
+    (propagated-inputs
+      `(("python-packaging" ,python-packaging)
+        ("python-pep517" ,python-pep517)
+        ("python-toml" ,python-toml)
+        ;; For fallback option.
+        ("python-setuptools" ,python-setuptools)))
+    (native-inputs
+      `(("python-filelock" ,python-filelock)
+        ("python-pytest" ,python-pytest)
+        ("python-pytest-cov" ,python-pytest-cov)
+        ("python-pytest-mock" ,python-pytest-mock)
+        ("python-pytest-xdist" ,python-pytest-xdist)))
+    (home-page "https://pypa-build.readthedocs.io/")
+    (synopsis
+      "A simple, correct PEP517 package builder")
+    (description
+      "A simple, correct PEP517 package builder")
+    (license license:expat)))
+
+(define-public python-pep517-bootstrap
+               (package
+                 (inherit python-pep517)
+                 (name "python-pep517-bootstrap")
+                 (arguments `(#:tests? #f))
+                 (native-inputs `())))
+
+(define-public python-build-bootstrap
+  (package
+    (name "python-build-bootstrap")
+    (version "0.1.0")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "build" version))
+        (sha256
+          (base32
+            "1d6m21lijwm04g50nwgsgj7x3vhblzw7jv05ah8psqgzk20bbch8"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:tests? #f
+       #:python-build-variant #f
+       #:phases (modify-phases %standard-phases
+                  (replace 'build
+                           (lambda _
+                             (invoke "python" "setup.py" "build")))
+                  (replace 'install
+                           (lambda* (#:key outputs #:allow-other-keys)
+                             (let ((out (assoc-ref outputs "out")))
+                             (invoke "python" "setup.py" "install" "--prefix" out "--single-version-externally-managed" "--root=/")))))))
+    (propagated-inputs
+      `(("python-pep517" ,python-pep517-source-bootstrap)
+        ("python-packaging" ,python-packaging-source-bootstrap)))
+    (home-page "https://pypa-build.readthedocs.io/")
+    (synopsis
+      "A simple, correct PEP517 package builder")
+    (description
+      "A simple, correct PEP517 package builder")
+    (license license:expat)))
+
+(define-public python-pep517-source-bootstrap
+  (package
+    (name "python-pep517-source-bootstrap")
+    (version "0.9.1")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "pep517" version))
+        (sha256
+         (base32
+          "0zqidxah03qpnp6zkg3zd1kmd5f79hhdsfmlc0cldaniy80qddxf"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:tests? #f
+       #:python-build-variant #f
+       #:phases (modify-phases %standard-phases
+(add-after 'unpack 'patch
+           (lambda _
+             (substitute* "setup.py"
+               (("distutils\\.core") "setuptools"))
+             #t))
+                  (replace 'build
+                           (lambda _
+                             (invoke "python" "setup.py" "build")))
+                  (replace 'install
+                           (lambda* (#:key outputs #:allow-other-keys)
+                             (let ((out (assoc-ref outputs "out")))
+                             (invoke "python" "setup.py" "install" "--prefix" out "--single-version-externally-managed" "--root=/")))))))
+    (propagated-inputs
+     `(("python-toml" ,python-toml-source-bootstrap)
+       ("python-wheel" ,python-wheel-bootstrap)
+       ))
+    (home-page "https://github.com/pypa/pep517")
+    (synopsis "Wrappers to build Python packages using PEP 517 hooks")
+    (description
+     "Wrappers to build Python packages using PEP 517 hooks.")
+    (license license:expat)))
+
+(define-public python-toml-source-bootstrap
+  (package
+    (name "python-toml-source-bootstrap")
+    (version "0.10.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (pypi-uri "toml" version))
+       (sha256
+        (base32
+         "03wbqm5cn685cwx2664hjdpz370njl7lf0yal8s0dkp5w4mn2swj"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:tests? #f
+       #:python-build-variant #f
+       #:phases (modify-phases %standard-phases
+                  (replace 'build
+                           (lambda _
+                             (invoke "python" "setup.py" "build")))
+                  (replace 'install
+                           (lambda* (#:key outputs #:allow-other-keys)
+                             (let ((out (assoc-ref outputs "out")))
+                             (invoke "python" "setup.py" "install" "--prefix" out "--single-version-externally-managed" "--root=/")))))))
+    (home-page "https://github.com/uiri/toml")
+    (synopsis "Library for TOML")
+    (description
+     "@code{toml} is a library for parsing and creating Tom's Obvious, Minimal
+Language (TOML) configuration files.")
+    (license license:expat)))
+
+(define-public python-packaging-source-bootstrap
+  (package
+    (name "python-packaging-source-bootstrap")
+    (version "20.0")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "packaging" version))
+        ;; XXX: The URL in the patch file is wrong, it should be
+        ;; <https://github.com/pypa/packaging/pull/256>.
+        (patches (search-patches "python-packaging-test-arch.patch"))
+        (sha256
+         (base32
+          "1y2ip3a4ykkpgnwgn85j6hkspcl0cg3mzms97f40mk57vwqq67gy"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:tests? #f
+       #:python-build-variant #f
+       #:phases (modify-phases %standard-phases
+                  (replace 'build
+                           (lambda _
+                             (invoke "python" "setup.py" "build")))
+                  (replace 'install
+                           (lambda* (#:key outputs #:allow-other-keys)
+                             (let ((out (assoc-ref outputs "out")))
+                             (invoke "python" "setup.py" "install" "--prefix" out "--single-version-externally-managed" "--root=/")))))))
+    (propagated-inputs
+     `(("python-pyparsing" ,python-pyparsing-bootstrap)
+       ("python-six" ,python-six-bootstrap2)
+       ))
+    (home-page "https://github.com/pypa/packaging")
+    (synopsis "Core utilities for Python packages")
+    (description "Packaging is a Python module for dealing with Python packages.
+It offers an interface for working with package versions, names, and dependency
+information.")
+    ;; From 'LICENSE': This software is made available under the terms of
+    ;; *either* of the licenses found in LICENSE.APACHE or LICENSE.BSD.
+    ;; Contributions to this software is made under the terms of *both* these
+    ;; licenses.
+    (license (list license:asl2.0 license:bsd-2))))
+
+(define-public python-pyparsing-bootstrap
+  (package
+    (name "python-pyparsing-bootstrap")
+    (version "2.4.6")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (pypi-uri "pyparsing" version))
+       (sha256
+        (base32 "17wn5zlijc9m9zj26gy3f541y7smpj8rfhl51d025c2gm210b0sc"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:tests? #f
+       #:python-build-variant #f
+       #:phases (modify-phases %standard-phases
+                  (replace 'build
+                           (lambda _
+                             (invoke "python" "setup.py" "build")))
+                  (replace 'install
+                           (lambda* (#:key outputs #:allow-other-keys)
+                             (let ((out (assoc-ref outputs "out")))
+                             (invoke "python" "setup.py" "install" "--prefix" out "--single-version-externally-managed" "--root=/")))))))
+    (home-page "https://github.com/pyparsing/pyparsing")
+    (synopsis "Python parsing class library")
+    (description
+     "The pyparsing module is an alternative approach to creating and
+executing simple grammars, vs. the traditional lex/yacc approach, or the use
+of regular expressions.  The pyparsing module provides a library of classes
+that client code uses to construct the grammar directly in Python code.")
+    (license license:expat)))
+
+(define-public python-six-bootstrap2
+  (package
+    (name "python-six-bootstrap")
+    (version "1.14.0")
+    (source
+     (origin
+      (method url-fetch)
+      (uri (pypi-uri "six" version))
+      (sha256
+       (base32
+        "02lw67hprv57hyg3cfy02y3ixjk3nzwc0dx3c4ynlvkfwkfdnsr3"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:tests? #f
+       #:python-build-variant #f
+       #:phases (modify-phases %standard-phases
+                  (replace 'build
+                           (lambda _
+                             (invoke "python" "setup.py" "build")))
+                  (replace 'install
+                           (lambda* (#:key outputs #:allow-other-keys)
+                             (let ((out (assoc-ref outputs "out")))
+                             (invoke "python" "setup.py" "install" "--prefix" out "--single-version-externally-managed" "--root=/")))))))
+    (home-page "https://pypi.org/project/six/")
+    (synopsis "Python 2 and 3 compatibility utilities")
+    (description
+     "Six is a Python 2 and 3 compatibility library.  It provides utility
+functions for smoothing over the differences between the Python versions with
+the goal of writing Python code that is compatible on both Python versions.
+Six supports every Python version since 2.5.  It is contained in only one
+Python file, so it can be easily copied into your project.")
+    (license license:x11)))
+
+(define-public python-wheel-bootstrap
+  (package
+    (name "python-wheel-bootstrap")
+    (version "0.33.6")
+    (source
+      (origin
+        (method url-fetch)
+        (uri (pypi-uri "wheel" version))
+        (sha256
+         (base32
+          "0ii6f34rvpjg3nmw4bc2h7fhdsy38y1h93hghncfs5akfrldmj8h"))))
+    (build-system python-build-system)
+    (arguments
+     `(#:tests? #f
+       #:python-build-variant #f
+       #:phases (modify-phases %standard-phases
+(add-after 'unpack 'patch-enable-entrypoints
+           (lambda _
+             ;; python-wheel tells setuptools to not install entry point scripts
+             ;; by default. Stop doing that, so wheels built contain all data
+             ;; required.
+             (substitute* "wheel/bdist_wheel.py"
+               (("(install_scripts\\.no_ep = )True" all assignment) (string-append assignment "False")))
+             #t))
+                  (replace 'build
+                           (lambda _
+                             (invoke "python" "setup.py" "build")))
+                  (replace 'install
+                           (lambda* (#:key outputs #:allow-other-keys)
+                             (let ((out (assoc-ref outputs "out")))
+                             (invoke "python" "setup.py" "install" "--prefix" out "--single-version-externally-managed" "--root=/")))))))
+    (home-page "https://bitbucket.org/pypa/wheel/")
+    (synopsis "Format for built Python packages")
+    (description
+     "A wheel is a ZIP-format archive with a specially formatted filename and
+the @code{.whl} extension.  It is designed to contain all the files for a PEP
+376 compatible install in a way that is very close to the on-disk format.  Many
+packages will be properly installed with only the @code{Unpack} step and the
+unpacked archive preserves enough information to @code{Spread} (copy data and
+scripts to their final locations) at any later time.  Wheel files can be
+installed with a newer @code{pip} or with wheel's own command line utility.")
+    (license license:expat)))
+
diff --git a/gnu/packages/python.scm b/gnu/packages/python.scm
index fa9bf10e07..57221a91ea 100644
--- a/gnu/packages/python.scm
+++ b/gnu/packages/python.scm
@@ -100,6 +100,7 @@
   #:use-module (guix utils)
   #:use-module (guix build-system gnu)
   #:use-module (guix build-system trivial)
+  #:use-module (guix build-system copy)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-26))
 
@@ -153,7 +154,7 @@
        (list "--enable-shared"                    ;allow embedding
              "--with-system-expat"                ;for XML support
              "--with-system-ffi"                  ;build ctypes
-             "--with-ensurepip=install"           ;install pip and setuptools
+             "--with-ensurepip=no"                ;do not install pip and setuptools
              "--enable-unicode=ucs4"
 
              ;; Prevent the installed _sysconfigdata.py from retaining a reference
@@ -874,4 +875,12 @@ Python code natively, including C extensions.")
                    license:bsd-3 ; lib_pypy/cffi/_pycparser/ply/
                    (license:non-copyleft
                     "http://www.unicode.org/copyright.html")))))
+(define* (pypi-uri name version #:optional (extension ".tar.gz"))
+  "Return a URI string for the Python package hosted on the Python Package
+Index (PyPI) corresponding to NAME and VERSION.  EXTENSION is the file name
+extension, such as '.tar.gz'."
+  (string-append "https://files.pythonhosted.org/packages/source/"
+                 (string-take name 1) "/" name "/"
+                 name "-" version extension))
+
 
diff --git a/gnu/packages/xml.scm b/gnu/packages/xml.scm
index 930cd795f5..2af62d59df 100644
--- a/gnu/packages/xml.scm
+++ b/gnu/packages/xml.scm
@@ -64,6 +64,7 @@
   #:use-module (gnu packages perl)
   #:use-module (gnu packages perl-check)
   #:use-module (gnu packages python)
+  #:use-module (gnu packages python-xyz)
   #:use-module (gnu packages tls)
   #:use-module (gnu packages web)
   #:use-module ((guix licenses) #:prefix license:)
@@ -2391,6 +2392,7 @@ The central program included in this package is @code{onsgmls}, which replaces
         (base32
          "15h7d41v48q31hzjay7qzixdv531hnga3h35hksk7x52pgqcrkz7"))))
     (build-system python-build-system)
+    (native-inputs `(("python-setuptools" ,python-setuptools)))
     (home-page
      "https://github.com/sissaschool/elementpath")
     (synopsis
@@ -2416,13 +2418,20 @@ because lxml.etree already has it's own implementation of XPath 1.0.")
         (base32 "01nvb5j8vs9nk4z5s3250b1m22b4d08kffa36if3g1mdygdrvxpg"))))
     (build-system python-build-system)
     (arguments
-     `(#:phases (modify-phases %standard-phases
-                  (replace 'check
+      `(#:phases (modify-phases %standard-phases
+                                ;; Expects setup.py to be called from source root.
+         (add-after 'unpack 'patch-get-base-dir
                     (lambda _
-                      (invoke "make" "test"))))))
+                      (substitute* "versioninfo.py"
+                                   (("os.path.abspath\\(os.path.dirname\\(sys.argv\\[0\\]\\)\\)") "'.'"))
+                      #t))
+         (replace 'check
+                  (lambda _
+                    (invoke "make" "test"))))))
     (inputs
      `(("libxml2" ,libxml2)
        ("libxslt" ,libxslt)))
+    (native-inputs `(("python-setuptools" ,python-setuptools)))
     (home-page "https://lxml.de/")
     (synopsis "Python XML processing library")
     (description
diff --git a/guix/build-system/python.scm b/guix/build-system/python.scm
index e39c06528e..6a9f40faa4 100644
--- a/guix/build-system/python.scm
+++ b/guix/build-system/python.scm
@@ -70,6 +70,16 @@ extension, such as '.tar.gz'."
   (let ((python (resolve-interface '(gnu packages python))))
     (module-ref python 'python-2)))
 
+(define (default-python-build)
+  "Return the default Python 2 package."
+  (let ((python (resolve-interface '(gnu packages python-xyz))))
+    (module-ref python 'python-build-bootstrap)))
+
+(define (default-python-setuptools)
+  "Return the default Python 2 package."
+  (let ((python (resolve-interface '(gnu packages python-xyz))))
+    (module-ref python 'python-setuptools)))
+
 (define* (package-with-explicit-python python old-prefix new-prefix
                                        #:key variant-property)
   "Return a procedure of one argument, P.  The procedure creates a package with
@@ -138,11 +148,13 @@ pre-defined variants."
 (define* (lower name
                 #:key source inputs native-inputs outputs system target
                 (python (default-python))
+                (python-build-variant (default-python-build))
+				(need-setuptools #t)
                 #:allow-other-keys
                 #:rest arguments)
   "Return a bag for NAME."
   (define private-keywords
-    '(#:source #:target #:python #:inputs #:native-inputs))
+    '(#:source #:target #:python #:python-build-variant #:need-setuptools #:inputs #:native-inputs))
 
   (and (not target)                               ;XXX: no cross-compilation
        (bag
@@ -156,6 +168,15 @@ pre-defined variants."
                         ;; Keep the standard inputs of 'gnu-build-system'.
                         ,@(standard-packages)))
          (build-inputs `(("python" ,python)
+                         ,@(if python-build-variant
+							`(("python-build" ,python-build-variant))
+							'())
+						 ;; Most packages still use setuptools and *all* of our
+						 ;; packages assume it’s available, so include it
+						 ;; except when bootstrapping.
+						 ,@(if need-setuptools
+							 `(("python-setuptools" ,(default-python-setuptools)))
+							 '())
                          ,@native-inputs))
          (outputs outputs)
          (build python-build)
@@ -164,8 +185,6 @@ pre-defined variants."
 (define* (python-build store name inputs
                        #:key
                        (tests? #t)
-                       (test-target "test")
-                       (use-setuptools? #t)
                        (configure-flags ''())
                        (phases '(@ (guix build python-build-system)
                                    %standard-phases))
@@ -191,9 +210,7 @@ provides a 'setup.py' file as its build system."
                                   source))
                      #:configure-flags ,configure-flags
                      #:system ,system
-                     #:test-target ,test-target
                      #:tests? ,tests?
-                     #:use-setuptools? ,use-setuptools?
                      #:phases ,phases
                      #:outputs %outputs
                      #:search-paths ',(map search-path-specification->sexp
diff --git a/guix/build/python-build-system.scm b/guix/build/python-build-system.scm
index 09bd8465c8..750c2d33f7 100644
--- a/guix/build/python-build-system.scm
+++ b/guix/build/python-build-system.scm
@@ -104,47 +104,18 @@
 ;; and the scripts defined in entry-points will always be created.
 
 
-(define setuptools-shim
-  ;; Run setup.py with "setuptools" being imported, which will patch
-  ;; "distutils". This is needed for packages using "distutils" instead of
-  ;; "setuptools" since the former does not understand the
-  ;; "--single-version-externally-managed" flag.
-  ;; Python code taken from pip 9.0.1 pip/utils/setuptools_build.py
-  (string-append
-   "import setuptools, tokenize;__file__='setup.py';"
-   "f=getattr(tokenize, 'open', open)(__file__);"
-   "code=f.read().replace('\\r\\n', '\\n');"
-   "f.close();"
-   "exec(compile(code, __file__, 'exec'))"))
-
-(define (call-setuppy command params use-setuptools?)
-  (if (file-exists? "setup.py")
-      (begin
-         (format #t "running \"python setup.py\" with command ~s and parameters ~s~%"
-                command params)
-         (if use-setuptools?
-             (apply invoke "python" "-c" setuptools-shim
-                    command params)
-             (apply invoke "python" "./setup.py" command params)))
-      (error "no setup.py found")))
-
-(define* (build #:key use-setuptools? #:allow-other-keys)
+(define* (build #:key outputs #:allow-other-keys)
   "Build a given Python package."
-  (call-setuppy "build" '() use-setuptools?)
+  ;; XXX: use "wheel" output instead?
+  (mkdir-p "dist")
+  (invoke "python" "-m" "build" "--outdir" "dist" "--no-isolation" "--wheel" ".")
   #t)
 
-(define* (check #:key tests? test-target use-setuptools? #:allow-other-keys)
+(define* (check #:key tests? #:allow-other-keys)
   "Run the test suite of a given Python package."
   (if tests?
-      ;; Running `setup.py test` creates an additional .egg-info directory in
-      ;; build/lib in some cases, e.g. if the source is in a sub-directory
-      ;; (given with `package_dir`). This will by copied to the output, too,
-      ;; so we need to remove.
-      (let ((before (find-files "build" "\\.egg-info$" #:directories? #t)))
-        (call-setuppy test-target '() use-setuptools?)
-        (let* ((after (find-files "build" "\\.egg-info$" #:directories? #t))
-               (inter (lset-difference string=? after before)))
-          (for-each delete-file-recursively inter)))
+    ;; XXX: Choose testing util based on native inputs?
+      (format #t "fixme")
       (format #t "test suite not run~%"))
   #t)
 
@@ -172,18 +143,38 @@ when running checks after installing the package."
                            (if old-path (string-append ":" old-path) "")))
     #t))
 
-(define* (install #:key outputs (configure-flags '()) use-setuptools?
-                  #:allow-other-keys)
+(define* (install #:key inputs outputs (configure-flags '()) #:allow-other-keys)
   "Install a given Python package."
-  (let* ((out (assoc-ref outputs "out"))
-         (params (append (list (string-append "--prefix=" out))
-                         (if use-setuptools?
-                             ;; distutils does not accept these flags
-                             (list "--single-version-externally-managed"
-                                    "--root=/")
-                             '())
-                         configure-flags)))
-    (call-setuppy "install" params use-setuptools?)
+  (let* ((site-dir (site-packages inputs outputs))
+         (out (assoc-ref outputs "out"))
+         (wheels (find-files "dist" "\\.whl$")))
+	(define (extract file)
+      ;; Use Python’s zipfile to avoid extra dependency
+      ;; XXX: have to move data files according to PEP 517
+      (invoke "python3" "-m" "zipfile" "-e" file site-dir))
+
+    (for-each extract wheels)
+
+    ;; for scripts
+    (mkdir-p (string-append out "/bin"))
+	(let ((datadirs (find-files site-dir "\\.data$" #:directories? #t)))
+      (for-each (lambda (d)
+                  (for-each (lambda (f)
+                              (rename-file (string-append d "/scripts/" f) (string-append out "/bin/" (basename f)))
+                              ;; ZIP does not save/restore permissions, make executable, XXX: f might not be a file, but directory with subdirectories
+                              (chmod (string-append out "/bin/" (basename f)) #o755)
+                              (substitute* (string-append out "/bin/" (basename f))
+               (("#!python")
+                (string-append "#!" (assoc-ref inputs "python") "/bin/python"))))
+                            (scandir (string-append d "/scripts") (negate (cut member <> '("." "..")))))) datadirs))
+    #t))
+
+(define* (compile-bytecode #:key inputs outputs (configure-flags '()) #:allow-other-keys)
+  "Compile installed byte-code in site-packages."
+  (let ((site-dir (site-packages inputs outputs)))
+    ;; XXX: replace 0 with max allowed threads
+    (invoke "python3" "-m" "compileall" "-j" "0" site-dir)
+    ;; XXX: We could compile with -O and -OO too here, at the cost of more space.
     #t))
 
 (define* (wrap #:key inputs outputs #:allow-other-keys)
@@ -214,23 +205,6 @@ when running checks after installing the package."
               bindirs)
     #t))
 
-(define* (rename-pth-file #:key name inputs outputs #:allow-other-keys)
-  "Rename easy-install.pth to NAME.pth to avoid conflicts between packages
-installed with setuptools."
-  ;; Even if the "easy-install.pth" is not longer created, we kept this phase.
-  ;; There still may be packages creating an "easy-install.pth" manually for
-  ;; some good reason.
-  (let* ((out (assoc-ref outputs "out"))
-         (python (assoc-ref inputs "python"))
-         (site-packages (string-append out "/lib/python"
-                                       (python-version python)
-                                       "/site-packages"))
-         (easy-install-pth (string-append site-packages "/easy-install.pth"))
-         (new-pth (string-append site-packages "/" name ".pth")))
-    (when (file-exists? easy-install-pth)
-      (rename-file easy-install-pth new-pth))
-    #t))
-
 (define* (ensure-no-mtimes-pre-1980 #:rest _)
   "Ensure that there are no mtimes before 1980-01-02 in the source tree."
   ;; Rationale: patch-and-repack creates tarballs with timestamps at the POSIX
@@ -244,6 +218,13 @@ installed with setuptools."
                #t))
     #t))
 
+(define* (set-SOURCE-DATE-EPOCH #:rest _)
+  "Set the 'SOURCE_DATE_EPOCH' environment variable.  This is used by tools
+that incorporate timestamps as a way to tell them to use a fixed timestamp.
+See https://reproducible-builds.org/specs/source-date-epoch/."
+  (setenv "SOURCE_DATE_EPOCH" "315619200") ;; python-wheel respects this variable and sets pre-1980 times on files in zip files, which is unsupported
+  #t)
+
 (define* (enable-bytecode-determinism #:rest _)
   "Improve determinism of pyc files."
   ;; Use deterministic hashes for strings, bytes, and datetime objects.
@@ -260,14 +241,15 @@ installed with setuptools."
     (add-after 'unpack 'ensure-no-mtimes-pre-1980 ensure-no-mtimes-pre-1980)
     (add-after 'ensure-no-mtimes-pre-1980 'enable-bytecode-determinism
       enable-bytecode-determinism)
+    (replace 'set-SOURCE-DATE-EPOCH set-SOURCE-DATE-EPOCH)
     (delete 'bootstrap)
     (delete 'configure)                 ;not needed
     (replace 'build build)
     (delete 'check)                     ;moved after the install phase
     (replace 'install install)
     (add-after 'install 'check check)
-    (add-after 'install 'wrap wrap)
-    (add-before 'strip 'rename-pth-file rename-pth-file)))
+    (add-before 'check 'compile-bytecode compile-bytecode)
+    (add-after 'install 'wrap wrap)))
 
 (define* (python-build #:key inputs (phases %standard-phases)
                        #:allow-other-keys #:rest args)

  reply	other threads:[~2021-01-23 12:51 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-08 14:27 Questions regarding Python packaging Tanguy Le Carrour
2020-11-08 17:05 ` Leo Famulari
2020-11-10  8:35   ` Tanguy Le Carrour
2020-11-08 20:43 ` Michael Rohleder
2020-11-10  8:30   ` Tanguy Le Carrour
2020-11-09 16:54 ` Hartmut Goebel
2020-11-10  8:47   ` Tanguy Le Carrour
2020-11-10  8:53     ` Hartmut Goebel
2021-01-05 10:25 ` Lars-Dominik Braun
2021-01-06 15:32   ` Tanguy LE CARROUR
2021-01-22  8:38     ` Tanguy LE CARROUR
2021-01-23 12:34       ` Lars-Dominik Braun [this message]
2021-01-24 13:30         ` Tanguy LE CARROUR
2021-01-24 20:54         ` Ryan Prior
2021-01-25 11:47           ` Lars-Dominik Braun
2021-01-25 16:57             ` Ryan Prior
2021-02-05 10:40         ` Hartmut Goebel
2021-05-17  6:24         ` Lars-Dominik Braun
2021-06-06 16:44           ` Tanguy LE CARROUR
2021-06-06 19:44             ` Lars-Dominik Braun
2021-06-22  6:53               ` Removal of Python 2? Hartmut Goebel
2021-06-22 12:41                 ` Konrad Hinsen
2021-06-23 15:26                   ` Ludovic Courtès
2021-06-23 15:34                     ` zimoun
2021-06-23 18:32                     ` Konrad Hinsen
2021-06-22 18:02                 ` Ryan Prior
2021-06-25  6:37                   ` Konrad Hinsen
2021-06-22  7:00               ` Questions regarding Python packaging Hartmut Goebel
2021-06-28 11:59                 ` Lars-Dominik Braun
2021-06-28 20:37                   ` Hartmut Goebel
2021-06-29  7:20                     ` Lars-Dominik Braun
2021-07-06 12:16                       ` [bug#46848] " Lars-Dominik Braun
2021-07-07 15:01                       ` Hartmut Goebel
2021-01-26  7:21       ` Tanguy LE CARROUR
2021-01-27  3:43         ` Maxim Cournoyer
2021-01-06 15:37   ` Tanguy LE CARROUR

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://guix.gnu.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=YAwXwV1BNlzL+w47@noor.fritz.box \
    --to=lars@6xq.net \
    --cc=guix-devel@gnu.org \
    --cc=tanguy@bioneland.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).