guix_mirror_bot pushed a commit to branch python-team
in repository guix.
commit ddf5dff92e9f45770cfd9e354c88f43b0c271d14
Author: Nicolas Graves <[email protected]>
AuthorDate: Wed Oct 29 15:11:55 2025 +0100
build-system/pyproject: Ignore selected pytest inputs.
* gnu/packages/aux-files/python/pytest_guix.py: New file.
* Makefile.am: Record it.
* guix/build/pyproject-build-system.scm (check): Preload pytest_guix
plugin when available.
* guix/build-system/pyproject.scm (default-pytest-guix-plugin): New
package, generated from pytest_guix.py.
(lower): Add python-pytest-guix argument, and inject it if
python-pytest is in the native-inputs.
Signed-off-by: Sharlatan Hellseher <[email protected]>
---
Makefile.am | 1 +
gnu/packages/aux-files/python/pytest_guix.py | 68 ++++++++++++++++++++++++++++
guix/build-system/pyproject.scm | 57 +++++++++++++++++++++--
guix/build/pyproject-build-system.scm | 20 ++++----
4 files changed, 134 insertions(+), 12 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 546e3ed758..016b95401c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -483,6 +483,7 @@ AUX_FILES = \
gnu/packages/aux-files/linux-libre/5.10-x86_64.conf \
gnu/packages/aux-files/ovmf/51-edk2-ovmf-2m-raw-x64-nosb.json \
gnu/packages/aux-files/pack-audit.c \
+ gnu/packages/aux-files/python/pytest_guix.py \
gnu/packages/aux-files/python/sanity-check.py \
gnu/packages/aux-files/python/sitecustomize.py \
gnu/packages/aux-files/renpy/renpy.in \
diff --git a/gnu/packages/aux-files/python/pytest_guix.py
b/gnu/packages/aux-files/python/pytest_guix.py
new file mode 100644
index 0000000000..750b1e99e9
--- /dev/null
+++ b/gnu/packages/aux-files/python/pytest_guix.py
@@ -0,0 +1,68 @@
+# GNU Guix --- Functional package management for GNU
+# Copyright © 2025 Nicolas Graves <[email protected]>
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+import importlib.util
+
+
+def pytest_addoption(parser):
+ """Add stub options to be ignored by pytest.
+
+ More precisely, inject all options provided in .pytest_guix_options.json,
+ except options whose plugin is indeed installed.
+
+ For example, if the json file records --cov:
+ if the pytest_cov module is installed, its --cov will be used.
+ otherwise, --cov is ignored (read by this parser, but nothing is done
+ with it).
+
+ This allows to remove development packages, which are not required at build
+ time while at the same time avoiding the need to adjust test options in
+ pyproject.toml or other configuration files.
+ """
+ plugin_options = {
+ "cov": [
+ "--cov",
+ "--cov-reset",
+ "--cov-report",
+ "--cov-config",
+ "--no-cov-on-fail",
+ "--no-cov",
+ "--cov-fail-under",
+ "--cov-append",
+ "--cov-branch",
+ "--cov-context",
+ ],
+ "mypy": ["--mypy", "--mypy-config-file",
"--mypy-ignore-missing-imports"],
+ "isort": ["--isort"],
+ "flake8": ["--flake8"],
+ "black": ["--black"],
+ "flakes": ["--flakes"],
+ "pep8": ["--pep8"],
+ "html": ["--html", "--self-contained-html", "--css"],
+ }
+
+ group = parser.getgroup(
+ "guix", "Options ignored by the Guix pyproject-build-system"
+ )
+
+ # Only add options for plugins that are not present.
+ for key, options in plugin_options.items():
+ if importlib.util.find_spec(f"pytest_{key}") is None:
+ # Plugin not found, add stub options
+ for option in options:
+ group.addoption(option, action="append", nargs="?")
diff --git a/guix/build-system/pyproject.scm b/guix/build-system/pyproject.scm
index d8939a7fde..a74e5480bc 100644
--- a/guix/build-system/pyproject.scm
+++ b/guix/build-system/pyproject.scm
@@ -23,15 +23,19 @@
#:use-module (guix store)
#:use-module (guix utils)
#:use-module (guix gexp)
+ #:use-module ((guix licenses) #:prefix license:)
#:use-module (guix monads)
#:use-module (guix packages)
#:use-module (guix search-paths)
#:use-module (guix build-system)
#:use-module (guix build-system gnu)
#:use-module (guix build-system python)
+ #:use-module (guix build-system trivial)
#:use-module (srfi srfi-1)
+ #:use-module (ice-9 match)
#:export (%pyproject-build-system-modules
default-python
+ default-pytest-guix-plugin
default-sanity-check.py
pyproject-build
pyproject-build-system
@@ -62,6 +66,36 @@
"Return the default guile-json package, resolved lazily."
(@* (gnu packages guile) guile-json-4))
+;; Maybe try to upstream it at some point, it's currently flavored for guix
+;; but the idea itself is more general.
+(define (default-pytest-guix-plugin python)
+ (let* ((effective (version-major+minor (package-version python)))
+ (site (string-append "lib/python" effective "/site-packages/")))
+ (package
+ (name "python-pytest-guix")
+ (version "0.0.1")
+ (source (local-file (search-auxiliary-file "python/pytest_guix.py")))
+ (build-system trivial-build-system)
+ (arguments
+ (list
+ #:modules '((guix build utils))
+ #:builder
+ #~(begin
+ (use-modules (guix build utils))
+ (let* ((site (string-append #$output "/" #$site))
+ (dist (string-append site "-" #$version ".dist.info")))
+ (mkdir-p dist)
+ (install-file #$source site)
+ (call-with-output-file (string-append dist "/entry_points.txt")
+ (lambda (port)
+ (format port "[pytest11]~%guix=pytest_guix~%")))))))
+ (home-page "https://guix.gnu.org/")
+ (synopsis "Ignore selected pytest options")
+ (description
+ "This package provides the script to cleanly ignore pytest options at
the
+build-system level.")
+ (license license:gpl3+))))
+
;; TODO: On the next iteration of python-team, migrate the sanity-check to
;; importlib_metadata instead of setuptools.
(define (default-sanity-check.py)
@@ -69,13 +103,21 @@
(define* (lower name
#:key source inputs native-inputs outputs system target
+ test-backend
(python (default-python))
+ (python-pytest-guix (default-pytest-guix-plugin python))
(sanity-check.py (default-sanity-check.py))
#:allow-other-keys
#:rest arguments)
"Return a bag for NAME."
(define private-keywords
- '(#:target #:python #:inputs #:native-inputs #:sanity-check.py))
+ '(#:target #:python #:inputs #:native-inputs
+ #:python-pytest-guix #:sanity-check.py))
+ (define native-inputs-labels (map car native-inputs))
+ (define has-pytest?
+ (or (member "python-pytest-bootstrap" native-inputs-labels)
+ (member "python-pytest" native-inputs-labels)))
+
(and (not target) ;XXX: no cross-compilation
(bag
@@ -88,9 +130,16 @@
;; Keep the standard inputs of 'gnu-build-system'.
,@(standard-packages)))
- (build-inputs `(("python" ,python)
- ("sanity-check.py" ,sanity-check.py)
- ,@native-inputs))
+ (build-inputs
+ `(("python" ,python)
+ ("sanity-check.py" ,sanity-check.py)
+ ,@(if (and has-pytest?
+ (match test-backend
+ ((or 'pytest-with-guix-plugin #f) #t)
+ (_ #f)))
+ `(("python-pytest-guix" ,python-pytest-guix))
+ `())
+ ,@native-inputs))
(outputs (append outputs '(wheel)))
(build pyproject-build)
(arguments (strip-keyword-arguments private-keywords arguments)))))
diff --git a/guix/build/pyproject-build-system.scm
b/guix/build/pyproject-build-system.scm
index 21f356c67e..5685ddc033 100644
--- a/guix/build/pyproject-build-system.scm
+++ b/guix/build/pyproject-build-system.scm
@@ -314,7 +314,7 @@ without errors."
(with-directory-excursion "/tmp"
(invoke "python" sanity-check.py (site-packages inputs outputs)))))
-(define* (check #:key tests? test-backend test-flags #:allow-other-keys)
+(define* (check #:key inputs tests? test-backend test-flags #:allow-other-keys)
"Run the test suite of a given Python package."
(if tests?
;; Unfortunately with PEP 517 there is no common method to specify test
@@ -330,20 +330,24 @@ without errors."
(tests-found (find-files "." "test.*\\.py$"))
(use-test-backend
(or test-backend
- ;; Prefer pytest
- (if pytest 'pytest #f)
- (if stestr 'stestr #f)
- (if nosetests 'nose #f)
- (if nose2 'nose2 #f)
+ ;; By order of preference.
+ (and (assoc-ref inputs "python-pytest-guix")
+ 'pytest-with-guix-plugin)
+ (and pytest 'pytest)
+ (and stestr 'stestr)
+ (and nosetests 'nose)
+ (and nose2 'nose2)
;; Fall back to setup.py. The command is deprecated, but is
;; a superset of unittest, so should work for most packages.
;; Keep it until setuptools removes `setup.py test'.
;; See https://setuptools.pypa.io/en/latest/deprecated/\
;; commands.html#test-build-package-and-run-a-unittest-suite
- (if have-setup-py 'setup.py #f)
- (if tests-found 'unittest #f))))
+ (and have-setup-py 'setup.py)
+ (and tests-found 'unittest))))
(format #t "Using ~a~%" use-test-backend)
(match use-test-backend
+ ('pytest-with-guix-plugin
+ (apply invoke pytest "-vv" "-p" "pytest_guix" test-flags))
('pytest
(apply invoke pytest "-vv" test-flags))
('nose