From 56b49c2be27dbe440f4236a5ca711950aa788e63 Mon Sep 17 00:00:00 2001 From: Jerome Robert Date: Mon, 18 Oct 2021 03:38:41 +0200 Subject: [PATCH 01/11] ci: fix mingw checks by pinning (#3375) * Workaround for https://github.com/msys2/setup-msys2/issues/167 * Adapted from https://github.com/cocotb/cocotb/commit/05036cb24d10579647e81dc1a405b126f711a66f --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5d5222f8b..e337770eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -892,7 +892,8 @@ jobs: - { sys: mingw64, env: x86_64 } - { sys: mingw32, env: i686 } steps: - - uses: msys2/setup-msys2@v2 + # Force version because of https://github.com/msys2/setup-msys2/issues/167 + - uses: msys2/setup-msys2@v2.4.2 with: msystem: ${{matrix.sys}} install: >- From 931f66440f932c62a38e8112ea8ec2f7d962e64a Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Sun, 17 Oct 2021 21:40:10 -0400 Subject: [PATCH 02/11] ci: cancel in-progress on repeated pushes (#3370) --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e337770eb..09b400056 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,10 @@ on: - stable - v* +concurrency: + group: test-${{ github.ref }} + cancel-in-progress: true + jobs: # This is the "main" test suite, which tests a large number of different # versions of default compilers and Python versions in GitHub Actions. From f791dc8648e1f6ec33f402d679b6b116a76d4e1b Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Tue, 19 Oct 2021 14:39:29 -0400 Subject: [PATCH 03/11] fix: deprecate make_simple_namespace, fix Python 3.11 (#3374) * fix: deprecate make_simple_namespace, fix Python 3.11 * docs: update links --- docs/advanced/pycpp/object.rst | 13 +++---------- docs/changelog.rst | 8 ++++++-- docs/upgrade.rst | 13 ++++++++++++- include/pybind11/cast.h | 10 ---------- include/pybind11/pybind11.h | 9 +++++++++ tests/test_pytypes.cpp | 2 +- 6 files changed, 31 insertions(+), 24 deletions(-) diff --git a/docs/advanced/pycpp/object.rst b/docs/advanced/pycpp/object.rst index 8bffb83e1..93e1a94d8 100644 --- a/docs/advanced/pycpp/object.rst +++ b/docs/advanced/pycpp/object.rst @@ -41,24 +41,17 @@ A tuple of python objects can be instantiated using :func:`py::make_tuple`: Each element is converted to a supported Python type. A `simple namespace`_ can be instantiated using -:func:`py::make_simple_namespace`: .. code-block:: cpp - using namespace pybind11::literals; // to bring in the `_a` literal - py::object ns = py::make_simple_namespace("spam"_a=py::none(), "eggs"_a=42); + using namespace pybind11::literals; // to bring in the `_a` literal + py::object SimpleNamespace = py::module_::import("types").attr("SimpleNamespace"); + py::object ns = SimpleNamespace("spam"_a=py::none(), "eggs"_a=42); Attributes on a namespace can be modified with the :func:`py::delattr`, :func:`py::getattr`, and :func:`py::setattr` functions. Simple namespaces can be useful as lightweight stand-ins for class instances. -.. note:: - - ``make_simple_namespace`` is not available in Python 2. - -.. versionchanged:: 2.8 - ``make_simple_namespace`` added. - .. _simple namespace: https://docs.python.org/3/library/types.html#types.SimpleNamespace .. _casting_back_and_forth: diff --git a/docs/changelog.rst b/docs/changelog.rst index 0721020db..ee79a1871 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -10,6 +10,10 @@ Starting with version 1.8.0, pybind11 releases use a `semantic versioning IN DEVELOPMENT -------------- +* The simple namespace creation shortcut added in 2.8.0 was deprecated due to + usage of CPython internal API, and will be removed soon. Use + ``py::module_::import("types").attr("SimpleNamespace")``. + `#3374 `_ v2.8.0 (Oct 4, 2021) @@ -25,10 +29,10 @@ New features: ``register_local_exception_translator(ExceptionTranslator&& translator)`` instead of ``register_exception_translator(ExceptionTranslator&& translator)`` to keep your exception remapping code local to the module. - `#2650 `_ + `#2650 `_ * Add ``make_simple_namespace`` function for instantiating Python - ``SimpleNamespace`` objects. + ``SimpleNamespace`` objects. **Deprecated in 2.8.1.** `#2840 `_ * ``pybind11::scoped_interpreter`` and ``initialize_interpreter`` have new diff --git a/docs/upgrade.rst b/docs/upgrade.rst index b2b6b1245..69609ca28 100644 --- a/docs/upgrade.rst +++ b/docs/upgrade.rst @@ -8,7 +8,17 @@ to a new version. But it goes into more detail. This includes things like deprecated APIs and their replacements, build system changes, general code modernization and other useful information. -.. _upgrade-guide-2.6: +.. _upgrade-guide-2.9: + +v2.9 +==== + +* Any usage of the recently added ``py::make_simple_namespace`` should be + converted to using ``py::module_::import("types").attr("SimpleNamespace")`` + instead. + + +.. _upgrade-guide-2.7: v2.7 ==== @@ -34,6 +44,7 @@ to be common: careful review and custom fixes. +.. _upgrade-guide-2.6: v2.6 ==== diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 1ec2080f8..20fbb3258 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1036,16 +1036,6 @@ template = 0x03030000 -template ()>> -object make_simple_namespace(Args&&... args_) { - PyObject *ns = _PyNamespace_New(dict(std::forward(args_)...).ptr()); - if (!ns) throw error_already_set(); - return reinterpret_steal(ns); -} -#endif - /// \ingroup annotations /// Annotation for arguments struct arg { diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 285f3b18c..095efd9c3 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1124,6 +1124,15 @@ inline dict globals() { return reinterpret_borrow(p ? p : module_::import("__main__").attr("__dict__").ptr()); } +#if PY_VERSION_HEX >= 0x03030000 +template ()>> +PYBIND11_DEPRECATED("make_simple_namespace should be replaced with py::module_::import(\"types\").attr(\"SimpleNamespace\") ") +object make_simple_namespace(Args&&... args_) { + return module_::import("types").attr("SimpleNamespace")(std::forward(args_)...); +} +#endif + PYBIND11_NAMESPACE_BEGIN(detail) /// Generic support for creating new Python heap types class generic_type : public object { diff --git a/tests/test_pytypes.cpp b/tests/test_pytypes.cpp index 2157dc097..9a1e91881 100644 --- a/tests/test_pytypes.cpp +++ b/tests/test_pytypes.cpp @@ -84,7 +84,7 @@ TEST_SUBMODULE(pytypes, m) { #if PY_VERSION_HEX >= 0x03030000 // test_simple_namespace m.def("get_simple_namespace", []() { - auto ns = py::make_simple_namespace("attr"_a=42, "x"_a="foo", "wrong"_a=1); + auto ns = py::module_::import("types").attr("SimpleNamespace")("attr"_a=42, "x"_a="foo", "wrong"_a=1); py::delattr(ns, "wrong"); py::setattr(ns, "right", py::int_(2)); return ns; From 2d6014e417a9be926eb9a3c490570707be35cd42 Mon Sep 17 00:00:00 2001 From: Geoffrey Gunter <12984092+gmgunter@users.noreply.github.com> Date: Thu, 21 Oct 2021 07:37:54 -0700 Subject: [PATCH 04/11] docs: fix minor typo (#3390) --- include/pybind11/numpy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index b7747fae2..b43a77168 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -518,7 +518,7 @@ public: } /// Single-character for dtype's type. - /// For example, ``float`` is 'f', ``double`` 'd', ``int`` 'i', and ``long`` 'd'. + /// For example, ``float`` is 'f', ``double`` 'd', ``int`` 'i', and ``long`` 'l'. char char_() const { // Note: The signature, `dtype::char_` follows the naming of NumPy's // public Python API (i.e., ``dtype.char``), rather than its internal From 606f81a966e56d1ec0f17b0c032e8d6679430d67 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 22 Oct 2021 16:38:40 -0400 Subject: [PATCH 05/11] style: drop pycln (#3397) --- .pre-commit-config.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c6652d836..04166de9a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -61,12 +61,6 @@ repos: hooks: - id: remove-tabs -# Autoremoves unused imports -- repo: https://github.com/hadialqattan/pycln - rev: v1.0.3 - hooks: - - id: pycln - - repo: https://github.com/pre-commit/pygrep-hooks rev: v1.9.0 hooks: From 076c89fc54d3859bb56581555897fda1c621405c Mon Sep 17 00:00:00 2001 From: Dmitry Yershov Date: Fri, 22 Oct 2021 17:09:15 -0400 Subject: [PATCH 06/11] tests: test recursive dispatch using visitor pattern (#3365) --- tests/test_virtual_functions.cpp | 40 ++++++++++++++++++++++++++++++++ tests/test_virtual_functions.py | 33 ++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/tests/test_virtual_functions.cpp b/tests/test_virtual_functions.cpp index 1eba534dd..6e06db9fc 100644 --- a/tests/test_virtual_functions.cpp +++ b/tests/test_virtual_functions.cpp @@ -174,6 +174,25 @@ struct DispatchIssue : Base { } }; +// An abstract adder class that uses visitor pattern to add two data +// objects and send the result to the visitor functor +struct AdderBase { + struct Data {}; + using DataVisitor = std::function; + + virtual void operator()(const Data& first, const Data& second, const DataVisitor& visitor) const = 0; + virtual ~AdderBase() = default; + AdderBase() = default; + AdderBase(const AdderBase&) = delete; +}; + +struct Adder : AdderBase { + void operator()(const Data& first, const Data& second, const DataVisitor& visitor) const override { + PYBIND11_OVERRIDE_PURE_NAME(void, AdderBase, "__call__", operator(), first, second, visitor); + } +}; + + static void test_gil() { { py::gil_scoped_acquire lock; @@ -295,6 +314,27 @@ TEST_SUBMODULE(virtual_functions, m) { m.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); }); + // test_recursive_dispatch_issue + // #3357: Recursive dispatch fails to find python function override + pybind11::class_(m, "Adder") + .def(pybind11::init<>()) + .def("__call__", &AdderBase::operator()); + + pybind11::class_(m, "Data") + .def(pybind11::init<>()); + + m.def("add2", [](const AdderBase::Data& first, const AdderBase::Data& second, + const AdderBase& adder, const AdderBase::DataVisitor& visitor) { + adder(first, second, visitor); + }); + + m.def("add3", [](const AdderBase::Data& first, const AdderBase::Data& second, const AdderBase::Data& third, + const AdderBase& adder, const AdderBase::DataVisitor& visitor) { + adder(first, second, [&] (const AdderBase::Data& first_plus_second) { + adder(first_plus_second, third, visitor); + }); + }); + // test_override_ref // #392/397: overriding reference-returning functions class OverrideTest { diff --git a/tests/test_virtual_functions.py b/tests/test_virtual_functions.py index f7d3bd1e4..0b550992f 100644 --- a/tests/test_virtual_functions.py +++ b/tests/test_virtual_functions.py @@ -257,6 +257,39 @@ def test_dispatch_issue(msg): assert m.dispatch_issue_go(b) == "Yay.." +def test_recursive_dispatch_issue(msg): + """#3357: Recursive dispatch fails to find python function override""" + + class Data(m.Data): + def __init__(self, value): + super(Data, self).__init__() + self.value = value + + class Adder(m.Adder): + def __call__(self, first, second, visitor): + # lambda is a workaround, which adds extra frame to the + # current CPython thread. Removing lambda reveals the bug + # [https://github.com/pybind/pybind11/issues/3357] + (lambda: visitor(Data(first.value + second.value)))() + + class StoreResultVisitor: + def __init__(self): + self.result = None + + def __call__(self, data): + self.result = data.value + + store = StoreResultVisitor() + + m.add2(Data(1), Data(2), Adder(), store) + assert store.result == 3 + + # without lambda in Adder class, this function fails with + # RuntimeError: Tried to call pure virtual function "AdderBase::__call__" + m.add3(Data(1), Data(2), Data(3), Adder(), store) + assert store.result == 6 + + def test_override_ref(): """#392/397: overriding reference-returning functions""" o = m.OverrideTest("asdf") From 78ee782bd494debcbc166f717379a4f9c2093c0f Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Sat, 23 Oct 2021 00:07:22 -0400 Subject: [PATCH 07/11] feat: Add C++ binding to throw AttributeError (#3387) * Add C++ bindings to throw AttributeError * Fix formatting bug --- docs/advanced/exceptions.rst | 4 +++- include/pybind11/detail/common.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/advanced/exceptions.rst b/docs/advanced/exceptions.rst index b4825cbcd..40f67d7b8 100644 --- a/docs/advanced/exceptions.rst +++ b/docs/advanced/exceptions.rst @@ -56,7 +56,9 @@ at its exception handler. +--------------------------------------+--------------------------------------+ | :class:`pybind11::buffer_error` | ``BufferError`` | +--------------------------------------+--------------------------------------+ -| :class:`pybind11::import_error` | ``import_error`` | +| :class:`pybind11::import_error` | ``ImportError`` | ++--------------------------------------+--------------------------------------+ +| :class:`pybind11::attribute_error` | ``AttributeError`` | +--------------------------------------+--------------------------------------+ | Any other exception | ``RuntimeError`` | +--------------------------------------+--------------------------------------+ diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 9ad305a4e..862451fd1 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -831,6 +831,7 @@ PYBIND11_RUNTIME_EXCEPTION(value_error, PyExc_ValueError) PYBIND11_RUNTIME_EXCEPTION(type_error, PyExc_TypeError) PYBIND11_RUNTIME_EXCEPTION(buffer_error, PyExc_BufferError) PYBIND11_RUNTIME_EXCEPTION(import_error, PyExc_ImportError) +PYBIND11_RUNTIME_EXCEPTION(attribute_error, PyExc_AttributeError) PYBIND11_RUNTIME_EXCEPTION(cast_error, PyExc_RuntimeError) /// Thrown when pybind11::cast or handle::call fail due to a type casting error PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used internally From 9379b399d99a784f7e226f135fb117aff6db8013 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 25 Oct 2021 16:01:19 -0400 Subject: [PATCH 08/11] fix: MSVC 2017 C++17 on Python 3 regression (#3407) * fix: MSVC 2017 C++17 on Python 3 regression * ci: add 3.7 job on CI --- .github/workflows/ci.yml | 4 ++++ include/pybind11/functional.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 09b400056..b027640df 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -851,6 +851,10 @@ jobs: std: 17 args: > -DCMAKE_CXX_FLAGS="/permissive- /EHsc /GR" + - python: 3.7 + std: 17 + args: > + -DCMAKE_CXX_FLAGS="/permissive- /EHsc /GR" steps: - uses: actions/checkout@v2 diff --git a/include/pybind11/functional.h b/include/pybind11/functional.h index 24141ce38..ad5608c25 100644 --- a/include/pybind11/functional.h +++ b/include/pybind11/functional.h @@ -69,7 +69,7 @@ public: // ensure GIL is held during functor destruction struct func_handle { function f; -#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17) && PY_MAJOR_VERSION < 3) +#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17)) // This triggers a syntax error under very special conditions (very weird indeed). explicit #endif From d45a88105c3dab1dc2a1da831f1c83a0f3b57f8b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 25 Oct 2021 16:06:13 -0400 Subject: [PATCH 09/11] [pre-commit.ci] pre-commit autoupdate (#3409) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/yesqa: v1.2.3 → v1.3.0](https://github.com/asottile/yesqa/compare/v1.2.3...v1.3.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 04166de9a..b3e517905 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -82,7 +82,7 @@ repos: exclude: ^(docs/.*|tools/.*)$ - repo: https://github.com/asottile/yesqa - rev: v1.2.3 + rev: v1.3.0 hooks: - id: yesqa additional_dependencies: *flake8_dependencies From c2d3e220bd1bfcf664e29d95ac2ed774fd6723f4 Mon Sep 17 00:00:00 2001 From: Ryan Cahoon Date: Mon, 25 Oct 2021 19:04:45 -0700 Subject: [PATCH 10/11] fix: the types for return_value_policy_override in optional_caster (#3376) * fix: the types for return_value_policy_override in optional_caster `return_value_policy_override` was not being applied correctly in `optional_caster` in two ways: - The `is_lvalue_reference` condition referenced `T`, which was the `optional` type parameter from the class, when it should have used `T_`, which was the parameter to the `cast` function. `T_` can potentially be a reference type, but `T` will never be. - The type parameter passed to `return_value_policy_override` should be `T::value_type`, not `T`. This matches the way that the other STL container type casters work. The result of these issues was that a method/property definition which used a `reference` or `reference_internal` return value policy would create a Python value that's bound by reference to a temporary C++ object, resulting in undefined behavior. For reasons that I was not able to figure out fully, it seems like this causes problems when using old versions of `boost::optional`, but not with recent versions of `boost::optional` or the `libstdc++` implementation of `std::optional`. The issue (that the override to `return_value_policy::move` is never being applied) is present for all implementations, it just seems like that somehow doesn't result in problems for the some implementation of `optional`. This change includes a regression type with a custom optional-like type which was able to reproduce the issue. Part of the issue with using the wrong types may have stemmed from the type variables `T` and `T_` having very similar names. This also changes the type variables in `optional_caster` to use slightly more descriptive names, which also more closely follow the naming convention used by the other STL casters. Fixes #3330 * Fix clang-tidy complaints * Add missing NOLINT * Apply a couple more fixes * fix: support GCC 4.8 * tests: avoid warning about unknown compiler for compilers missing C++17 * Remove unneeded test module attribute * Change test enum to have more unique int values Co-authored-by: Aaron Gokaslan Co-authored-by: Henry Schreiner --- include/pybind11/stl.h | 16 ++-- tests/CMakeLists.txt | 6 +- tests/test_stl.cpp | 189 ++++++++++++++++++++++++++++++++++++++++- tests/test_stl.py | 67 +++++++++++++++ 4 files changed, 265 insertions(+), 13 deletions(-) diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h index 2c017b4fe..3608d2989 100644 --- a/include/pybind11/stl.h +++ b/include/pybind11/stl.h @@ -245,17 +245,17 @@ template , Key, Value> { }; // This type caster is intended to be used for std::optional and std::experimental::optional -template struct optional_caster { - using value_conv = make_caster; +template struct optional_caster { + using value_conv = make_caster; - template - static handle cast(T_ &&src, return_value_policy policy, handle parent) { + template + static handle cast(T &&src, return_value_policy policy, handle parent) { if (!src) return none().inc_ref(); if (!std::is_lvalue_reference::value) { - policy = return_value_policy_override::policy(policy); + policy = return_value_policy_override::policy(policy); } - return value_conv::cast(*std::forward(src), policy, parent); + return value_conv::cast(*std::forward(src), policy, parent); } bool load(handle src, bool convert) { @@ -269,11 +269,11 @@ template struct optional_caster { if (!inner_caster.load(src, convert)) return false; - value.emplace(cast_op(std::move(inner_caster))); + value.emplace(cast_op(std::move(inner_caster))); return true; } - PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name + _("]")); + PYBIND11_TYPE_CASTER(Type, _("Optional[") + value_conv::name + _("]")); }; #if defined(PYBIND11_HAS_OPTIONAL) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d4e7b71e1..e1b18dd74 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -256,7 +256,9 @@ if(Boost_FOUND) endif() # Check if we need to add -lstdc++fs or -lc++fs or nothing -if(MSVC) +if(DEFINED CMAKE_CXX_STANDARD AND CMAKE_CXX_STANDARD LESS 17) + set(STD_FS_NO_LIB_NEEDED TRUE) +elseif(MSVC) set(STD_FS_NO_LIB_NEEDED TRUE) else() file( @@ -286,7 +288,7 @@ elseif(${STD_FS_NEEDS_CXXFS}) elseif(${STD_FS_NO_LIB_NEEDED}) set(STD_FS_LIB "") else() - message(WARNING "Unknown compiler - not passing -lstdc++fs") + message(WARNING "Unknown C++17 compiler - not passing -lstdc++fs") set(STD_FS_LIB "") endif() diff --git a/tests/test_stl.cpp b/tests/test_stl.cpp index 7e3363c5e..bc5c6553a 100644 --- a/tests/test_stl.cpp +++ b/tests/test_stl.cpp @@ -19,6 +19,18 @@ #include #include +#if defined(PYBIND11_TEST_BOOST) +#include + +namespace pybind11 { namespace detail { +template +struct type_caster> : optional_caster> {}; + +template <> +struct type_caster : void_caster {}; +}} // namespace pybind11::detail +#endif + // Test with `std::variant` in C++17 mode, or with `boost::variant` in C++11/14 #if defined(PYBIND11_HAS_VARIANT) using std::variant; @@ -59,7 +71,8 @@ namespace std { template