From 301c9d7880cbaadd52196e28c38ea0319ee3143b Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 24 Oct 2022 15:07:13 -0400 Subject: [PATCH 1/4] tests: add ABI check Signed-off-by: Henry Schreiner --- .gitignore | 1 + noxfile.py | 13 +++++++++++++ tests/extra_abi/dog.cpp | 11 +++++++++++ tests/extra_abi/dog.hpp | 10 ++++++++++ tests/extra_abi/pet.cpp | 12 ++++++++++++ tests/extra_abi/pet.hpp | 6 ++++++ tests/extra_abi/setup.py | 20 ++++++++++++++++++++ tests/extra_abi/test_installed.py | 13 +++++++++++++ 8 files changed, 86 insertions(+) create mode 100644 tests/extra_abi/dog.cpp create mode 100644 tests/extra_abi/dog.hpp create mode 100644 tests/extra_abi/pet.cpp create mode 100644 tests/extra_abi/pet.hpp create mode 100644 tests/extra_abi/setup.py create mode 100755 tests/extra_abi/test_installed.py diff --git a/.gitignore b/.gitignore index 43d5094c96..0ef3180c74 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,4 @@ pybind11Targets.cmake /docs/_build/* .ipynb_checkpoints/ tests/main.cpp +tests/*/temp* diff --git a/noxfile.py b/noxfile.py index 021ced2453..2e137a6aad 100644 --- a/noxfile.py +++ b/noxfile.py @@ -61,6 +61,19 @@ def tests_packaging(session: nox.Session) -> None: session.run("pytest", "tests/extra_python_package", *session.posargs) +@nox.session +def tests_abi(session: nox.Session) -> None: + """ + Run the abi checker. + """ + + session.install("pybind11==2.8.0") + session.install("tests/extra_abi", env={"EXAMPLE_NAME": "pet"}) + session.install(".") + session.install("tests/extra_abi", env={"EXAMPLE_NAME": "dog"}) + session.run("python", "tests/extra_abi/test_installed.py") + + @nox.session(reuse_venv=True) def docs(session: nox.Session) -> None: """ diff --git a/tests/extra_abi/dog.cpp b/tests/extra_abi/dog.cpp new file mode 100644 index 0000000000..da40d5885e --- /dev/null +++ b/tests/extra_abi/dog.cpp @@ -0,0 +1,11 @@ +#include + +#include "dog.hpp" + +#include + +namespace py = pybind11; + +PYBIND11_MODULE(dog, m) { + py::class_(m, "Dog").def(py::init()).def("bark", &Dog::bark); +} diff --git a/tests/extra_abi/dog.hpp b/tests/extra_abi/dog.hpp new file mode 100644 index 0000000000..f604716a9a --- /dev/null +++ b/tests/extra_abi/dog.hpp @@ -0,0 +1,10 @@ +#include + +#include "pet.hpp" + +#include + +struct PYBIND11_EXPORT Dog : Pet { + explicit Dog(const std::string &name) : Pet(name) {} + std::string bark() const { return "woof!"; } +}; diff --git a/tests/extra_abi/pet.cpp b/tests/extra_abi/pet.cpp new file mode 100644 index 0000000000..7830b90e24 --- /dev/null +++ b/tests/extra_abi/pet.cpp @@ -0,0 +1,12 @@ +#include + +#include "pet.hpp" + +#include + +namespace py = pybind11; + +PYBIND11_MODULE(pet, m) { + py::class_ pet(m, "Pet"); + pet.def(py::init()).def_readwrite("name", &Pet::name); +} diff --git a/tests/extra_abi/pet.hpp b/tests/extra_abi/pet.hpp new file mode 100644 index 0000000000..37fa90b186 --- /dev/null +++ b/tests/extra_abi/pet.hpp @@ -0,0 +1,6 @@ +#include + +struct Pet { + explicit Pet(const std::string &name) : name(name) {} + std::string name; +}; diff --git a/tests/extra_abi/setup.py b/tests/extra_abi/setup.py new file mode 100644 index 0000000000..809be19633 --- /dev/null +++ b/tests/extra_abi/setup.py @@ -0,0 +1,20 @@ +import os +import sys + +from setuptools import setup + +from pybind11.setup_helpers import Pybind11Extension + +name = os.environ["EXAMPLE_NAME"] +assert name in {"pet", "dog"} + + +ext = Pybind11Extension( + name, + [f"{name}.cpp"], + include_dirs=["."], + cxx_std=11, + extra_compile_args=["/d2FH4-"] if sys.platform.startswith("win32") else [], +) + +setup(name=name, version="0.0.0", ext_modules=[ext]) diff --git a/tests/extra_abi/test_installed.py b/tests/extra_abi/test_installed.py new file mode 100755 index 0000000000..ca8fe7fa80 --- /dev/null +++ b/tests/extra_abi/test_installed.py @@ -0,0 +1,13 @@ +try: + import dog + + raise RuntimeError("Broken! Dog must require Pet to be loaded") +except ImportError: + import pet # noqa: F401 + +import dog # noqa: F811 + +d = dog.Dog("Bluey") + +d.bark() +assert d.name == "Bluey" From 188a43b9854d386b9f2fb65579c682d07798e5ad Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 24 Oct 2022 16:54:01 -0400 Subject: [PATCH 2/4] tests: use pytest-virtualenv to test abi Signed-off-by: Henry Schreiner --- noxfile.py | 14 ++++++---- tests/conftest.py | 26 +++++++++++-------- .../{test_installed.py => check_installed.py} | 0 tests/extra_abi/test_venv_abi.py | 16 ++++++++++++ tests/requirements.txt | 1 + 5 files changed, 41 insertions(+), 16 deletions(-) rename tests/extra_abi/{test_installed.py => check_installed.py} (100%) create mode 100755 tests/extra_abi/test_venv_abi.py diff --git a/noxfile.py b/noxfile.py index 2e137a6aad..3e2b58f777 100644 --- a/noxfile.py +++ b/noxfile.py @@ -67,11 +67,15 @@ def tests_abi(session: nox.Session) -> None: Run the abi checker. """ - session.install("pybind11==2.8.0") - session.install("tests/extra_abi", env={"EXAMPLE_NAME": "pet"}) - session.install(".") - session.install("tests/extra_abi", env={"EXAMPLE_NAME": "dog"}) - session.run("python", "tests/extra_abi/test_installed.py") + session.install("pybind11==2.8.0", "--no-build-isolation") + session.install( + "tests/extra_abi", "--no-build-isolation", env={"EXAMPLE_NAME": "pet"} + ) + session.install(".", "--no-build-isolation") + session.install( + "tests/extra_abi", "--no-build-isolation", env={"EXAMPLE_NAME": "dog"} + ) + session.run("python", "tests/extra_abi/check_installed.py") @nox.session(reuse_venv=True) diff --git a/tests/conftest.py b/tests/conftest.py index 02ce263afc..517e0908f1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -13,7 +13,10 @@ import pytest # Early diagnostic for failed imports -import pybind11_tests +try: + import pybind11_tests +except ModuleNotFoundError: + pybind11_tests = None _long_marker = re.compile(r"([0-9])L") _hexadecimal = re.compile(r"0x[0-9a-fA-F]+") @@ -201,13 +204,14 @@ def pytest_configure(): def pytest_report_header(config): - del config # Unused. - 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}" - ) + if pybind11_tests is not None: + del config # Unused. + 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}" + ) diff --git a/tests/extra_abi/test_installed.py b/tests/extra_abi/check_installed.py similarity index 100% rename from tests/extra_abi/test_installed.py rename to tests/extra_abi/check_installed.py diff --git a/tests/extra_abi/test_venv_abi.py b/tests/extra_abi/test_venv_abi.py new file mode 100755 index 0000000000..95d368865d --- /dev/null +++ b/tests/extra_abi/test_venv_abi.py @@ -0,0 +1,16 @@ +from pathlib import Path + +DIR = Path(__file__).parent.resolve() + + +def test_build_import(virtualenv): + virtualenv.run('pip install "pybind11==2.8.0" --no-build-isolation') + virtualenv.env["EXAMPLE_NAME"] = "pet" + virtualenv.run(f"pip install {DIR} --no-build-isolation") + + virtualenv.run(f"pip install {DIR.parent.parent} --no-build-isolation") + virtualenv.env["EXAMPLE_NAME"] = "dog" + virtualenv.run(f"pip install {DIR} --no-build-isolation") + + script = DIR / "check_installed.py" + virtualenv.run(f"python {script}") diff --git a/tests/requirements.txt b/tests/requirements.txt index 04aafa8cf9..d8ad4643fb 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -5,5 +5,6 @@ numpy==1.21.5; platform_python_implementation!="PyPy" and python_version>="3.7" numpy==1.22.2; platform_python_implementation!="PyPy" and python_version>="3.10" and python_version<"3.11" pytest==7.0.0 pytest-timeout +pytest-virtualenv scipy==1.5.4; platform_python_implementation!="PyPy" and python_version<"3.10" scipy==1.8.0; platform_python_implementation!="PyPy" and python_version=="3.10" From 1d75e2a543ed094de9a50a5bbcced8a412da4a3e Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 24 Oct 2022 17:21:18 -0400 Subject: [PATCH 3/4] ci: enable abi test on some platforms Signed-off-by: Henry Schreiner --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2951a0ad19..6fc2677839 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -176,6 +176,10 @@ jobs: run: pytest tests/extra_setuptools if: "!(matrix.runs-on == 'windows-2022')" + # This tests ABI compatibility + - name: ABI test + run: pytest tests/extra_abi + deadsnakes: strategy: From e7aa7703027bd9da29f5f3e3e6ad2ac1baa14f03 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 24 Oct 2022 21:58:39 -0400 Subject: [PATCH 4/4] Update .github/workflows/ci.yml --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6fc2677839..1503a25656 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -178,6 +178,7 @@ jobs: # This tests ABI compatibility - name: ABI test + if: matrix.python != '3.11-dev' run: pytest tests/extra_abi