From 8e22fbf63e0c6fa50a3dc8b0c0d60724baa1539f Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 28 Mar 2025 13:11:08 -0400 Subject: [PATCH 1/4] ci: update to GraalPy 24.2 and mention in README Signed-off-by: Henry Schreiner --- .github/workflows/ci.yml | 7 +++++-- README.rst | 17 +++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6bfb38da11..6aabdc6256 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,7 +38,7 @@ jobs: - '3.13' - 'pypy-3.10' - 'pypy-3.11' - - 'graalpy-24.1' + - 'graalpy-24.2' # Items in here will either be added to the build matrix (if not # present), or add new keys to an existing matrix element if all the @@ -95,9 +95,12 @@ jobs: python: '3.12' args: > -DCMAKE_CXX_FLAGS="/DPYBIND11_RUN_TESTING_WITH_SMART_HOLDER_AS_DEFAULT_BUT_NEVER_USE_IN_PRODUCTION_PLEASE /GR /EHsc" + - python: 'graalpy-24.1' + runs-on: 'ubuntu-latest' exclude: # The setup-python action currently doesn't have graalpy for windows - - python: 'graalpy-24.1' + # See https://github.com/actions/setup-python/pull/880 + - python: 'graalpy-24.2' runs-on: 'windows-2022' diff --git a/README.rst b/README.rst index eaea399aba..09b4d6da18 100644 --- a/README.rst +++ b/README.rst @@ -34,12 +34,12 @@ dependency. Think of this library as a tiny self-contained version of Boost.Python with everything stripped away that isn't relevant for binding generation. Without comments, the core header files only require ~4K -lines of code and depend on Python (3.8+, or PyPy) and the C++ -standard library. This compact implementation was possible thanks to -some C++11 language features (specifically: tuples, lambda functions and -variadic templates). Since its creation, this library has grown beyond -Boost.Python in many ways, leading to dramatically simpler binding code in many -common situations. +lines of code and depend on Python (CPython 3.8+, PyPy, or GraalPy) and the C++ +standard library. This compact implementation was possible thanks to some C++11 +language features (specifically: tuples, lambda functions and variadic +templates). Since its creation, this library has grown beyond Boost.Python in +many ways, leading to dramatically simpler binding code in many common +situations. Tutorial and reference documentation is provided at `pybind11.readthedocs.io `_. @@ -79,8 +79,9 @@ Goodies In addition to the core functionality, pybind11 provides some extra goodies: -- Python 3.8+, and PyPy3 7.3 are supported with an implementation-agnostic - interface (pybind11 2.9 was the last version to support Python 2 and 3.5). +- Python 3.8+, PyPy3 7.3, and GraalPy 24.1+ are supported with an + implementation-agnostic interface (pybind11 2.9 was the last version to + support Python 2 and 3.5). - It is possible to bind C++11 lambda functions with captured variables. The lambda capture data is stored inside the resulting From 99548335c69d4ca754d6443000579477bfe84b49 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 28 Mar 2025 14:05:15 -0400 Subject: [PATCH 2/4] tests: update for GRAALPY 24.2 and better printout Signed-off-by: Henry Schreiner --- tests/conftest.py | 38 ++++++++++++++++++++++-------- tests/pybind11_tests.cpp | 5 ++++ tests/test_enum.py | 11 ++++++--- tests/test_operator_overloading.py | 7 +++++- 4 files changed, 47 insertions(+), 14 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index a018a3f795..cada111279 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,9 +9,11 @@ import contextlib import difflib import gc +import importlib.metadata import multiprocessing import re import sys +import sysconfig import textwrap import traceback @@ -210,16 +212,32 @@ def pytest_configure(): pytest.gc_collect = gc_collect -def pytest_report_header(config): - del config # Unused. +def pytest_report_header(): assert pybind11_tests.compiler_info is not None, ( "Please update pybind11_tests.cpp if this assert fails." ) - return ( - "C++ Info:" - f" {pybind11_tests.compiler_info}" - f" {pybind11_tests.cpp_std}" - f" {pybind11_tests.PYBIND11_INTERNALS_ID}" - f" PYBIND11_SIMPLE_GIL_MANAGEMENT={pybind11_tests.PYBIND11_SIMPLE_GIL_MANAGEMENT}" - f" PYBIND11_NUMPY_1_ONLY={pybind11_tests.PYBIND11_NUMPY_1_ONLY}" - ) + interesting_packages = ("pybind11", "numpy", "scipy", "build") + valid = [] + for package in sorted(interesting_packages): + with contextlib.suppress(ModuleNotFoundError): + valid.append(f"{package}=={importlib.metadata.version(package)}") + reqs = " ".join(valid) + + cpp_info = [ + "C++ Info:", + f"{pybind11_tests.compiler_info}", + f"{pybind11_tests.cpp_std}", + f"{pybind11_tests.PYBIND11_INTERNALS_ID}", + f"PYBIND11_SIMPLE_GIL_MANAGEMENT={pybind11_tests.PYBIND11_SIMPLE_GIL_MANAGEMENT}", + f"PYBIND11_NUMPY_1_ONLY={pybind11_tests.PYBIND11_NUMPY_1_ONLY}", + ] + if hasattr(pybind11_tests, "GRAALPY_VERSION_NUM"): + cpp_info.append(f"GRAALPY_VERSION_NUM=0x{pybind11_tests.GRAALPY_VERSION_NUM:x}") + lines = [ + f"installed packages of interest: {reqs}", + " ".join(cpp_info), + ] + if sysconfig.get_config_var("Py_GIL_DISABLED"): + lines.append("free-threaded Python build") + + return lines diff --git a/tests/pybind11_tests.cpp b/tests/pybind11_tests.cpp index 818d53a548..07f481a74d 100644 --- a/tests/pybind11_tests.cpp +++ b/tests/pybind11_tests.cpp @@ -104,6 +104,11 @@ PYBIND11_MODULE(pybind11_tests, m, py::mod_gil_not_used()) { false; #endif +// Note that this is missing before GraalPy 24.2 +#if defined(GRAALPY_VERSION_NUM) + m.attr("GRAALPY_VERSION_NUM") = GRAALPY_VERSION_NUM; +#endif + bind_ConstructorStats(m); #if defined(PYBIND11_DETAILED_ERROR_MESSAGES) diff --git a/tests/test_enum.py b/tests/test_enum.py index 697e28843f..fd20852102 100644 --- a/tests/test_enum.py +++ b/tests/test_enum.py @@ -5,11 +5,16 @@ import pytest -import env # noqa: F401 +import env +import pybind11_tests from pybind11_tests import enums as m +GRAALPY_24_2 = ( + env.GRAALPY and getattr(pybind11_tests, "GRAALPY_VERSION_NUM", 0) >= 0x180200 +) + -@pytest.mark.xfail("env.GRAALPY", reason="TODO should get fixed on GraalPy side") +@pytest.mark.xfail(env.GRAALPY and not GRAALPY_24_2, reason="Fixed in GraalPy 24.2") def test_unscoped_enum(): assert str(m.UnscopedEnum.EOne) == "UnscopedEnum.EOne" assert str(m.UnscopedEnum.ETwo) == "UnscopedEnum.ETwo" @@ -197,7 +202,7 @@ def test_implicit_conversion(): assert repr(x) == "{: 3, : 4}" -@pytest.mark.xfail("env.GRAALPY", reason="TODO should get fixed on GraalPy side") +@pytest.mark.xfail(env.GRAALPY and not GRAALPY_24_2, reason="Fixed in GraalPy 24.2") def test_binary_operators(): assert int(m.Flags.Read) == 4 assert int(m.Flags.Write) == 2 diff --git a/tests/test_operator_overloading.py b/tests/test_operator_overloading.py index 47949042dd..5f2c44e4fa 100644 --- a/tests/test_operator_overloading.py +++ b/tests/test_operator_overloading.py @@ -3,9 +3,14 @@ import pytest import env +import pybind11_tests from pybind11_tests import ConstructorStats from pybind11_tests import operators as m +GRAALPY_24_2 = ( + env.GRAALPY and getattr(pybind11_tests, "GRAALPY_VERSION_NUM", 0) >= 0x180200 +) + @pytest.mark.xfail("env.GRAALPY", reason="TODO should get fixed on GraalPy side") def test_operator_overloading(): @@ -88,7 +93,7 @@ def test_operator_overloading(): assert cstats.move_assignments == 0 -@pytest.mark.xfail("env.GRAALPY", reason="TODO should get fixed on GraalPy side") +@pytest.mark.xfail(env.GRAALPY and not GRAALPY_24_2, reason="Fixed in GraalPy 24.2") def test_operators_notimplemented(): """#393: need to return NotSupported to ensure correct arithmetic operator behavior""" From 410a96bf7547e94fe3391ddcec19d1a385c8f42d Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 28 Mar 2025 15:01:42 -0400 Subject: [PATCH 3/4] tests: use __graalpython__ for version number Signed-off-by: Henry Schreiner --- tests/conftest.py | 6 ++++-- tests/env.py | 4 ++++ tests/pybind11_tests.cpp | 5 ----- tests/test_enum.py | 13 ++++++------- tests/test_operator_overloading.py | 9 +++------ 5 files changed, 17 insertions(+), 20 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index cada111279..cd356a3bc5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -231,8 +231,10 @@ def pytest_report_header(): f"PYBIND11_SIMPLE_GIL_MANAGEMENT={pybind11_tests.PYBIND11_SIMPLE_GIL_MANAGEMENT}", f"PYBIND11_NUMPY_1_ONLY={pybind11_tests.PYBIND11_NUMPY_1_ONLY}", ] - if hasattr(pybind11_tests, "GRAALPY_VERSION_NUM"): - cpp_info.append(f"GRAALPY_VERSION_NUM=0x{pybind11_tests.GRAALPY_VERSION_NUM:x}") + if "__graalpython__" in sys.modules: + cpp_info.append( + f"GraalPy version: {sys.modules['__graalpython__'].get_graalvm_version()}" + ) lines = [ f"installed packages of interest: {reqs}", " ".join(cpp_info), diff --git a/tests/env.py b/tests/env.py index b513e455d1..9de53999b0 100644 --- a/tests/env.py +++ b/tests/env.py @@ -13,6 +13,10 @@ CPYTHON = platform.python_implementation() == "CPython" PYPY = platform.python_implementation() == "PyPy" GRAALPY = sys.implementation.name == "graalpy" +_graalpy_version = ( + sys.modules["__graalpython__"].get_graalvm_version() if GRAALPY else "0.0.0" +) +GRAALPY_VERSION = tuple(int(t) for t in _graalpy_version.split(".")[:3]) PY_GIL_DISABLED = bool(sysconfig.get_config_var("Py_GIL_DISABLED")) diff --git a/tests/pybind11_tests.cpp b/tests/pybind11_tests.cpp index 07f481a74d..818d53a548 100644 --- a/tests/pybind11_tests.cpp +++ b/tests/pybind11_tests.cpp @@ -104,11 +104,6 @@ PYBIND11_MODULE(pybind11_tests, m, py::mod_gil_not_used()) { false; #endif -// Note that this is missing before GraalPy 24.2 -#if defined(GRAALPY_VERSION_NUM) - m.attr("GRAALPY_VERSION_NUM") = GRAALPY_VERSION_NUM; -#endif - bind_ConstructorStats(m); #if defined(PYBIND11_DETAILED_ERROR_MESSAGES) diff --git a/tests/test_enum.py b/tests/test_enum.py index fd20852102..874dae0100 100644 --- a/tests/test_enum.py +++ b/tests/test_enum.py @@ -6,15 +6,12 @@ import pytest import env -import pybind11_tests from pybind11_tests import enums as m -GRAALPY_24_2 = ( - env.GRAALPY and getattr(pybind11_tests, "GRAALPY_VERSION_NUM", 0) >= 0x180200 -) - -@pytest.mark.xfail(env.GRAALPY and not GRAALPY_24_2, reason="Fixed in GraalPy 24.2") +@pytest.mark.xfail( + env.GRAALPY and env.GRAALPY_VERSION < (24, 2), reason="Fixed in GraalPy 24.2" +) def test_unscoped_enum(): assert str(m.UnscopedEnum.EOne) == "UnscopedEnum.EOne" assert str(m.UnscopedEnum.ETwo) == "UnscopedEnum.ETwo" @@ -202,7 +199,9 @@ def test_implicit_conversion(): assert repr(x) == "{: 3, : 4}" -@pytest.mark.xfail(env.GRAALPY and not GRAALPY_24_2, reason="Fixed in GraalPy 24.2") +@pytest.mark.xfail( + env.GRAALPY and env.GRAALPY_VERSION < (24, 2), reason="Fixed in GraalPy 24.2" +) def test_binary_operators(): assert int(m.Flags.Read) == 4 assert int(m.Flags.Write) == 2 diff --git a/tests/test_operator_overloading.py b/tests/test_operator_overloading.py index 5f2c44e4fa..0230e72c5a 100644 --- a/tests/test_operator_overloading.py +++ b/tests/test_operator_overloading.py @@ -3,14 +3,9 @@ import pytest import env -import pybind11_tests from pybind11_tests import ConstructorStats from pybind11_tests import operators as m -GRAALPY_24_2 = ( - env.GRAALPY and getattr(pybind11_tests, "GRAALPY_VERSION_NUM", 0) >= 0x180200 -) - @pytest.mark.xfail("env.GRAALPY", reason="TODO should get fixed on GraalPy side") def test_operator_overloading(): @@ -93,7 +88,9 @@ def test_operator_overloading(): assert cstats.move_assignments == 0 -@pytest.mark.xfail(env.GRAALPY and not GRAALPY_24_2, reason="Fixed in GraalPy 24.2") +@pytest.mark.xfail( + env.GRAALPY and env.GRAALPY_VERSION < (24, 2), reason="Fixed in GraalPy 24.2" +) def test_operators_notimplemented(): """#393: need to return NotSupported to ensure correct arithmetic operator behavior""" From b945bfccfedef1de8133bef7d693d365fc7c63e2 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 31 Mar 2025 18:57:50 -0400 Subject: [PATCH 4/4] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 09b4d6da18..2f2829960b 100644 --- a/README.rst +++ b/README.rst @@ -79,7 +79,7 @@ Goodies In addition to the core functionality, pybind11 provides some extra goodies: -- Python 3.8+, PyPy3 7.3, and GraalPy 24.1+ are supported with an +- Python 3.8+, PyPy3 7.3.17+, and GraalPy 24.1+ are supported with an implementation-agnostic interface (pybind11 2.9 was the last version to support Python 2 and 3.5).