build-system: Add pyproject-build-system.
[jackhill/guix/guix.git] / gnu / packages / aux-files / python / sanity-check-next.py
1 # -*- coding: utf-8 -*-
2 # GNU Guix --- Functional package management for GNU
3 # Copyright © 2021, 2022 Lars-Dominik Braun <lars@6xq.net>
4 #
5 # This file is part of GNU Guix.
6 #
7 # GNU Guix is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or (at
10 # your option) any later version.
11 #
12 # GNU Guix is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
19
20 # This version adds a small change to accommodate missing python-setuptools.
21 # TODO: Merge with sanity-check.py in the next core-updates cycle.
22
23 from __future__ import print_function # Python 2 support.
24 import importlib
25 import sys
26 import traceback
27 try:
28 import pkg_resources
29 except ImportError:
30 print('Warning: Skipping, because python-setuptools are not available.')
31 sys.exit(0)
32
33 try:
34 from importlib.machinery import PathFinder
35 except ImportError:
36 PathFinder = None
37
38 ret = 0
39
40 # Only check site-packages installed by this package, but not dependencies
41 # (which pkg_resources.working_set would include). Path supplied via argv.
42 ws = pkg_resources.find_distributions(sys.argv[1])
43
44 for dist in ws:
45 print('validating', repr(dist.project_name), dist.location)
46 try:
47 print('...checking requirements: ', end='')
48 req = str(dist.as_requirement())
49 # dist.activate() is not enough to actually check requirements, we
50 # have to .require() it.
51 pkg_resources.require(req)
52 print('OK')
53 except Exception as e:
54 print('ERROR:', req, repr(e))
55 ret = 1
56 continue
57
58 # Try to load top level modules. This should not have any side-effects.
59 try:
60 metalines = dist.get_metadata_lines('top_level.txt')
61 except (KeyError, EnvironmentError):
62 # distutils (i.e. #:use-setuptools? #f) will not install any metadata.
63 # This file is also missing for packages built using a PEP 517 builder
64 # such as poetry.
65 print('WARNING: cannot determine top-level modules')
66 continue
67 for name in metalines:
68 # Only available on Python 3.
69 if PathFinder and PathFinder.find_spec(name) is None:
70 # Ignore unavailable modules, often C modules, which were not
71 # installed at the top-level. Cannot use ModuleNotFoundError,
72 # because it is raised by failed imports too.
73 continue
74 try:
75 print('...trying to load module', name, end=': ')
76 importlib.import_module(name)
77 print('OK')
78 except Exception:
79 print('ERROR:')
80 traceback.print_exc(file=sys.stdout)
81 ret = 1
82
83 # Try to load entry points of console scripts too, making sure they
84 # work. They should be removed if they don't. Other groups may not be
85 # safe, as they can depend on optional packages.
86 for group, v in dist.get_entry_map().items():
87 if group not in {'console_scripts', 'gui_scripts'}:
88 continue
89 for name, ep in v.items():
90 try:
91 print('...trying to load endpoint', group, name, end=': ')
92 ep.load()
93 print('OK')
94 except Exception:
95 print('ERROR:')
96 traceback.print_exc(file=sys.stdout)
97 ret = 1
98
99 sys.exit(ret)