From 3974e5e640f7192e02a318a4d698ff5acd4a6086 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Wed, 2 Jul 2025 15:08:07 +0200 Subject: [PATCH 1/6] Move downstream tests into a separate file --- mx.graalpython/downstream_tests.py | 155 +++++++++++++++++++++++++++++ mx.graalpython/mx_graalpython.py | 96 +----------------- 2 files changed, 159 insertions(+), 92 deletions(-) create mode 100644 mx.graalpython/downstream_tests.py diff --git a/mx.graalpython/downstream_tests.py b/mx.graalpython/downstream_tests.py new file mode 100644 index 0000000000..d44aa7df8a --- /dev/null +++ b/mx.graalpython/downstream_tests.py @@ -0,0 +1,155 @@ +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# The Universal Permissive License (UPL), Version 1.0 +# +# Subject to the condition set forth below, permission is hereby granted to any +# person obtaining a copy of this software, associated documentation and/or +# data (collectively the "Software"), free of charge and under any and all +# copyright rights in the Software, and any and all patent rights owned or +# freely licensable by each licensor hereunder covering either (i) the +# unmodified Software as contributed to or provided by such licensor, or (ii) +# the Larger Works (as defined below), to deal in both +# +# (a) the Software, and +# +# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +# one is included with the Software each a "Larger Work" to which the Software +# is contributed by such licensors), +# +# without restriction, including without limitation the rights to copy, create +# derivative works of, display, perform, and distribute the Software and make, +# use, sell, offer for sale, import, export, have made, and have sold the +# Software and the Larger Work(s), and to sublicense the foregoing rights on +# either these or other terms. +# +# This license is subject to the following condition: +# +# The above copyright notice and either this complete permission notice or at a +# minimum a reference to the UPL must be included in all copies or substantial +# portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import argparse +import os +import shlex +import shutil +import subprocess +from pathlib import Path + +DIR = Path(__file__).parent.parent +DOWNSTREAM_TESTS = {} + + +def run(*args, check=True, **kwargs): + return subprocess.run(*args, check=check, **kwargs) + + +def run_in_venv(venv, cmd, **kwargs): + return run(['sh', '-c', f". {venv}/bin/activate && {shlex.join(cmd)}"], **kwargs) + + +def downstream_test(name): + def decorator(fn): + DOWNSTREAM_TESTS[name] = fn + return fn + + return decorator + + +@downstream_test('hpy') +def downstream_test_hpy(graalpy, args=None, env=None, check=True, timeout=None): + testdir = Path('upstream-tests').absolute() + shutil.rmtree(testdir, ignore_errors=True) + testdir.mkdir(exist_ok=True) + hpy_root = DIR / "graalpython" / "hpy" + shutil.copytree(hpy_root, testdir / "hpy") + hpy_root = testdir / "hpy" + hpy_test_root = hpy_root / "test" + venv = testdir / 'hpy_venv' + run([graalpy, "-m", "venv", str(venv)]) + run_in_venv(venv, ["pip", "install", "pytest", "pytest-xdist", "pytest-rerunfailures", "filelock"]) + env = env or os.environ.copy() + env["SETUPTOOLS_SCM_PRETEND_VERSION"] = "0.9.0" + run_in_venv(venv, ["pip", "install", "-e", "."], cwd=str(hpy_root), env=env) + parallelism = str(min(os.cpu_count(), int(os.cpu_count() / 4))) + args = args or [] + args = [ + "python", + "--vm.ea", + "--experimental-options=true", + "--python.EnableDebuggingBuiltins", + *args, + "-m", "pytest", + "-v", + # for those cases where testing invalid handles corrupts the process so + # much that we crash - we don't recover gracefully in some cases :( + "--reruns", "3", + "-n", parallelism, + str(hpy_test_root), + # test_distutils is just slow and testing the build infrastructure + "-k", "not test_distutils" + ] + return run_in_venv(venv, args, env=env, cwd=str(hpy_root), check=check, timeout=timeout) + + +@downstream_test('pybind11') +def downstream_test_pybind11(graalpy): + testdir = Path('upstream-tests').absolute() + shutil.rmtree(testdir, ignore_errors=True) + testdir.mkdir(exist_ok=True) + run(['git', 'clone', 'https://github.com/pybind/pybind11.git'], cwd=testdir) + src = testdir / 'pybind11' + venv = src / 'venv' + run([graalpy, '-m', 'venv', str(venv)]) + run_in_venv(venv, ['pip', 'install', 'pytest']) + run_in_venv(venv, ['cmake', '-S', '.', '-B', 'build', '-DPYBIND11_WERROR=ON'], cwd=src) + run_in_venv(venv, ['cmake', '--build', 'build', '--parallel'], cwd=src) + env = os.environ.copy() + env['PYTHONPATH'] = 'build/tests' + run_in_venv(venv, ['pytest', '-v', '--tb=short', 'tests'], cwd=src, env=env) + + +@downstream_test('virtualenv') +def downstream_test_virtualenv(graalpy): + testdir = Path('upstream-tests').absolute() + shutil.rmtree(testdir, ignore_errors=True) + testdir.mkdir(exist_ok=True) + run(['git', 'clone', 'https://github.com/pypa/virtualenv.git', '-b', 'main'], cwd=testdir) + src = testdir / 'virtualenv' + venv = src / 'venv' + run([graalpy, '-m', 'venv', str(venv)]) + env = os.environ.copy() + env.pop('VIRTUAL_ENV_DISABLE_PROMPT', None) + env['CI_RUN'] = '1' + # Need to avoid pulling in graalpy seeder + env['PIP_GRAALPY_DISABLE_PATCHING'] = '1' + run_in_venv(venv, ['pip', 'install', f'{src}[test]'], env=env) + # Don't activate the venv, it interferes with the test + run([ + str(venv / 'bin' / 'pytest'), '-v', '--tb=short', 'tests', + '-k', 'not fish and not csh and not nushell and not powershell', + ], cwd=src, env=env) + + +def run_downstream_test(python, project): + DOWNSTREAM_TESTS[project](python) + + +def main(): + parser = argparse.ArgumentParser("Runs important upstream packages tests using their main branch") + parser.add_argument("python") + parser.add_argument("project", choices=sorted(DOWNSTREAM_TESTS)) + args = parser.parse_args() + run_downstream_test(args.python, args.project) + + +if __name__ == '__main__': + main() diff --git a/mx.graalpython/mx_graalpython.py b/mx.graalpython/mx_graalpython.py index 70fd5860e7..003c647807 100644 --- a/mx.graalpython/mx_graalpython.py +++ b/mx.graalpython/mx_graalpython.py @@ -43,6 +43,7 @@ from typing import cast +import downstream_tests import mx_graalpython_benchmark import mx_graalpython_gradleproject import mx_urlrewrites @@ -1056,7 +1057,7 @@ def run_python_unittests(python_binary, args=None, paths=None, exclude=None, env def run_hpy_unittests(python_binary, args=None, env=None, nonZeroIsFatal=True, timeout=None, report=False): t0 = time.time() - result = downstream_test_hpy(python_binary, args=args, env=env, nonZeroIsFatal=nonZeroIsFatal, timeout=timeout) + result = downstream_tests.downstream_test_hpy(python_binary, args=args, env=env, check=nonZeroIsFatal, timeout=timeout) if report: mx_gate.make_test_report([{ "name": report.title, @@ -2626,105 +2627,16 @@ def graalpy_jmh(args): mx.run_java(vm_args + ['org.openjdk.jmh.Main'] + args) -def run_in_venv(venv, cmd, **kwargs): - return mx.run(['sh', '-c', f". {venv}/bin/activate && {shlex.join(cmd)}"], **kwargs) - - -DOWNSTREAM_TESTS = {} - -def downstream_test(name): - def decorator(fn): - DOWNSTREAM_TESTS[name] = fn - return fn - return decorator - - -@downstream_test('hpy') -def downstream_test_hpy(graalpy, args=None, env=None, nonZeroIsFatal=True, timeout=None): - testdir = Path('upstream-tests').absolute() - shutil.rmtree(testdir, ignore_errors=True) - testdir.mkdir(exist_ok=True) - hpy_root = os.path.join(mx.dependency("hpy").dir) - shutil.copytree(hpy_root, testdir / "hpy") - hpy_root = testdir / "hpy" - hpy_test_root = hpy_root / "test" - venv = testdir / 'hpy_venv' - mx.run([graalpy, "-m", "venv", str(venv)]) - run_in_venv(venv, ["pip", "install", "pytest", "pytest-xdist", "pytest-rerunfailures", "filelock"]) - env = env or os.environ.copy() - env["SETUPTOOLS_SCM_PRETEND_VERSION"] = "0.9.0" - run_in_venv(venv, ["pip", "install", "-e", "."], cwd=str(hpy_root), env=env) - parallelism = str(min(os.cpu_count(), int(os.cpu_count() / 4))) - args = args or [] - args = [ - "python", - "--vm.ea", - "--experimental-options=true", - "--python.EnableDebuggingBuiltins", - *args, - "-m", "pytest", - "-v", - # for those cases where testing invalid handles corrupts the process so - # much that we crash - we don't recover gracefully in some cases :( - "--reruns", "3", - "-n", parallelism, - str(hpy_test_root), - # test_distutils is just slow and testing the build infrastructure - "-k", "not test_distutils" - ] - mx.logv(shlex.join(args)) - return run_in_venv(venv, args, env=env, cwd=str(hpy_root), nonZeroIsFatal=nonZeroIsFatal, timeout=timeout) - - -@downstream_test('pybind11') -def downstream_test_pybind11(graalpy): - testdir = Path('upstream-tests').absolute() - shutil.rmtree(testdir, ignore_errors=True) - testdir.mkdir(exist_ok=True) - mx.run(['git', 'clone', 'https://github.com/pybind/pybind11.git'], cwd=testdir) - src = testdir / 'pybind11' - venv = src / 'venv' - mx.run([graalpy, '-m', 'venv', str(venv)]) - run_in_venv(venv, ['pip', 'install', 'pytest']) - run_in_venv(venv, ['cmake', '-S', '.', '-B', 'build', '-DPYBIND11_WERROR=ON'], cwd=src) - run_in_venv(venv, ['cmake', '--build', 'build', '--parallel'], cwd=src) - env = os.environ.copy() - env['PYTHONPATH'] = 'build/tests' - run_in_venv(venv, ['pytest', '-v', '--tb=short', 'tests'], cwd=src, env=env) - - -@downstream_test('virtualenv') -def downstream_test_virtualenv(graalpy): - testdir = Path('upstream-tests').absolute() - shutil.rmtree(testdir, ignore_errors=True) - testdir.mkdir(exist_ok=True) - mx.run(['git', 'clone', 'https://github.com/pypa/virtualenv.git', '-b', 'main'], cwd=testdir) - src = testdir / 'virtualenv' - venv = src / 'venv' - mx.run([graalpy, '-m', 'venv', str(venv)]) - env = os.environ.copy() - env.pop('VIRTUAL_ENV_DISABLE_PROMPT', None) - env['CI_RUN'] = '1' - # Need to avoid pulling in graalpy seeder - env['PIP_GRAALPY_DISABLE_PATCHING'] = '1' - run_in_venv(venv, ['pip', 'install', f'{src}[test]'], env=env) - # Don't activate the venv, it interferes with the test - mx.run([ - str(venv / 'bin' / 'pytest'), '-v', '--tb=short', 'tests', - '-k', 'not fish and not csh and not nushell and not powershell', - ], cwd=src, env=env) - - def run_downstream_test(args): parser = ArgumentParser(description="Runs important upstream packages tests using their main branch") - parser.add_argument('project', choices=sorted(DOWNSTREAM_TESTS)) + parser.add_argument('project') parser.add_argument('--dev', action='store_true', help="Use JVM dev standalone") args = parser.parse_args(args) if args.dev: graalpy = graalpy_standalone('jvm', dev=True) else: graalpy = graalpy_standalone_native() - DOWNSTREAM_TESTS[args.project](graalpy) + downstream_tests.run_downstream_test(graalpy, args.project) # ---------------------------------------------------------------------------------------------------------------------- From 341eaae037edd84442918a80882fd5fa240176cb Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Wed, 2 Jul 2025 15:46:04 +0200 Subject: [PATCH 2/6] Add downstream tests to github actions --- .github/workflows/downstream-tests.yml | 47 ++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .github/workflows/downstream-tests.yml diff --git a/.github/workflows/downstream-tests.yml b/.github/workflows/downstream-tests.yml new file mode 100644 index 0000000000..4189b94717 --- /dev/null +++ b/.github/workflows/downstream-tests.yml @@ -0,0 +1,47 @@ +name: Weekly Downstream Tests +on: + schedule: + - cron: '0 0 * * 1' + workflow_dispatch: + +jobs: + downstream-tests: + strategy: + fail-fast: false + matrix: + name: + - pybind11 + - virtualenv + - pyo3 + os: + - id: ubuntu-latest + graalpy_platform: linux-amd64 + - id: macos-latest + graalpy_platform: darwin-aarch64 + + runs-on: ${{ matrix.os.id }} + + steps: + - name: Install CMake + if: ${{ matrix.name == 'pybind11' }} + uses: lukka/get-cmake@latest + with: + cmakeVersion: 3.30.8 + ninjaVersion: 1.12.1 + + - name: Install Rust toolchain + if: ${{ matrix.name == 'pyo3' }} + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + + - name: Checkout main repository + uses: actions/checkout@v4 + + - name: Get GraalPy EA build + run: | + tarball="$(curl -sfL https://raw.githubusercontent.com/graalvm/graal-languages-ea-builds/refs/heads/main/graalpy/versions/latest-native-${{ matrix.os.graalpy_platform }}.url)" + curl -sfL "$tarball" | tar xz + + - name: Run downstream tests for ${{ matrix.name }} + run: python mx.graalpython/downstream_tests.py graalpy-*/bin/python ${{ matrix.name }} From 9c2382a7d3e685c843368bc1b76113feedc107a7 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Wed, 2 Jul 2025 15:49:55 +0200 Subject: [PATCH 3/6] Add downstream test for pyo3 --- mx.graalpython/downstream_tests.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/mx.graalpython/downstream_tests.py b/mx.graalpython/downstream_tests.py index d44aa7df8a..d5b202c919 100644 --- a/mx.graalpython/downstream_tests.py +++ b/mx.graalpython/downstream_tests.py @@ -139,6 +139,19 @@ def downstream_test_virtualenv(graalpy): ], cwd=src, env=env) +@downstream_test('pyo3') +def downstream_test_pyo3(graalpy): + testdir = Path('upstream-tests').absolute() + shutil.rmtree(testdir, ignore_errors=True) + testdir.mkdir(exist_ok=True) + run(['git', 'clone', 'https://github.com/PyO3/pyo3.git', '-b', 'main'], cwd=testdir) + src = testdir / 'pyo3' + venv = src / 'venv' + run([graalpy, '-m', 'venv', str(venv)]) + run_in_venv(venv, ['pip', 'install', 'nox']) + run_in_venv(venv, ['nox', '-s', 'test-py'], cwd=src) + + def run_downstream_test(python, project): DOWNSTREAM_TESTS[project](python) From c767ac0f2ae8f2ed075e3152e39d0a77f70dc4bf Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Wed, 2 Jul 2025 15:50:58 +0200 Subject: [PATCH 4/6] Remove downstream gates from CI --- ci.jsonnet | 9 --------- ci/python-gate.libsonnet | 15 --------------- 2 files changed, 24 deletions(-) diff --git a/ci.jsonnet b/ci.jsonnet index 9ab17ff3f5..1b99aec2b3 100644 --- a/ci.jsonnet +++ b/ci.jsonnet @@ -72,7 +72,6 @@ local cov_jacoco_base = self.cov_jacoco_gate_base, local cov_truffle = self.cov_truffle_gate, local watchdog = self.watchdog, - local downstream_tests_gate = self.downstream_tests_gate, local bench_task(bench=null, benchmarks=BENCHMARKS) = super.bench_task(bench=bench, benchmarks=benchmarks), local bisect_bench_task = self.bisect_bench_task, @@ -341,14 +340,6 @@ "tox-example": gpgate_ee + require(GPYEE_NATIVE_STANDALONE) + platform_spec(no_jobs) + platform_spec({ "linux:amd64:jdk-latest" : tier3 + t("01:00:00"), }), - "python-downstream-tests": gpgate + platform_spec(no_jobs) + downstream_tests_gate({ - "project:*": { - "linux:amd64:jdk-latest": daily + require(GPY_NATIVE_STANDALONE) + t("01:00:00"), - }, - "project:virtualenv": { - "darwin:aarch64:jdk-latest": weekly + t("01:00:00"), - }, - }), "build-wheels": base_gate + platform_spec(no_jobs) + platform_spec({ "windows:amd64:jdk-latest" : on_demand + t("01:00:00"), "darwin:aarch64:jdk-latest" : on_demand + t("01:00:00"), diff --git a/ci/python-gate.libsonnet b/ci/python-gate.libsonnet index f7c2a1a52a..4eb6245157 100644 --- a/ci/python-gate.libsonnet +++ b/ci/python-gate.libsonnet @@ -614,21 +614,6 @@ style_gate:: base_style_gate + task_spec({ tags +:: ",fullbuild,python-license", }), - - local downstream_projects = ["pybind11", "virtualenv"], - local downstream_tests_feature_map = { - project: { - [name]: $.no_jobs {"*" +: task_spec({downstream_project:: name})} - for name in downstream_projects - }, - }, - - downstream_tests_gate(downstream_spec):: run_spec.generate_variants(downstream_spec, downstream_tests_feature_map) + task_spec({ - name_suffix:: [self.downstream_project], - run: [ - ["mx"] + self.mx_parameters + self.dy + self.primary_suite + ["downstream-test", self.downstream_project], - ], - }), } // Local Variables: From 15ce95703b4e23e6d039b1a6af18b737587947a5 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Wed, 2 Jul 2025 16:33:45 +0200 Subject: [PATCH 5/6] Lower parallelism in pybind11 test preparation --- mx.graalpython/downstream_tests.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mx.graalpython/downstream_tests.py b/mx.graalpython/downstream_tests.py index d5b202c919..2e4675c14c 100644 --- a/mx.graalpython/downstream_tests.py +++ b/mx.graalpython/downstream_tests.py @@ -111,7 +111,9 @@ def downstream_test_pybind11(graalpy): run([graalpy, '-m', 'venv', str(venv)]) run_in_venv(venv, ['pip', 'install', 'pytest']) run_in_venv(venv, ['cmake', '-S', '.', '-B', 'build', '-DPYBIND11_WERROR=ON'], cwd=src) - run_in_venv(venv, ['cmake', '--build', 'build', '--parallel'], cwd=src) + # GitHub actions tend to OOM here + parallel_arg = ['--parallel'] if "GITHUB_ACTIONS" not in os.environ else [] + run_in_venv(venv, ['cmake', '--build', 'build', *parallel_arg], cwd=src) env = os.environ.copy() env['PYTHONPATH'] = 'build/tests' run_in_venv(venv, ['pytest', '-v', '--tb=short', 'tests'], cwd=src, env=env) From 59fb1f78e58b043edad77ef56de78a33423d83d0 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Wed, 2 Jul 2025 16:45:19 +0200 Subject: [PATCH 6/6] Disable pyo3 job for now --- .github/workflows/downstream-tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/downstream-tests.yml b/.github/workflows/downstream-tests.yml index 4189b94717..235a6c7c78 100644 --- a/.github/workflows/downstream-tests.yml +++ b/.github/workflows/downstream-tests.yml @@ -12,7 +12,8 @@ jobs: name: - pybind11 - virtualenv - - pyo3 + # Currently fails + # - pyo3 os: - id: ubuntu-latest graalpy_platform: linux-amd64