From ff7b69714d76c312b0bcc45e4a8b854783f6dbc5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Oct 2022 00:50:40 -0400 Subject: [PATCH 1/6] chore(deps): bump jwlawson/actions-setup-cmake from 1.12 to 1.13 (#4233) Bumps [jwlawson/actions-setup-cmake](https://github.com/jwlawson/actions-setup-cmake) from 1.12 to 1.13. - [Release notes](https://github.com/jwlawson/actions-setup-cmake/releases) - [Commits](https://github.com/jwlawson/actions-setup-cmake/compare/v1.12...v1.13) --- updated-dependencies: - dependency-name: jwlawson/actions-setup-cmake dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 12 ++++++------ .github/workflows/configure.yml | 2 +- .github/workflows/upstream.yml | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 99caabf09..38694bcfa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -80,7 +80,7 @@ jobs: run: brew install boost - name: Update CMake - uses: jwlawson/actions-setup-cmake@v1.12 + uses: jwlawson/actions-setup-cmake@v1.13 - name: Cache wheels if: runner.os == 'macOS' @@ -202,7 +202,7 @@ jobs: debug: ${{ matrix.python-debug }} - name: Update CMake - uses: jwlawson/actions-setup-cmake@v1.12 + uses: jwlawson/actions-setup-cmake@v1.13 - name: Valgrind cache if: matrix.valgrind @@ -465,7 +465,7 @@ jobs: run: python3 -m pip install --upgrade pip - name: Update CMake - uses: jwlawson/actions-setup-cmake@v1.12 + uses: jwlawson/actions-setup-cmake@v1.13 - name: Configure shell: bash @@ -754,7 +754,7 @@ jobs: architecture: x86 - name: Update CMake - uses: jwlawson/actions-setup-cmake@v1.12 + uses: jwlawson/actions-setup-cmake@v1.13 - name: Prepare MSVC uses: ilammy/msvc-dev-cmd@v1.11.0 @@ -807,7 +807,7 @@ jobs: architecture: x86 - name: Update CMake - uses: jwlawson/actions-setup-cmake@v1.12 + uses: jwlawson/actions-setup-cmake@v1.13 - name: Prepare MSVC uses: ilammy/msvc-dev-cmd@v1.11.0 @@ -858,7 +858,7 @@ jobs: python3 -m pip install -r tests/requirements.txt - name: Update CMake - uses: jwlawson/actions-setup-cmake@v1.12 + uses: jwlawson/actions-setup-cmake@v1.13 - name: Configure C++20 run: > diff --git a/.github/workflows/configure.yml b/.github/workflows/configure.yml index edcad4198..5ec0dd462 100644 --- a/.github/workflows/configure.yml +++ b/.github/workflows/configure.yml @@ -51,7 +51,7 @@ jobs: # An action for adding a specific version of CMake: # https://github.com/jwlawson/actions-setup-cmake - name: Setup CMake ${{ matrix.cmake }} - uses: jwlawson/actions-setup-cmake@v1.12 + uses: jwlawson/actions-setup-cmake@v1.13 with: cmake-version: ${{ matrix.cmake }} diff --git a/.github/workflows/upstream.yml b/.github/workflows/upstream.yml index 95ff4cb83..366284acf 100644 --- a/.github/workflows/upstream.yml +++ b/.github/workflows/upstream.yml @@ -31,7 +31,7 @@ jobs: run: sudo apt-get install libboost-dev - name: Update CMake - uses: jwlawson/actions-setup-cmake@v1.12 + uses: jwlawson/actions-setup-cmake@v1.13 - name: Prepare env run: | From 0927c4d19e33687b463346ecb7d194493ee53b4c Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Tue, 11 Oct 2022 16:07:42 -0400 Subject: [PATCH 2/6] chore: Improve PyCapsule exception handling (#4232) * Improve pycapsule error handling corner cases * Handle another corner case * Simplify err handling code --- include/pybind11/pytypes.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 29506b7ea..2e6b755ca 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -1829,7 +1829,7 @@ public: // guard if destructor called while err indicator is set error_scope error_guard; auto destructor = reinterpret_cast(PyCapsule_GetContext(o)); - if (PyErr_Occurred()) { + if (destructor == nullptr && PyErr_Occurred()) { throw error_already_set(); } const char *name = get_name_in_error_scope(o); @@ -1843,7 +1843,7 @@ public: } }); - if (!m_ptr || PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) { + if (!m_ptr || PyCapsule_SetContext(m_ptr, reinterpret_cast(destructor)) != 0) { throw error_already_set(); } } From 8781daf6e6c2a80524d787110094584a28619f2a Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Wed, 12 Oct 2022 16:46:40 -0400 Subject: [PATCH 3/6] chore: Optimize iterator advance() call (#4237) --- include/pybind11/pytypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 2e6b755ca..0dda48145 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -1382,7 +1382,7 @@ public: private: void advance() { value = reinterpret_steal(PyIter_Next(m_ptr)); - if (PyErr_Occurred()) { + if (value.ptr() == nullptr && PyErr_Occurred()) { throw error_already_set(); } } From 964c49978f7e7227f2968c359f4f05255d2b54f4 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 12 Oct 2022 15:43:43 -0700 Subject: [PATCH 4/6] Minor `py::capsule` cleanup. No functional change. (#4238) Use `PyCapsule_Destructor` (part of the stable Python ABI) instead of spelling out the C `typedef`. The deprecation message is misleading. Replace with a message pointing to another existing ctor. Background: According to @wjakob the original motivation for deprecating the ctor (in PR #752) was to hide Python C API details, but PR #902 brought those back with a new ctor, it cannot be avoided. Having a `PyCapsule_Destructor` or a `void (*destructor)(void *)` are two separate and valid use cases. --- include/pybind11/pytypes.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 0dda48145..4b93d2018 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -1809,16 +1809,16 @@ public: explicit capsule(const void *value, const char *name = nullptr, - void (*destructor)(PyObject *) = nullptr) + PyCapsule_Destructor destructor = nullptr) : object(PyCapsule_New(const_cast(value), name, destructor), stolen_t{}) { if (!m_ptr) { throw error_already_set(); } } - PYBIND11_DEPRECATED("Please pass a destructor that takes a void pointer as input") - capsule(const void *value, void (*destruct)(PyObject *)) - : object(PyCapsule_New(const_cast(value), nullptr, destruct), stolen_t{}) { + PYBIND11_DEPRECATED("Please use the ctor with value, name, destructor args") + capsule(const void *value, PyCapsule_Destructor destructor) + : object(PyCapsule_New(const_cast(value), nullptr, destructor), stolen_t{}) { if (!m_ptr) { throw error_already_set(); } From 5b5547bc1bcfdf58ff4febbb3a08f1764ac4ec7e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Oct 2022 17:57:55 -0400 Subject: [PATCH 5/6] chore(deps): bump ilammy/msvc-dev-cmd from 1.11.0 to 1.12.0 (#4242) Bumps [ilammy/msvc-dev-cmd](https://github.com/ilammy/msvc-dev-cmd) from 1.11.0 to 1.12.0. - [Release notes](https://github.com/ilammy/msvc-dev-cmd/releases) - [Commits](https://github.com/ilammy/msvc-dev-cmd/compare/v1.11.0...v1.12.0) --- updated-dependencies: - dependency-name: ilammy/msvc-dev-cmd dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 38694bcfa..bc7175d82 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -757,7 +757,7 @@ jobs: uses: jwlawson/actions-setup-cmake@v1.13 - name: Prepare MSVC - uses: ilammy/msvc-dev-cmd@v1.11.0 + uses: ilammy/msvc-dev-cmd@v1.12.0 with: arch: x86 @@ -810,7 +810,7 @@ jobs: uses: jwlawson/actions-setup-cmake@v1.13 - name: Prepare MSVC - uses: ilammy/msvc-dev-cmd@v1.11.0 + uses: ilammy/msvc-dev-cmd@v1.12.0 with: arch: x86 From b926396bdf42ef1e5f1f67f9d42277ce0c88adb8 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Mon, 17 Oct 2022 19:15:08 -0400 Subject: [PATCH 6/6] bugfix: py contains raises errors when appropiate (#4209) * bugfix: contains now throws an exception if the key is not hashable * Fix tests and improve robustness * Remove todo * Workaround PyPy corner case * PyPy xfail * Fix typo * fix xfail * Make clang-tidy happy * Remove redundant exc checking --- include/pybind11/pytypes.h | 12 ++++++++++-- tests/test_pytypes.cpp | 5 ++++- tests/test_pytypes.py | 25 +++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 4b93d2018..37fc49a0e 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -1967,7 +1967,11 @@ public: void clear() /* py-non-const */ { PyDict_Clear(ptr()); } template bool contains(T &&key) const { - return PyDict_Contains(m_ptr, detail::object_or_cast(std::forward(key)).ptr()) == 1; + auto result = PyDict_Contains(m_ptr, detail::object_or_cast(std::forward(key)).ptr()); + if (result == -1) { + throw error_already_set(); + } + return result == 1; } private: @@ -2053,7 +2057,11 @@ public: bool empty() const { return size() == 0; } template bool contains(T &&val) const { - return PySet_Contains(m_ptr, detail::object_or_cast(std::forward(val)).ptr()) == 1; + auto result = PySet_Contains(m_ptr, detail::object_or_cast(std::forward(val)).ptr()); + if (result == -1) { + throw error_already_set(); + } + return result == 1; } }; diff --git a/tests/test_pytypes.cpp b/tests/test_pytypes.cpp index c95ff8230..99237ccef 100644 --- a/tests/test_pytypes.cpp +++ b/tests/test_pytypes.cpp @@ -183,7 +183,7 @@ TEST_SUBMODULE(pytypes, m) { return d2; }); m.def("dict_contains", - [](const py::dict &dict, py::object val) { return dict.contains(val); }); + [](const py::dict &dict, const py::object &val) { return dict.contains(val); }); m.def("dict_contains", [](const py::dict &dict, const char *val) { return dict.contains(val); }); @@ -538,6 +538,9 @@ TEST_SUBMODULE(pytypes, m) { m.def("hash_function", [](py::object obj) { return py::hash(std::move(obj)); }); + m.def("obj_contains", + [](py::object &obj, const py::object &key) { return obj.contains(key); }); + m.def("test_number_protocol", [](const py::object &a, const py::object &b) { py::list l; l.append(a.equal(b)); diff --git a/tests/test_pytypes.py b/tests/test_pytypes.py index 070849fc5..3ed7b9c94 100644 --- a/tests/test_pytypes.py +++ b/tests/test_pytypes.py @@ -168,6 +168,31 @@ def test_dict(capture, doc): assert m.dict_keyword_constructor() == {"x": 1, "y": 2, "z": 3} +class CustomContains: + d = {"key": None} + + def __contains__(self, m): + return m in self.d + + +@pytest.mark.parametrize( + "arg,func", + [ + (set(), m.anyset_contains), + (dict(), m.dict_contains), + (CustomContains(), m.obj_contains), + ], +) +@pytest.mark.xfail("env.PYPY and sys.pypy_version_info < (7, 3, 10)", strict=False) +def test_unhashable_exceptions(arg, func): + class Unhashable: + __hash__ = None + + with pytest.raises(TypeError) as exc_info: + func(arg, Unhashable()) + assert "unhashable type:" in str(exc_info.value) + + def test_tuple(): assert m.tuple_no_args() == () assert m.tuple_ssize_t() == ()