aboutsummaryrefslogtreecommitdiffstats
path: root/testing/wheel_tester.py
diff options
context:
space:
mode:
Diffstat (limited to 'testing/wheel_tester.py')
-rw-r--r--testing/wheel_tester.py295
1 files changed, 295 insertions, 0 deletions
diff --git a/testing/wheel_tester.py b/testing/wheel_tester.py
new file mode 100644
index 000000000..60fd7a38a
--- /dev/null
+++ b/testing/wheel_tester.py
@@ -0,0 +1,295 @@
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qt for Python.
+##
+## $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$
+##
+#############################################################################
+
+"""
+This script is used by Coin (coin_test_instructions.py specifically) to
+test installation of generated wheels, and test building of the
+"buildable" examples samplebinding and scriptableapplication.
+
+It can also be invoked regularly from the command line via
+python testing/wheel_tester.py --qmake=some-value --cmake=some-value
+
+The qmake and cmake arguments can also be omitted, and they will be
+looked up in your PATH.
+
+Make sure that some generated wheels already exist in the dist/
+directory (e.g. setup.py bdist_wheel was already executed).
+"""
+
+import os, sys
+
+try:
+ this_file = __file__
+except NameError:
+ this_file = sys.argv[0]
+this_file = os.path.abspath(this_file)
+this_dir = os.path.dirname(this_file)
+setup_script_dir = os.path.abspath(os.path.join(this_dir, '..'))
+sys.path.append(setup_script_dir)
+
+from build_scripts.options import OPTION_QMAKE
+from build_scripts.options import OPTION_CMAKE
+
+from build_scripts.utils import find_files_using_glob
+from build_scripts.utils import find_glob_in_path
+from build_scripts.utils import run_process
+from build_scripts.utils import rmtree
+import distutils.log as log
+
+log.set_verbosity(1)
+
+
+def find_executable_qmake():
+ return find_executable('qmake', OPTION_QMAKE)
+
+
+def find_executable_cmake():
+ return find_executable('cmake', OPTION_CMAKE)
+
+
+def find_executable(executable, command_line_value):
+ value = command_line_value
+ option_str = '--{}'.format(executable)
+
+ if value:
+ log.info("{} option given: {}".format(option_str, value))
+ if not os.path.exists(value):
+ raise RuntimeError("No executable exists at: {}".format(value))
+ else:
+ log.info("No {} option given, trying to find {} in PATH.".format(option_str, executable))
+ paths = find_glob_in_path(executable)
+ log.info("{} executables found in PATH: {}".format(executable, paths))
+ if not paths:
+ raise RuntimeError(
+ "No {} option was specified and no {} was found "
+ "in PATH.".format(option_str, executable))
+ else:
+ value = paths[0]
+ log.info("Using {} found in PATH: {}".format(executable, value))
+ log.info("")
+ return value
+
+
+QMAKE_PATH = find_executable_qmake()
+CMAKE_PATH = find_executable_cmake()
+
+
+def get_wheels_dir():
+ return os.path.join(setup_script_dir, "dist")
+
+
+def get_examples_dir():
+ return os.path.join(setup_script_dir, "examples")
+
+
+def package_prefix_names():
+ return ["shiboken2", "shiboken2_generator", "PySide2"]
+
+
+def clean_egg_info():
+ # After a successful bdist_wheel build, some .egg-info directories
+ # are left over, which confuse pip when invoking it via
+ # python -m pip, making pip think that the packages are already
+ # installed in the root source directory.
+ # Clean up the .egg-info directories to fix this, it should be
+ # safe to do so.
+ paths = find_files_using_glob(setup_script_dir, "*.egg-info")
+ for p in paths:
+ log.info("Removing {}".format(p))
+ rmtree(p)
+
+
+def install_wheel(wheel_path):
+ log.info("Installing wheel: {}".format(wheel_path))
+ exit_code = run_process([sys.executable, "-m", "pip", "install", wheel_path])
+ log.info("")
+ if exit_code:
+ raise RuntimeError("Error while installing wheel {}".format(wheel_path))
+
+
+def try_install_wheels(wheels_dir, py_version):
+ clean_egg_info()
+ all_wheels_pattern = "*.whl"
+ all_wheels = find_files_using_glob(wheels_dir, all_wheels_pattern)
+
+ if len(all_wheels) > 1:
+ log.info("Found the following wheels in {}: ".format(wheels_dir))
+ for wheel in all_wheels:
+ log.info(wheel)
+ else:
+ log.info("No wheels found in {}".format(wheels_dir))
+ log.info("")
+
+ for p in package_prefix_names():
+ pattern = "{}-*cp{}*.whl".format(p, py_version)
+ files = find_files_using_glob(wheels_dir, pattern)
+ if files and len(files) == 1:
+ wheel_path = files[0]
+ install_wheel(wheel_path)
+ elif len(files) > 1:
+ raise RuntimeError("More than one wheel found for specific package and version.")
+ else:
+ raise RuntimeError("No wheels compatible with Python {} found "
+ "for testing.".format(py_version))
+
+
+def is_unix():
+ if sys.platform.startswith("linux") or sys.platform == "darwin":
+ return True
+ return False
+
+
+def generate_build_cmake():
+ args = [CMAKE_PATH]
+ if is_unix():
+ args.extend(["-G", "Unix Makefiles"])
+ else:
+ args.extend(["-G", "NMake Makefiles"])
+ args.append("-DCMAKE_BUILD_TYPE=Release")
+ args.append("-Dpython_interpreter={}".format(sys.executable))
+
+ # Specify prefix path so find_package(Qt5) works.
+ qmake_dir = os.path.abspath(os.path.join(os.path.dirname(QMAKE_PATH), ".."))
+ args.append("-DCMAKE_PREFIX_PATH={}".format(qmake_dir))
+
+ args.append("..")
+
+ exit_code = run_process(args)
+ if exit_code:
+ raise RuntimeError("Failure while running cmake.")
+ log.info("")
+
+
+def generate_build_qmake():
+ exit_code = run_process([QMAKE_PATH, "..", "python_interpreter={}".format(sys.executable)])
+ if exit_code:
+ raise RuntimeError("Failure while running qmake.")
+ log.info("")
+
+
+def run_make():
+ args = []
+ if is_unix():
+ executable = "make"
+ else:
+ executable = "nmake"
+ args.append(executable)
+
+ exit_code = run_process(args)
+ if exit_code:
+ raise RuntimeError("Failure while running {}.".format(executable))
+ log.info("")
+
+
+def run_make_install():
+ args = []
+ if is_unix():
+ executable = "make"
+ else:
+ executable = "nmake"
+ args.append(executable)
+ args.append("install")
+
+ exit_code = run_process(args)
+ if exit_code:
+ raise RuntimeError("Failed while running {} install.".format(executable))
+ log.info("")
+
+
+def execute_script(script_path):
+ args = [sys.executable, script_path]
+ exit_code = run_process(args)
+ if exit_code:
+ raise RuntimeError("Failure while executing script: {}".format(script_path))
+ log.info("")
+
+
+def prepare_build_folder(src_path, build_folder_name):
+ build_path = os.path.join(src_path, build_folder_name)
+
+ # The script can be called for both Python 2 and Python 3 wheels, so
+ # preparing a build folder should clean any previous existing build.
+ if os.path.exists(build_path):
+ log.info("Removing {}".format(build_path))
+ rmtree(build_path)
+
+ log.info("Creating {}".format(build_path))
+ os.makedirs(build_path)
+ os.chdir(build_path)
+
+
+def try_build_examples():
+ examples_dir = get_examples_dir()
+
+ log.info("Attempting to build and run samplebinding using cmake.")
+ src_path = os.path.join(examples_dir, "samplebinding")
+ prepare_build_folder(src_path, "cmake")
+ generate_build_cmake()
+ run_make()
+ run_make_install()
+ execute_script(os.path.join(src_path, "main.py"))
+
+ log.info("Attempting to build scriptableapplication using cmake.")
+ src_path = os.path.join(examples_dir, "scriptableapplication")
+ prepare_build_folder(src_path, "cmake")
+ generate_build_cmake()
+ run_make()
+
+ log.info("Attempting to build scriptableapplication using qmake.")
+ src_path = os.path.join(examples_dir, "scriptableapplication")
+ prepare_build_folder(src_path, "qmake")
+ generate_build_qmake()
+ run_make()
+
+
+def run_wheel_tests():
+ wheels_dir = get_wheels_dir()
+ py_version = sys.version_info[0]
+
+ log.info("Attempting to install wheels.\n")
+ try_install_wheels(wheels_dir, py_version)
+
+ log.info("Attempting to build examples.\n")
+ try_build_examples()
+
+ log.info("All tests passed!")
+
+
+if __name__ == "__main__":
+ run_wheel_tests()