LAL 7.6.1.1-a06bc80
test_python_scripts.py
Go to the documentation of this file.
1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2019-2020 Cardiff University
4#
5# This program is free software; you can redistribute it and/or modify it
6# under the terms of the GNU General Public License as published by the
7# Free Software Foundation; either version 2 of the License, or (at your
8# option) any later version.
9#
10# This program is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13# Public License for more details.
14#
15# You should have received a copy of the GNU General Public License along
16# with this program; if not, write to the Free Software Foundation, Inc.,
17# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
19"""Test that the `--help` option works for all scripts in this package
20"""
21
22import os
23import sys
24import warnings
25from pathlib import Path
26from subprocess import check_call
27
28import pytest
29
30# name of this package
31PACKAGE = "lal"
32
33# are we currently in the TEST phase of a conda build?
34CONDA_BUILD_TEST = os.getenv("CONDA_BUILD_STATE") == "TEST"
35
36# default run arguments
37DEFAULT_PYTEST_ARGUMENTS = [
38 "-v",
39 "-rs",
40 "--junit-xml=junit-scripts.xml",
41]
42
43# paths
44HERE = Path(__file__).parent.absolute()
45BUILDDIR = (HERE / Path(".")).resolve()
46SRCDIR = (HERE / Path(".")).resolve()
47TOPBUILDDIR = (HERE / Path("../..")).resolve()
48if PACKAGE == "lalapps": # lalapps is different
49 BINDIR = BUILDDIR
50else:
51 BINDIR = TOPBUILDDIR / "bin"
52
53# path to exclusion file
54EXCLUDEFILE = SRCDIR / "exclude-scripts.txt"
55
56
57# -- utilities ----------------------------------
58
59def read_exclude_file(source):
60 """Read all excluded file paths from the given source file
61 """
62 excludes = set()
63 try:
64 with open(str(source), "r") as fobj:
65 for line in fobj:
66 if isinstance(line, bytes):
67 line = line.decode("utf-8")
68 content = line.strip().split("#", 1)[0].strip()
69 if content:
70 excludes.add(content)
71 except FileNotFoundError as exc:
72 warnings.warn(str(exc))
73 return excludes
74
75
76def parse_pybin_scripts(path, var="pybin_scripts"):
77 """Yield script names from the relevant Makefile list variable.
78 """
79 with path.open("r") as makefile:
80 inscriptslist = False
81 for line in makefile:
82 line = line.rstrip()
83 # starting the pybin_scripts list
84 if line.startswith(var):
85 inscriptslist = True
86 # if given a value immediately, use it
87 value = line.split("=", 1)[1].rstrip(" \\")
88 if value:
89 yield value
90 # ending the pybin_scripts list (or not in it)
91 elif not line or line.endswith("$(END_OF_LIST)"):
92 inscriptslist = False
93 # otherwise we must be inside the list definition,
94 # so yield its contents
95 elif inscriptslist:
96 yield line.rstrip("\\").strip()
97
98
99def find_scripts(path):
100 """Yields the script names of python files in the given directory.
101
102 This is just the file name with the trailing ``.py`` extension removed.
103 """
104 for pyf in path.glob("*.py"):
105 # build system creates a shell wrapper around each .py script
106 # so we want to actually execute that, this also allows us to
107 # only pick up scripts that are to be installed
108 shf = Path(str(pyf)[:-3])
109 if shf.is_file():
110 yield str(shf.name)
111
112
113# -- tests --------------------------------------
114
115EXCLUDE = read_exclude_file(SRCDIR / "exclude-scripts.txt")
116try:
117 SCRIPTS = sorted(parse_pybin_scripts(BINDIR / "Makefile"))
118except (FileNotFoundError, ValueError, TypeError):
119 # failed to find/parse the makefile, use the brute force method
120 SCRIPTS = sorted(find_scripts(BINDIR))
121
122
123# only parametrize if we have something to loop over,
124# this allows pytest to exit with the 'no tests collected' code
125# which we can then pass up the stack to automake
126if SCRIPTS:
127 @pytest.mark.parametrize('script', SCRIPTS)
128 def test_help(script):
129 """Test that `<script> --help` can be executed for the named script.
130 """
131 if script in EXCLUDE: # skip
132 pytest.skip("excluded {}".format(str(script)))
133 if CONDA_BUILD_TEST: # script should be on the path
134 check_call([script, "--help"], shell=False)
135 else: # use local path
136 startdir = os.getcwd()
137 os.chdir(str(BINDIR))
138 try:
139 check_call("./{} --help".format(script), shell=True)
140 finally:
141 os.chdir(startdir)
142
143
144# -- command-line -------------------------------
145
146# run from command line
147if __name__ == "__main__":
148 args = sys.argv[1:] or DEFAULT_PYTEST_ARGUMENTS
149 code = pytest.main(args=[__file__] + args)
150
151 # handle exit code
152 if code == 5: # (pytest.ExitCode.NO_TESTS_COLLECTED)
153 sys.exit(77) # for automake check
154 sys.exit(code)
def test_help(script)
Test that <script> --help can be executed for the named script.
def parse_pybin_scripts(path, var="pybin_scripts")
Yield script names from the relevant Makefile list variable.
def find_scripts(path)
Yields the script names of python files in the given directory.
def read_exclude_file(source)
Read all excluded file paths from the given source file.