Message ID | 20240425160010.6243-2-ngraves@ngraves.fr |
---|---|
State | New |
Headers | show |
Series | Python: Ignore unwanted development inputs. | expand |
Hi, pretty smart idea to use a pytest plugin :) > +;; Pytest plugin to filter out arguments to ignore. > +(define pytest-default-ignore-alist From the comment it’s not entirely clear to me what this list does. It’s a map from pytest plugin name to it’s pytest command line options, right? > +;; Allow guix to ignore these options when underlying pytest package is not > +;; an input. These flags are not necessary to properly run tests. > +(define (pytest-ignore-options-plugin flags) > + "This function converts an list of flags in a string that can > + be instantiated as a python pytest plugin." … > +(define (call-with-guix-pytest-plugin inputs thunk) Same here. As far as I understand you want to emulate command line options provided by pytest plugins, so pytest won’t fail if the plugin is not present. And we only do that if the plugin is not an input to avoid clashing command line options, right? + for option in options: + group.addoption(option, action='append', nargs='*')" Not sure nargs='*' is a good idea, since it might consume positional arguments intended for pytest. '?' would be a more conservative option, especially since we cannot override this easily per-package. > + (let* ((former-path (getenv "PYTHONPATH")) … > + (dynamic-wind > + (lambda () > + (setenv "PYTHONPATH" … > + (lambda () > + (setenv "PYTHONPATH" former-path) Isn’t it GUIX_PYTHONPATH? Lars
On 2024-04-26 10:47, Lars-Dominik Braun wrote: > Hi, > > pretty smart idea to use a pytest plugin :) > >> +;; Pytest plugin to filter out arguments to ignore. >> +(define pytest-default-ignore-alist > > From the comment it’s not entirely clear to me what this list > does. It’s a map from pytest plugin name to it’s pytest command line > options, right? Right, I'll update the command. > >> +;; Allow guix to ignore these options when underlying pytest package is not >> +;; an input. These flags are not necessary to properly run tests. >> +(define (pytest-ignore-options-plugin flags) >> + "This function converts an list of flags in a string that can >> + be instantiated as a python pytest plugin." > … >> +(define (call-with-guix-pytest-plugin inputs thunk) > > Same here. As far as I understand you want to emulate command line > options provided by pytest plugins, so pytest won’t fail if the plugin > is not present. And we only do that if the plugin is not an input to > avoid clashing command line options, right? Will do. > > + for option in options: > + group.addoption(option, action='append', nargs='*')" > > Not sure nargs='*' is a good idea, since it might consume positional > arguments intended for pytest. '?' would be a more conservative option, > especially since we cannot override this easily per-package. It works. I'll try with '?' then! > >> + (let* ((former-path (getenv "PYTHONPATH")) > … >> + (dynamic-wind >> + (lambda () >> + (setenv "PYTHONPATH" > … >> + (lambda () >> + (setenv "PYTHONPATH" former-path) > > Isn’t it GUIX_PYTHONPATH? > I know it works this way. Could be GUIX_PYTHONPATH too, I'm not sure I properly get the difference. Can test with GUIX_PYTHONPATH too, but in any case it's just for the tests, so it should be cleared out too. Should I? > Lars >
On 2024-04-26 12:14, Nicolas Graves wrote: > On 2024-04-26 10:47, Lars-Dominik Braun wrote: > >> Hi, >> >> pretty smart idea to use a pytest plugin :) >> >>> +;; Pytest plugin to filter out arguments to ignore. >>> +(define pytest-default-ignore-alist >> >> From the comment it’s not entirely clear to me what this list >> does. It’s a map from pytest plugin name to it’s pytest command line >> options, right? > > Right, I'll update the command. > >> >>> +;; Allow guix to ignore these options when underlying pytest package is not >>> +;; an input. These flags are not necessary to properly run tests. >>> +(define (pytest-ignore-options-plugin flags) >>> + "This function converts an list of flags in a string that can >>> + be instantiated as a python pytest plugin." >> … >>> +(define (call-with-guix-pytest-plugin inputs thunk) >> >> Same here. As far as I understand you want to emulate command line >> options provided by pytest plugins, so pytest won’t fail if the plugin >> is not present. And we only do that if the plugin is not an input to >> avoid clashing command line options, right? > > Will do. >> >> + for option in options: >> + group.addoption(option, action='append', nargs='*')" >> >> Not sure nargs='*' is a good idea, since it might consume positional >> arguments intended for pytest. '?' would be a more conservative option, >> especially since we cannot override this easily per-package. > > It works. I'll try with '?' then! > >> >>> + (let* ((former-path (getenv "PYTHONPATH")) >> … >>> + (dynamic-wind >>> + (lambda () >>> + (setenv "PYTHONPATH" >> … >>> + (lambda () >>> + (setenv "PYTHONPATH" former-path) >> >> Isn’t it GUIX_PYTHONPATH? >> > > I know it works this way. Could be GUIX_PYTHONPATH too, I'm not sure I > properly get the difference. Can test with GUIX_PYTHONPATH too, but in > any case it's just for the tests, so it should be cleared out > too. Should I? Actually, it doesn't seem to work with a replacement from PYTHONPATH to GUIX_PYTHONPATH, so I would rather keep it this way. > >> Lars >>
diff --git a/guix/build/pyproject-build-system.scm b/guix/build/pyproject-build-system.scm index 947d240114..3ca3c76c1c 100644 --- a/guix/build/pyproject-build-system.scm +++ b/guix/build/pyproject-build-system.scm @@ -1,6 +1,7 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2021 Lars-Dominik Braun <lars@6xq.net> ;;; Copyright © 2022 Marius Bakke <marius@gnu.org> +;;; Copyright © 2024 Nicolas Graves <ngraves@ngraves.fr> ;;; ;;; This file is part of GNU Guix. ;;; @@ -142,7 +143,86 @@ (define* (build #:key outputs build-backend backend-path configure-flags #:allow wheel-dir config-settings))) -(define* (check #:key tests? test-backend test-flags #:allow-other-keys) +;; Pytest plugin to filter out arguments to ignore. +(define pytest-default-ignore-alist + '(("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")))) + +;; Allow guix to ignore these options when underlying pytest package is not +;; an input. These flags are not necessary to properly run tests. +(define (pytest-ignore-options-plugin flags) + "This function converts an list of flags in a string that can + be instantiated as a python pytest plugin." + (format #f "\ +import pytest + +def pytest_addoption(parser): + group = parser.getgroup('guix','Guix ignored options') + options = [~{~s, ~}] + for option in options: + group.addoption(option, action='append', nargs='*')" + flags)) + +(define (call-with-guix-pytest-plugin inputs thunk) + (let* ((former-path (getenv "PYTHONPATH")) + (input-names + (filter (match-lambda + (((name . _) ...) + (if (string-prefix? "python-pytest-" name) + name + #f)) + ( _ #f)) + inputs)) + (filtered-flags + (filter identity + (append-map + (match-lambda + ((group . flags) + (if (member (string-append "python-pytest-" group) + input-names) + (list #f) + flags)) + (_ (list #f))) + pytest-default-ignore-alist)))) + (dynamic-wind + (lambda () + (setenv "PYTHONPATH" + (string-append + (if former-path + (string-append former-path ":") + "") + ".guix-pytest")) + (setenv "PYTEST_PLUGINS" + (string-append + (if (getenv "PYTEST_PLUGINS") + (string-append former-path ",") + "") + "pytest_guix_plugin")) + (mkdir-p ".guix-pytest") + (with-output-to-file ".guix-pytest/__init__.py" + (lambda _ (display ""))) + (with-output-to-file ".guix-pytest/pytest_guix_plugin.py" + (lambda _ + (display (pytest-ignore-options-plugin filtered-flags))))) + thunk + (lambda () + (setenv "PYTHONPATH" former-path) + (unsetenv "PYTEST_PLUGINS") + (when (file-exists? ".guix-pytest") + (delete-file-recursively ".guix-pytest")))))) + +(define-syntax-rule (with-guix-pytest-plugin inputs exp ...) + "Evaluate EXP in a context where the Guix pytest plugin is added." + (call-with-guix-pytest-plugin inputs (lambda () exp ...))) + +(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 @@ -165,7 +245,8 @@ (define* (check #:key tests? test-backend test-flags #:allow-other-keys) (format #t "Using ~a~%" use-test-backend) (match use-test-backend ('pytest - (apply invoke pytest "-vv" test-flags)) + (with-guix-pytest-plugin inputs + (apply invoke pytest "-vv" test-flags))) ('nose (apply invoke nosetests "-v" test-flags)) ('nose2 @@ -386,3 +467,6 @@ (define* (pyproject-build #:key inputs (phases %standard-phases) (apply python:python-build #:inputs inputs #:phases phases args)) ;;; pyproject-build-system.scm ends here +;;; Local Variables: +;;; eval: (put 'with-guix-pytest-plugin 'scheme-indent-function 1) +;;; End: