>From 919fd78b1aff6c277baca396ef962a5dcd4e23ae Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Sun, 3 Jan 2021 10:30:29 +0100 Subject: [PATCH] [WIP] build-system/python: Validate installed package * guix/build/python-build-system.scm (validate-loadable): New phase. (%standard-phases): Use it. --- guix/build/python-build-system.scm | 51 ++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/guix/build/python-build-system.scm b/guix/build/python-build-system.scm index 09bd8465c8..edb772a7a4 100644 --- a/guix/build/python-build-system.scm +++ b/guix/build/python-build-system.scm @@ -148,6 +148,56 @@ (format #t "test suite not run~%")) #t) +(define* (validate-loadable #:key tests? inputs outputs #:allow-other-keys) + "Ensure packages depending on this package via setuptools work properly, +their advertised endpoints work and their top level modules are importable +without errors." + (let ((script (string-join +'( +;; Python 2 support. +"from __future__ import print_function" +"import pkg_resources, sys, importlib" +;; Only check site-packages installed by this package, but not dependencies +;; (which pkg_resources.working_set would include). Path supplied via argv. +"ws = pkg_resources.find_distributions (sys.argv[1])" +"for dist in ws:" +" print ('validating', repr (dist.project_name), dist.location)" +" try:" +" req = str (dist.as_requirement ())" +;; dist.activate() is not enough to actually check requirements, we have to +;; .require() it. +" pkg_resources.require (req)" +" except Exception as e:" +" print (req, e)" +" sys.exit (1)" +;; Try to load entry points of console scripts too, making sure they work. They +;; should be removed if they don’t. Other groups may not be safe, as they can +;; depend on optional packages. +" for group, v in dist.get_entry_map ().items ():" +" if group not in {'console_scripts', }:" +" continue" +" for name, ep in v.items ():" +" print ('...trying to load endpoint', group, name)" +" ep.load ()" +;; And finally try to load top level modules. This should not have any +;; side-effects. +" for name in dist.get_metadata_lines ('top_level.txt'):" +" print ('...trying to load module', name)" +" try:" +" importlib.import_module (name)" +;; Ignore non-existent modules, we only want to know if the existing ones work. +" except ModuleNotFoundError:" +" print ('......WARNING: module', name, 'not found, continuing')" +" continue") +"\n"))) + (add-installed-pythonpath inputs outputs) + ;; Make sure the working directory is empty (i.e. no Python modules in it) + (with-directory-excursion "/tmp" + ;; XXX: Cloak command run. Long and unreadable if it fails, provide an + ;; explanation instead. + (invoke "python" "-c" script (site-packages inputs outputs)))) + #t) + (define (python-version python) (let* ((version (last (string-split python #\-))) (components (string-split version #\.)) @@ -267,6 +317,7 @@ installed with setuptools." (replace 'install install) (add-after 'install 'check check) (add-after 'install 'wrap wrap) + (add-after 'check 'validate-loadable validate-loadable) (add-before 'strip 'rename-pth-file rename-pth-file))) (define* (python-build #:key inputs (phases %standard-phases) -- 2.26.2