diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2888c420b9..dcc61ecd74 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,16 +30,14 @@ jobs: - '3.6' - '3.9' - '3.10' - # - '3.11-dev' - - 'pypy-3.7-v7.3.5' - # - 'pypy-3.8' + - 'pypy-3.7-v7.3.7' + - 'pypy-3.8-v7.3.7' # 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 # existing keys match. # - # We support three optional keys: args (both build), args1 (first - # build), and args2 (second build). + # We support an optional keys: args, for cmake args include: # Just add a key - runs-on: ubuntu-latest @@ -122,7 +120,7 @@ jobs: run: git clean -fdx # Second build - C++17 mode and in a build directory - - name: Configure ${{ matrix.args2 }} + - name: Configure C++17 run: > cmake -S . -B build2 -DPYBIND11_WERROR=ON @@ -130,7 +128,6 @@ jobs: -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=17 ${{ matrix.args }} - ${{ matrix.args2 }} - name: Build run: cmake --build build2 -j 2 diff --git a/.github/workflows/upstream.yml b/.github/workflows/upstream.yml new file mode 100644 index 0000000000..654947425f --- /dev/null +++ b/.github/workflows/upstream.yml @@ -0,0 +1,112 @@ + +name: Upstream + +on: + workflow_dispatch: + pull_request: + +concurrency: + group: upstream-${{ github.ref }} + cancel-in-progress: true + +env: + PIP_ONLY_BINARY: numpy + +jobs: + standard: + name: "🐍 3.11 dev • ubuntu-latest • x64" + runs-on: ubuntu-latest + if: "contains(github.event.pull_request.labels.*.name, 'python dev')" + + steps: + - uses: actions/checkout@v2 + + - name: Setup Python 3.11 + uses: actions/setup-python@v2 + with: + python-version: "3.11-dev" + + - name: Setup Boost (Linux) + if: runner.os == 'Linux' + run: sudo apt-get install libboost-dev + + - name: Update CMake + uses: jwlawson/actions-setup-cmake@v1.11 + + - name: Prepare env + run: | + python -m pip install -r tests/requirements.txt + + - name: Setup annotations on Linux + if: runner.os == 'Linux' + run: python -m pip install pytest-github-actions-annotate-failures + + # First build - C++11 mode and inplace + - name: Configure C++11 + run: > + cmake -S . -B . + -DPYBIND11_WERROR=ON + -DDOWNLOAD_CATCH=ON + -DDOWNLOAD_EIGEN=ON + -DCMAKE_CXX_STANDARD=11 + + - name: Build C++11 + run: cmake --build . -j 2 + + - name: Python tests C++11 + run: cmake --build . --target pytest -j 2 + + - name: C++11 tests + run: cmake --build . --target cpptest -j 2 + + - name: Interface test C++11 + run: cmake --build . --target test_cmake_build + + - name: Clean directory + run: git clean -fdx + + # Second build - C++17 mode and in a build directory + - name: Configure C++17 + run: > + cmake -S . -B build2 + -DPYBIND11_WERROR=ON + -DDOWNLOAD_CATCH=ON + -DDOWNLOAD_EIGEN=ON + -DCMAKE_CXX_STANDARD=17 + ${{ matrix.args }} + ${{ matrix.args2 }} + + - name: Build + run: cmake --build build2 -j 2 + + - name: Python tests + run: cmake --build build2 --target pytest + + - name: C++ tests + run: cmake --build build2 --target cpptest + + # Third build - C++17 mode with unstable ABI + - name: Configure (unstable ABI) + run: > + cmake -S . -B build3 + -DPYBIND11_WERROR=ON + -DDOWNLOAD_CATCH=ON + -DDOWNLOAD_EIGEN=ON + -DCMAKE_CXX_STANDARD=17 + -DPYBIND11_INTERNALS_VERSION=10000000 + "-DPYBIND11_TEST_OVERRIDE=test_call_policies.cpp;test_gil_scoped.cpp;test_thread.cpp" + ${{ matrix.args }} + + - name: Build (unstable ABI) + run: cmake --build build3 -j 2 + + - name: Python tests (unstable ABI) + run: cmake --build build3 --target pytest + + - name: Interface test + run: cmake --build build2 --target test_cmake_build + + # This makes sure the setup_helpers module can build packages using + # setuptools + - name: Setuptools helpers test + run: pytest tests/extra_setuptools diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 4b39827c25..097d41bdaf 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -150,7 +150,8 @@ struct type_caster::value && !is_std_char_t return false; } else { handle src_or_index = src; -#if PY_VERSION_HEX < 0x03080000 + // PyPy: 7.3.7's 3.8 does not implement PyLong_*'s __index__ calls. +#if PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION) object index; if (!PYBIND11_LONG_CHECK(src.ptr())) { // So: index_check(src.ptr()) index = reinterpret_steal(PyNumber_Index(src.ptr())); diff --git a/include/pybind11/eval.h b/include/pybind11/eval.h index 6cc672e2d5..4248551e9b 100644 --- a/include/pybind11/eval.h +++ b/include/pybind11/eval.h @@ -19,11 +19,11 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(detail) inline void ensure_builtins_in_globals(object &global) { - #if PY_VERSION_HEX < 0x03080000 + #if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x03080000 // Running exec and eval on Python 2 and 3 adds `builtins` module under // `__builtins__` key to globals if not yet present. // Python 3.8 made PyRun_String behave similarly. Let's also do that for - // older versions, for consistency. + // older versions, for consistency. This was missing from PyPy3.8 7.3.7. if (!global.contains("__builtins__")) global["__builtins__"] = module_::import(PYBIND11_BUILTINS_MODULE); #else diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index c2b88688a5..cfe03f6dbd 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -2365,8 +2365,9 @@ inline function get_type_override(const void *this_ptr, const type_info *this_ty /* Don't call dispatch code if invoked from overridden function. Unfortunately this doesn't work on PyPy. */ -#if !defined(PYPY_VERSION) - +#if !defined(PYPY_VERSION) && PY_VERSION_HEX < 0x030B0000 + // TODO: Remove PyPy workaround for Python 3.11. + // Current API fails on 3.11 since co_varnames can be null. #if PY_VERSION_HEX >= 0x03090000 PyFrameObject *frame = PyThreadState_GetFrame(PyThreadState_Get()); if (frame != nullptr) { @@ -2374,7 +2375,7 @@ inline function get_type_override(const void *this_ptr, const type_info *this_ty // f_code is guaranteed to not be NULL if ((std::string) str(f_code->co_name) == name && f_code->co_argcount > 0) { PyObject* locals = PyEval_GetLocals(); - if (locals != nullptr) { + if (locals != nullptr && f_code->co_varnames != nullptr) { PyObject *self_caller = dict_getitem( locals, PyTuple_GET_ITEM(f_code->co_varnames, 0) ); diff --git a/tests/requirements.txt b/tests/requirements.txt index 8d2742a71c..98ca46d28a 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -2,7 +2,7 @@ numpy==1.16.6; python_version<"3.6" and sys_platform!="win32" and platform_pytho numpy==1.19.0; platform_python_implementation=="PyPy" and sys_platform=="linux" and python_version=="3.6" numpy==1.20.0; platform_python_implementation=="PyPy" and sys_platform=="linux" and python_version=="3.7" numpy==1.19.3; platform_python_implementation!="PyPy" and python_version=="3.6" -numpy==1.21.3; platform_python_implementation!="PyPy" and python_version>="3.7" +numpy==1.21.3; platform_python_implementation!="PyPy" and python_version>="3.7" and python_version<"3.11" py @ git+https://github.com/pytest-dev/py; python_version>="3.11" pytest==4.6.9; python_version<"3.5" pytest==6.1.2; python_version=="3.5" diff --git a/tests/test_buffers.py b/tests/test_buffers.py index adf7cadff2..0877dc0e41 100644 --- a/tests/test_buffers.py +++ b/tests/test_buffers.py @@ -36,6 +36,10 @@ def test_from_python(): # https://foss.heptapod.net/pypy/pypy/-/issues/2444 +# TODO: fix on recent PyPy +@pytest.mark.xfail( + env.PYPY, reason="PyPy 7.3.7 doesn't clear this anymore", stict=False +) def test_to_python(): mat = m.Matrix(5, 4) assert memoryview(mat).shape == (5, 4) diff --git a/tests/test_builtin_casters.py b/tests/test_builtin_casters.py index 2a061c193e..9c5e17a68e 100644 --- a/tests/test_builtin_casters.py +++ b/tests/test_builtin_casters.py @@ -299,7 +299,8 @@ def cant_convert(v): assert noconvert(7) == 7 cant_convert(3.14159) # TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar) - if (3, 8) <= env.PY < (3, 10): + # TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7) + if (3, 8) <= env.PY < (3, 10) and env.CPYTHON: with env.deprecated_call(): assert convert(Int()) == 42 else: @@ -334,7 +335,9 @@ def require_implicit(v): # The implicit conversion from np.float32 is undesirable but currently accepted. # TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar) - if (3, 8) <= env.PY < (3, 10): + # TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7) + # https://github.com/pybind/pybind11/issues/3408 + if (3, 8) <= env.PY < (3, 10) and env.CPYTHON: with env.deprecated_call(): assert convert(np.float32(3.14159)) == 3 else: diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 3821eadaa4..56201a81c5 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -3,7 +3,7 @@ import pytest -import env # noqa: F401 +import env import pybind11_cross_module_tests as cm from pybind11_tests import exceptions as m @@ -97,6 +97,8 @@ def ignore_pytest_unraisable_warning(f): return f +# TODO: find out why this fails on PyPy, https://foss.heptapod.net/pypy/pypy/-/issues/3583 +@pytest.mark.xfail(env.PYPY, reason="Failure on PyPy 3.8 (7.3.7)", strict=False) @ignore_pytest_unraisable_warning def test_python_alreadyset_in_destructor(monkeypatch, capsys): hooked = False