diff options
Diffstat (limited to 'testing/runner.py')
-rw-r--r-- | testing/runner.py | 159 |
1 files changed, 72 insertions, 87 deletions
diff --git a/testing/runner.py b/testing/runner.py index 83b7b08e6..b52ac4937 100644 --- a/testing/runner.py +++ b/testing/runner.py @@ -1,56 +1,14 @@ -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of the Qt for Python project. -## -## $QT_BEGIN_LICENSE:LGPL$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU Lesser General Public License Usage -## Alternatively, this file may be used under the terms of the GNU Lesser -## General Public License version 3 as published by the Free Software -## Foundation and appearing in the file LICENSE.LGPL3 included in the -## packaging of this file. Please review the following information to -## ensure the GNU Lesser General Public License version 3 requirements -## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 2.0 or (at your option) the GNU General -## Public license version 3 or any later version approved by the KDE Free -## Qt Foundation. The licenses are as published by the Free Software -## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-2.0.html and -## https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# - -from __future__ import print_function +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +import inspect import os -import sys import re import subprocess -import inspect - -from collections import namedtuple +import sys +from subprocess import TimeoutExpired from textwrap import dedent -from .buildlog import builds -from .helper import decorate, PY3, TimeoutExpired - # Get the dir path to the utils module try: this_file = __file__ @@ -58,10 +16,11 @@ except NameError: this_file = sys.argv[0] this_file = os.path.abspath(this_file) this_dir = os.path.dirname(this_file) -build_scripts_dir = os.path.abspath(os.path.join(this_dir, '../build_scripts')) +build_scripts_dir = os.path.abspath(os.path.join(this_dir, "..")) sys.path.append(build_scripts_dir) -from utils import detect_clang +from build_scripts.utils import detect_clang + class TestRunner(object): def __init__(self, log_entry, project, index): @@ -70,23 +29,48 @@ class TestRunner(object): self.test_dir = os.path.join(built_path, project) log_dir = log_entry.log_dir if index is not None: - self.logfile = os.path.join(log_dir, project + ".{}.log".format(index)) + self.logfile = os.path.join(log_dir, f"{project}.{index}.log") else: - self.logfile = os.path.join(log_dir, project + ".log") - os.environ['CTEST_OUTPUT_ON_FAILURE'] = '1' + self.logfile = os.path.join(log_dir, f"{project}.log") + os.environ["CTEST_OUTPUT_ON_FAILURE"] = "1" self._setup_clang() self._setup() + def get_python_version(self): + """ + Finding the exact Python version. + --------------------------------- + + This is done by asking the interpreter, because it cannot reliably + be found from any file name parsing as a triple. + + Note: We need to look into the CMakeCache.txt file to find out + what CMake has found as the Python interpreter to use. + This is *not* necessarily the same Python that runs this script, + otherwise we could use the version info directly. + """ + look_python = os.path.join(self.test_dir, "CMakeCache.txt") + look_for = "PYTHON_EXECUTABLE:FILEPATH=" + with open(look_python) as f: + for line in f: + if line.startswith(look_for): + python_exec = line.split("=")[-1].strip() + res = subprocess.run([python_exec, "-c", + "import sys;print(sys.version_info[:3])"], + capture_output=True) + return eval(res.stdout.decode("utf-8")) + return None + def _setup_clang(self): if sys.platform != "win32": return clang_dir = detect_clang() if clang_dir[0]: - clang_bin_dir = os.path.join(clang_dir[0], 'bin') - path = os.environ.get('PATH') - if not clang_bin_dir in path: - os.environ['PATH'] = clang_bin_dir + os.pathsep + path - print("Adding %s as detected by %s to PATH" % (clang_bin_dir, clang_dir[1])) + clang_bin_dir = os.path.join(clang_dir[0], "bin") + path = os.environ.get("PATH") + if clang_bin_dir not in path: + os.environ["PATH"] = clang_bin_dir + os.pathsep + path + print(f"Adding {clang_bin_dir} as detected by {clang_dir[1]} to PATH") def _find_ctest_in_file(self, file_name): """ @@ -103,14 +87,16 @@ class TestRunner(object): # We have probably forgotten to build the tests. # Give a nice error message with a shortened but exact path. rel_path = os.path.relpath(file_name) - msg = dedent("""\n - {line} - ** ctest is not in '{}'. + msg = dedent( + f"""\n + {'*' * 79} + ** ctest is not in '{rel_path}'. * Did you forget to build the tests with '--build-tests' in setup.py? - """).format(rel_path, line=79 * "*") + """ + ) raise RuntimeError(msg) # the ctest program is on the left to look_for - assert line, "Did not find {}".format(look_for) + assert line, f"Did not find {look_for}" ctest = re.search(r'(\S+|"([^"]+)")\s+' + look_for, line).groups() return ctest[1] or ctest[0] @@ -130,8 +116,9 @@ class TestRunner(object): path = os.path.join(self.test_dir, candidate) if os.path.exists(path): return self._find_ctest_in_file(path) - raise RuntimeError('Cannot find any of the build system files {}.'.format( - ', '.join(candidate_files))) + raise RuntimeError( + "Cannot find any of the build system files " f"{', '.join(candidate_files)}." + ) def _setup(self): self.ctestCommand = self._find_ctest() @@ -155,16 +142,20 @@ class TestRunner(object): # without a caret are interpreted as such which leads to weirdness. # Since we have all commands with explicit paths and don't use shell # commands, this should work fine. - print(dedent("""\ - running {cmd} - in {test_dir} - """).format(**self.__dict__)) - ctest_process = subprocess.Popen(self.cmd, - cwd=self.test_dir, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) + print( + dedent( + f"""\ + running {self.cmd} + in {self.test_dir} + """ + ) + ) + ctest_process = subprocess.Popen( + self.cmd, cwd=self.test_dir, stdout=subprocess.PIPE, stderr=subprocess.STDOUT + ) + def py_tee(input, output, label): - ''' + """ A simple (incomplete) tee command in Python This script simply logs everything from input to output @@ -179,7 +170,8 @@ class TestRunner(object): The special escape is for the case of an embedded file in the output. - ''' + """ + def xprint(*args, **kw): print(*args, file=output, **kw) @@ -199,26 +191,20 @@ class TestRunner(object): if line.startswith(text_z): labelled = True - tee_src = dedent("""\ - from __future__ import print_function - import sys - {} - py_tee(sys.stdin, sys.stdout, '{label}') - """).format(dedent(inspect.getsource(py_tee)), label=label) + tee_src = dedent(inspect.getsource(py_tee)) + tee_src = f"import sys\n{tee_src}\npy_tee(sys.stdin, sys.stdout, '{label}')" tee_cmd = (sys.executable, "-E", "-u", "-c", tee_src) - tee_process = subprocess.Popen(tee_cmd, - cwd=self.test_dir, - stdin=ctest_process.stdout) + tee_process = subprocess.Popen(tee_cmd, cwd=self.test_dir, stdin=ctest_process.stdout) try: comm = tee_process.communicate - output = (comm(timeout=timeout) if PY3 else comm())[0] + _ = comm(timeout=timeout)[0] except (TimeoutExpired, KeyboardInterrupt): print() print("aborted, partial result") ctest_process.kill() - outs, errs = ctest_process.communicate() + _ = ctest_process.communicate() # ctest lists to a temp file. Move it to the log - tmp_name = self.logfile + ".tmp" + tmp_name = f"{self.logfile}.tmp" if os.path.exists(tmp_name): if os.path.exists(self.logfile): os.unlink(self.logfile) @@ -240,4 +226,3 @@ class TestRunner(object): words = "^(" + "|".join(rerun) + ")$" cmd += ("--tests-regex", words) self._run(cmd, label, timeout) -# eof |