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..2f2829960b 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.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). - It is possible to bind C++11 lambda functions with captured variables. The lambda capture data is stored inside the resulting diff --git a/tests/conftest.py b/tests/conftest.py index a018a3f795..cd356a3bc5 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,34 @@ 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 "__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), + ] + if sysconfig.get_config_var("Py_GIL_DISABLED"): + lines.append("free-threaded Python build") + + return lines 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/test_enum.py b/tests/test_enum.py index 697e28843f..874dae0100 100644 --- a/tests/test_enum.py +++ b/tests/test_enum.py @@ -5,11 +5,13 @@ import pytest -import env # noqa: F401 +import env from pybind11_tests import enums as m -@pytest.mark.xfail("env.GRAALPY", reason="TODO should get fixed on GraalPy side") +@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" @@ -197,7 +199,9 @@ 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 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 47949042dd..0230e72c5a 100644 --- a/tests/test_operator_overloading.py +++ b/tests/test_operator_overloading.py @@ -88,7 +88,9 @@ 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 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"""