summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Graves <ngraves@ngraves.fr>2025-10-29 15:11:55 +0100
committerSharlatan Hellseher <sharlatanus@gmail.com>2026-05-24 10:14:33 +0100
commit4f4ee461796491afd092f0baa80df96537296f63 (patch)
tree4f36fceb9679fd030909fd40ecdc8f1ea28d082f
parent30b3cbc90f27c4d84306f949bba24989779c0992 (diff)
build-system/pyproject: Ignore selected pytest inputs.
This commit includes squashed changes from https://codeberg.org/guix/guix/pulls/7220 and https://codeberg.org/guix/guix/pulls/7338. * 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. Change-Id: I13263b461e9962aad340347657b9c9685db63927 Signed-off-by: Sharlatan Hellseher <sharlatanus@gmail.com>
-rw-r--r--Makefile.am1
-rw-r--r--gnu/packages/aux-files/python/pytest_guix.py68
-rw-r--r--guix/build-system/pyproject.scm58
-rw-r--r--guix/build/pyproject-build-system.scm20
4 files changed, 135 insertions, 12 deletions
diff --git a/Makefile.am b/Makefile.am
index 16ab2d317ec..79575c7dfdb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -488,6 +488,7 @@ AUX_FILES = \
488 gnu/packages/aux-files/linux-libre/5.10-x86_64.conf \ 488 gnu/packages/aux-files/linux-libre/5.10-x86_64.conf \
489 gnu/packages/aux-files/ovmf/51-edk2-ovmf-2m-raw-x64-nosb.json \ 489 gnu/packages/aux-files/ovmf/51-edk2-ovmf-2m-raw-x64-nosb.json \
490 gnu/packages/aux-files/pack-audit.c \ 490 gnu/packages/aux-files/pack-audit.c \
491 gnu/packages/aux-files/python/pytest_guix.py \
491 gnu/packages/aux-files/python/sanity-check.py \ 492 gnu/packages/aux-files/python/sanity-check.py \
492 gnu/packages/aux-files/python/sitecustomize.py \ 493 gnu/packages/aux-files/python/sitecustomize.py \
493 gnu/packages/aux-files/renpy/renpy.in \ 494 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 00000000000..750b1e99e99
--- /dev/null
+++ b/gnu/packages/aux-files/python/pytest_guix.py
@@ -0,0 +1,68 @@
1# GNU Guix --- Functional package management for GNU
2# Copyright © 2025 Nicolas Graves <ngraves@ngraves.fr>
3#
4# This file is part of GNU Guix.
5#
6# GNU Guix is free software; you can redistribute it and/or modify it
7# under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 3 of the License, or (at
9# your option) any later version.
10#
11# GNU Guix is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
18
19import importlib.util
20
21
22def pytest_addoption(parser):
23 """Add stub options to be ignored by pytest.
24
25 More precisely, inject all options provided in .pytest_guix_options.json,
26 except options whose plugin is indeed installed.
27
28 For example, if the json file records --cov:
29 if the pytest_cov module is installed, its --cov will be used.
30 otherwise, --cov is ignored (read by this parser, but nothing is done
31 with it).
32
33 This allows to remove development packages, which are not required at build
34 time while at the same time avoiding the need to adjust test options in
35 pyproject.toml or other configuration files.
36 """
37 plugin_options = {
38 "cov": [
39 "--cov",
40 "--cov-reset",
41 "--cov-report",
42 "--cov-config",
43 "--no-cov-on-fail",
44 "--no-cov",
45 "--cov-fail-under",
46 "--cov-append",
47 "--cov-branch",
48 "--cov-context",
49 ],
50 "mypy": ["--mypy", "--mypy-config-file", "--mypy-ignore-missing-imports"],
51 "isort": ["--isort"],
52 "flake8": ["--flake8"],
53 "black": ["--black"],
54 "flakes": ["--flakes"],
55 "pep8": ["--pep8"],
56 "html": ["--html", "--self-contained-html", "--css"],
57 }
58
59 group = parser.getgroup(
60 "guix", "Options ignored by the Guix pyproject-build-system"
61 )
62
63 # Only add options for plugins that are not present.
64 for key, options in plugin_options.items():
65 if importlib.util.find_spec(f"pytest_{key}") is None:
66 # Plugin not found, add stub options
67 for option in options:
68 group.addoption(option, action="append", nargs="?")
diff --git a/guix/build-system/pyproject.scm b/guix/build-system/pyproject.scm
index d8939a7fde8..d833be10b47 100644
--- a/guix/build-system/pyproject.scm
+++ b/guix/build-system/pyproject.scm
@@ -23,15 +23,19 @@
23 #:use-module (guix store) 23 #:use-module (guix store)
24 #:use-module (guix utils) 24 #:use-module (guix utils)
25 #:use-module (guix gexp) 25 #:use-module (guix gexp)
26 #:use-module ((guix licenses) #:prefix license:)
26 #:use-module (guix monads) 27 #:use-module (guix monads)
27 #:use-module (guix packages) 28 #:use-module (guix packages)
28 #:use-module (guix search-paths) 29 #:use-module (guix search-paths)
29 #:use-module (guix build-system) 30 #:use-module (guix build-system)
30 #:use-module (guix build-system gnu) 31 #:use-module (guix build-system gnu)
31 #:use-module (guix build-system python) 32 #:use-module (guix build-system python)
33 #:use-module (guix build-system trivial)
32 #:use-module (srfi srfi-1) 34 #:use-module (srfi srfi-1)
35 #:use-module (ice-9 match)
33 #:export (%pyproject-build-system-modules 36 #:export (%pyproject-build-system-modules
34 default-python 37 default-python
38 default-pytest-guix-plugin
35 default-sanity-check.py 39 default-sanity-check.py
36 pyproject-build 40 pyproject-build
37 pyproject-build-system 41 pyproject-build-system
@@ -62,6 +66,37 @@
62 "Return the default guile-json package, resolved lazily." 66 "Return the default guile-json package, resolved lazily."
63 (@* (gnu packages guile) guile-json-4)) 67 (@* (gnu packages guile) guile-json-4))
64 68
69;; Maybe try to upstream it at some point, it's currently flavored for guix
70;; but the idea itself is more general.
71(define (default-pytest-guix-plugin python)
72 (let* ((effective (version-major+minor (package-version python)))
73 (site (string-append "lib/python" effective "/site-packages/")))
74 (package
75 (name "python-pytest-guix")
76 (version "0.0.1")
77 (source (local-file (search-auxiliary-file "python/pytest_guix.py")))
78 (build-system trivial-build-system)
79 (arguments
80 (list
81 #:modules '((guix build utils))
82 #:builder
83 #~(begin
84 (use-modules (guix build utils))
85 (let* ((site (string-append #$output "/" #$site))
86 (dist (string-append site "pytest_guix-" #$version
87 ".dist.info")))
88 (mkdir-p dist)
89 (copy-file #$source (string-append site "/pytest_guix.py"))
90 (call-with-output-file (string-append dist "/entry_points.txt")
91 (lambda (port)
92 (format port "[pytest11]~%guix=pytest_guix~%")))))))
93 (home-page "https://guix.gnu.org/")
94 (synopsis "Ignore selected pytest options")
95 (description
96 "This package provides the script to cleanly ignore pytest options at the
97build-system level.")
98 (license license:gpl3+))))
99
65;; TODO: On the next iteration of python-team, migrate the sanity-check to 100;; TODO: On the next iteration of python-team, migrate the sanity-check to
66;; importlib_metadata instead of setuptools. 101;; importlib_metadata instead of setuptools.
67(define (default-sanity-check.py) 102(define (default-sanity-check.py)
@@ -69,13 +104,21 @@
69 104
70(define* (lower name 105(define* (lower name
71 #:key source inputs native-inputs outputs system target 106 #:key source inputs native-inputs outputs system target
107 test-backend
72 (python (default-python)) 108 (python (default-python))
109 (python-pytest-guix (default-pytest-guix-plugin python))
73 (sanity-check.py (default-sanity-check.py)) 110 (sanity-check.py (default-sanity-check.py))
74 #:allow-other-keys 111 #:allow-other-keys
75 #:rest arguments) 112 #:rest arguments)
76 "Return a bag for NAME." 113 "Return a bag for NAME."
77 (define private-keywords 114 (define private-keywords
78 '(#:target #:python #:inputs #:native-inputs #:sanity-check.py)) 115 '(#:target #:python #:inputs #:native-inputs
116 #:python-pytest-guix #:sanity-check.py))
117 (define native-inputs-labels (map car native-inputs))
118 (define has-pytest?
119 (or (member "python-pytest-bootstrap" native-inputs-labels)
120 (member "python-pytest" native-inputs-labels)))
121
79 122
80 (and (not target) ;XXX: no cross-compilation 123 (and (not target) ;XXX: no cross-compilation
81 (bag 124 (bag
@@ -88,9 +131,16 @@
88 131
89 ;; Keep the standard inputs of 'gnu-build-system'. 132 ;; Keep the standard inputs of 'gnu-build-system'.
90 ,@(standard-packages))) 133 ,@(standard-packages)))
91 (build-inputs `(("python" ,python) 134 (build-inputs
92 ("sanity-check.py" ,sanity-check.py) 135 `(("python" ,python)
93 ,@native-inputs)) 136 ("sanity-check.py" ,sanity-check.py)
137 ,@(if (and has-pytest?
138 (match test-backend
139 ((or 'pytest-with-guix-plugin #f) #t)
140 (_ #f)))
141 `(("python-pytest-guix" ,python-pytest-guix))
142 `())
143 ,@native-inputs))
94 (outputs (append outputs '(wheel))) 144 (outputs (append outputs '(wheel)))
95 (build pyproject-build) 145 (build pyproject-build)
96 (arguments (strip-keyword-arguments private-keywords arguments))))) 146 (arguments (strip-keyword-arguments private-keywords arguments)))))
diff --git a/guix/build/pyproject-build-system.scm b/guix/build/pyproject-build-system.scm
index 21f356c67e9..5685ddc033f 100644
--- a/guix/build/pyproject-build-system.scm
+++ b/guix/build/pyproject-build-system.scm
@@ -314,7 +314,7 @@ without errors."
314 (with-directory-excursion "/tmp" 314 (with-directory-excursion "/tmp"
315 (invoke "python" sanity-check.py (site-packages inputs outputs))))) 315 (invoke "python" sanity-check.py (site-packages inputs outputs)))))
316 316
317(define* (check #:key tests? test-backend test-flags #:allow-other-keys) 317(define* (check #:key inputs tests? test-backend test-flags #:allow-other-keys)
318 "Run the test suite of a given Python package." 318 "Run the test suite of a given Python package."
319 (if tests? 319 (if tests?
320 ;; Unfortunately with PEP 517 there is no common method to specify test 320 ;; Unfortunately with PEP 517 there is no common method to specify test
@@ -330,20 +330,24 @@ without errors."
330 (tests-found (find-files "." "test.*\\.py$")) 330 (tests-found (find-files "." "test.*\\.py$"))
331 (use-test-backend 331 (use-test-backend
332 (or test-backend 332 (or test-backend
333 ;; Prefer pytest 333 ;; By order of preference.
334 (if pytest 'pytest #f) 334 (and (assoc-ref inputs "python-pytest-guix")
335 (if stestr 'stestr #f) 335 'pytest-with-guix-plugin)
336 (if nosetests 'nose #f) 336 (and pytest 'pytest)
337 (if nose2 'nose2 #f) 337 (and stestr 'stestr)
338 (and nosetests 'nose)
339 (and nose2 'nose2)
338 ;; Fall back to setup.py. The command is deprecated, but is 340 ;; Fall back to setup.py. The command is deprecated, but is
339 ;; a superset of unittest, so should work for most packages. 341 ;; a superset of unittest, so should work for most packages.
340 ;; Keep it until setuptools removes `setup.py test'. 342 ;; Keep it until setuptools removes `setup.py test'.
341 ;; See https://setuptools.pypa.io/en/latest/deprecated/\ 343 ;; See https://setuptools.pypa.io/en/latest/deprecated/\
342 ;; commands.html#test-build-package-and-run-a-unittest-suite 344 ;; commands.html#test-build-package-and-run-a-unittest-suite
343 (if have-setup-py 'setup.py #f) 345 (and have-setup-py 'setup.py)
344 (if tests-found 'unittest #f)))) 346 (and tests-found 'unittest))))
345 (format #t "Using ~a~%" use-test-backend) 347 (format #t "Using ~a~%" use-test-backend)
346 (match use-test-backend 348 (match use-test-backend
349 ('pytest-with-guix-plugin
350 (apply invoke pytest "-vv" "-p" "pytest_guix" test-flags))
347 ('pytest 351 ('pytest
348 (apply invoke pytest "-vv" test-flags)) 352 (apply invoke pytest "-vv" test-flags))
349 ('nose 353 ('nose