From af08a95b5666cc1fcb6fc74254fd676940462947 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Wed, 2 Mar 2022 14:14:52 -0500 Subject: [PATCH 01/34] fix: potential memory leak in pypy (#3774) --- include/pybind11/pybind11.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 4f6b2cdf4..422d534c1 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -2694,9 +2694,9 @@ get_type_override(const void *this_ptr, const type_info *this_type, const char * d.ptr()); if (result == nullptr) throw error_already_set(); + Py_DECREF(result); if (d["self"].is_none()) return function(); - Py_DECREF(result); #endif return override; From 2dd52544942be4bef80811ef18c8fcf1d3c7e246 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Wed, 2 Mar 2022 15:25:43 -0500 Subject: [PATCH 02/34] fix: missing move in eval.h (#3775) --- include/pybind11/eval.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/pybind11/eval.h b/include/pybind11/eval.h index c157a0095..bd5f981f5 100644 --- a/include/pybind11/eval.h +++ b/include/pybind11/eval.h @@ -82,7 +82,7 @@ template object eval(const char (&s)[N], object global = globals(), object local = object()) { /* Support raw string literals by removing common leading whitespace */ auto expr = (s[0] == '\n') ? str(module_::import("textwrap").attr("dedent")(s)) : str(s); - return eval(expr, global, local); + return eval(expr, std::move(global), std::move(local)); } inline void exec(const str &expr, object global = globals(), object local = object()) { @@ -91,7 +91,7 @@ inline void exec(const str &expr, object global = globals(), object local = obje template void exec(const char (&s)[N], object global = globals(), object local = object()) { - eval(s, global, local); + eval(s, std::move(global), std::move(local)); } #if defined(PYPY_VERSION) From d75b353694709add8bc31a931e123f7736929c94 Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Thu, 10 Mar 2022 10:31:16 -0800 Subject: [PATCH 03/34] CI: MSVC Debug Build (#3784) --- .github/workflows/ci.yml | 54 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 179caa9e8..11c93bafc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -755,6 +755,60 @@ jobs: - name: Python tests run: cmake --build build -t pytest + win32-debug: + strategy: + fail-fast: false + matrix: + python: + - 3.8 + - 3.9 + + include: + - python: 3.9 + args: -DCMAKE_CXX_STANDARD=20 + - python: 3.8 + args: -DCMAKE_CXX_STANDARD=17 + + name: "🐍 ${{ matrix.python }} • MSVC 2019 (Debug) • x86 ${{ matrix.args }}" + runs-on: windows-2019 + + steps: + - uses: actions/checkout@v2 + + - name: Setup Python ${{ matrix.python }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python }} + architecture: x86 + + - name: Update CMake + uses: jwlawson/actions-setup-cmake@v1.12 + + - name: Prepare MSVC + uses: ilammy/msvc-dev-cmd@v1.10.0 + with: + arch: x86 + + - name: Prepare env + run: | + python -m pip install -r tests/requirements.txt + + # First build - C++11 mode and inplace + - name: Configure ${{ matrix.args }} + run: > + cmake -S . -B build + -G "Visual Studio 16 2019" -A Win32 + -DCMAKE_BUILD_TYPE=Debug + -DPYBIND11_WERROR=ON + -DDOWNLOAD_CATCH=ON + -DDOWNLOAD_EIGEN=ON + ${{ matrix.args }} + - name: Build C++11 + run: cmake --build build --config Debug -j 2 + + - name: Python tests + run: cmake --build build --config Debug -t pytest + win32-msvc2017: name: "🐍 ${{ matrix.python }} • MSVC 2017 • x64" runs-on: windows-2016 From 91a6e129d9274a0b10943044e5aeae08471e00fe Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Fri, 11 Mar 2022 14:18:25 -0600 Subject: [PATCH 04/34] PYBIND11_OBJECT_CVT should use namespace for error_already_set() (#3797) * PYBIND11_OBJECT_CVT should use namespace for error_already_set() This change makes the macro usable outside of pybind11 namespace. * added test for use of PYBIND11_OBJECT_CVT for classes in external to pybind11 namespaces * Extended test_pytypes.cpp and test_pytest.py The added test defines a dummy function that takes a custom-defined class external::float_ that uses PYBIND11_OBJECT_CVT * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fixed issues pointed out by CI * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fixed memory leak in default constructor Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- include/pybind11/pytypes.h | 4 ++-- tests/test_pytypes.cpp | 33 +++++++++++++++++++++++++++++++++ tests/test_pytypes.py | 5 +++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index dc753d32c..e54941485 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -1038,12 +1038,12 @@ public: Name(const object &o) \ : Parent(check_(o) ? o.inc_ref().ptr() : ConvertFun(o.ptr()), stolen_t{}) { \ if (!m_ptr) \ - throw error_already_set(); \ + throw ::pybind11::error_already_set(); \ } \ /* NOLINTNEXTLINE(google-explicit-constructor) */ \ Name(object &&o) : Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) { \ if (!m_ptr) \ - throw error_already_set(); \ + throw ::pybind11::error_already_set(); \ } #define PYBIND11_OBJECT_CVT_DEFAULT(Name, Parent, CheckFun, ConvertFun) \ diff --git a/tests/test_pytypes.cpp b/tests/test_pytypes.cpp index 1ed237ea2..b859497b8 100644 --- a/tests/test_pytypes.cpp +++ b/tests/test_pytypes.cpp @@ -11,6 +11,34 @@ #include +namespace external { +namespace detail { +bool check(PyObject *o) { return PyFloat_Check(o) != 0; } + +PyObject *conv(PyObject *o) { + PyObject *ret = nullptr; + if (PyLong_Check(o)) { + double v = PyLong_AsDouble(o); + if (!(v == -1.0 && PyErr_Occurred())) { + ret = PyFloat_FromDouble(v); + } + } else { + PyErr_SetString(PyExc_TypeError, "Unexpected type"); + } + return ret; +} + +PyObject *default_constructed() { return PyFloat_FromDouble(0.0); } +} // namespace detail +class float_ : public py::object { + PYBIND11_OBJECT_CVT(float_, py::object, external::detail::check, external::detail::conv) + + float_() : py::object(external::detail::default_constructed(), stolen_t{}) {} + + double get_value() const { return PyFloat_AsDouble(this->ptr()); } +}; +} // namespace external + TEST_SUBMODULE(pytypes, m) { // test_bool m.def("get_bool", [] { return py::bool_(false); }); @@ -545,4 +573,9 @@ TEST_SUBMODULE(pytypes, m) { py::detail::accessor_policies::tuple_item::set(o, (py::size_t) 0, s0); return o; }); + + m.def("square_float_", [](const external::float_ &x) -> double { + double v = x.get_value(); + return v * v; + }); } diff --git a/tests/test_pytypes.py b/tests/test_pytypes.py index becd1cc8a..85afb9423 100644 --- a/tests/test_pytypes.py +++ b/tests/test_pytypes.py @@ -634,3 +634,8 @@ def test_implementation_details(): assert m.tuple_item_set_ssize_t() == ("emely", "edmond") assert m.tuple_item_get_size_t(tup) == 93 assert m.tuple_item_set_size_t() == ("candy", "cat") + + +def test_external_float_(): + r1 = m.square_float_(2.0) + assert r1 == 4.0 From f8a532a7ded45203cd755d53f0da5f1fadbbea2d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 15 Mar 2022 10:18:12 -0400 Subject: [PATCH 05/34] [pre-commit.ci] pre-commit autoupdate (#3800) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v2.31.0 → v2.31.1](https://github.com/asottile/pyupgrade/compare/v2.31.0...v2.31.1) - [github.com/sirosen/texthooks: 0.2.2 → 0.3.1](https://github.com/sirosen/texthooks/compare/0.2.2...0.3.1) - [github.com/hadialqattan/pycln: v1.2.4 → v1.2.5](https://github.com/hadialqattan/pycln/compare/v1.2.4...v1.2.5) - [github.com/pre-commit/mirrors-mypy: v0.931 → v0.940](https://github.com/pre-commit/mirrors-mypy/compare/v0.931...v0.940) - [github.com/mgedmin/check-manifest: 0.47 → 0.48](https://github.com/mgedmin/check-manifest/compare/0.47...0.48) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e9a0e03f2..c8b527613 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -32,7 +32,7 @@ repos: # Upgrade old Python syntax - repo: https://github.com/asottile/pyupgrade - rev: "v2.31.0" + rev: "v2.31.1" hooks: - id: pyupgrade args: [--py36-plus] @@ -64,14 +64,14 @@ repos: - id: remove-tabs - repo: https://github.com/sirosen/texthooks - rev: "0.2.2" + rev: "0.3.1" hooks: - id: fix-ligatures - id: fix-smartquotes # Autoremoves unused imports - repo: https://github.com/hadialqattan/pycln - rev: "v1.2.4" + rev: "v1.2.5" hooks: - id: pycln @@ -122,7 +122,7 @@ repos: # Check static types with mypy - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v0.931" + rev: "v0.940" hooks: - id: mypy args: [--show-error-codes] @@ -131,7 +131,7 @@ repos: # Checks the manifest for missing files (native support) - repo: https://github.com/mgedmin/check-manifest - rev: "0.47" + rev: "0.48" hooks: - id: check-manifest # This is a slow hook, so only run this if --hook-stage manual is passed From a7e7a6e8460767b70f11b375ea564d3856272260 Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Thu, 17 Mar 2022 11:21:28 -0700 Subject: [PATCH 06/34] Docs: No Strip in Debug (#3779) The docs were not 100% the same as we advertise with our tooling function: most users do not want to strip symbols in Debug builds. --- docs/compiling.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/compiling.rst b/docs/compiling.rst index 4ae9234e1..2b543be0b 100644 --- a/docs/compiling.rst +++ b/docs/compiling.rst @@ -505,7 +505,10 @@ You can use these targets to build complex applications. For example, the target_link_libraries(example PRIVATE pybind11::module pybind11::lto pybind11::windows_extras) pybind11_extension(example) - pybind11_strip(example) + if(NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug|RelWithDebInfo) + # Strip unnecessary sections of the binary on Linux/macOS + pybind11_strip(example) + endif() set_target_properties(example PROPERTIES CXX_VISIBILITY_PRESET "hidden" CUDA_VISIBILITY_PRESET "hidden") From 8b1944d390e9a89f22a1e47d2acbe7c547662aad Mon Sep 17 00:00:00 2001 From: JonTriebenbach <40633432+JonTriebenbach@users.noreply.github.com> Date: Thu, 17 Mar 2022 14:51:16 -0500 Subject: [PATCH 07/34] Remove idioms in code comments (#3809) --- .github/workflows/ci.yml | 2 +- docs/advanced/pycpp/numpy.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 11c93bafc..3523e82c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -667,7 +667,7 @@ jobs: # This verifies that the documentation is not horribly broken, and does a - # basic sanity check on the SDist. + # basic validation check on the SDist. doxygen: name: "Documentation build test" runs-on: ubuntu-latest diff --git a/docs/advanced/pycpp/numpy.rst b/docs/advanced/pycpp/numpy.rst index 8ad341004..b6ef019ed 100644 --- a/docs/advanced/pycpp/numpy.rst +++ b/docs/advanced/pycpp/numpy.rst @@ -87,7 +87,7 @@ buffer objects (e.g. a NumPy matrix). /* Request a buffer descriptor from Python */ py::buffer_info info = b.request(); - /* Some sanity checks ... */ + /* Some basic validation checks ... */ if (info.format != py::format_descriptor::format()) throw std::runtime_error("Incompatible format: expected a double array!"); From b3a43d137c6c9ecf271a2a3d51a51b2fd1c3e8f6 Mon Sep 17 00:00:00 2001 From: Laramie Leavitt Date: Fri, 18 Mar 2022 11:10:31 -0700 Subject: [PATCH 08/34] Use rvalue reference for std::variant cast_op (#3811) Nearly every call site of cast_op uses an r-value reference. Except stl.h variant_caster::load_alternative for handling std::variant. Fix that. --- include/pybind11/stl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h index b66129688..e3a061444 100644 --- a/include/pybind11/stl.h +++ b/include/pybind11/stl.h @@ -372,7 +372,7 @@ struct variant_caster> { bool load_alternative(handle src, bool convert, type_list) { auto caster = make_caster(); if (caster.load(src, convert)) { - value = cast_op(caster); + value = cast_op(std::move(caster)); return true; } return load_alternative(src, convert, type_list{}); From 67089cd3e6ca429faa4d9bf525e4b5ff29ede0d4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 21 Mar 2022 20:47:02 -0400 Subject: [PATCH 09/34] [pre-commit.ci] pre-commit autoupdate (#3817) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v0.940 → v0.941](https://github.com/pre-commit/mirrors-mypy/compare/v0.940...v0.941) 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 c8b527613..01a21e98d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -122,7 +122,7 @@ repos: # Check static types with mypy - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v0.940" + rev: "v0.941" hooks: - id: mypy args: [--show-error-codes] From b22ee64c7309eb7344031b5e5385e6907d84c7eb Mon Sep 17 00:00:00 2001 From: Laramie Leavitt Date: Mon, 21 Mar 2022 22:58:04 -0700 Subject: [PATCH 10/34] Add type_caster (#3818) * Add type_caster for std::variant Add type_caster, allowing std::variant * Add variant test methods * Add std::monostate tests * Update test_stl.py Remove erroneous extra tests * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update test fn name * And update the doc() test Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- include/pybind11/stl.h | 3 +++ tests/test_stl.cpp | 20 ++++++++++++++++++-- tests/test_stl.py | 16 ++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h index e3a061444..3d1ca7ac2 100644 --- a/include/pybind11/stl.h +++ b/include/pybind11/stl.h @@ -406,6 +406,9 @@ struct variant_caster> { #if defined(PYBIND11_HAS_VARIANT) template struct type_caster> : variant_caster> {}; + +template <> +struct type_caster : public void_caster {}; #endif PYBIND11_NAMESPACE_END(detail) diff --git a/tests/test_stl.cpp b/tests/test_stl.cpp index fd1824beb..b56a91953 100644 --- a/tests/test_stl.cpp +++ b/tests/test_stl.cpp @@ -37,9 +37,10 @@ struct type_caster : void_caster {}; // Test with `std::variant` in C++17 mode, or with `boost::variant` in C++11/14 #if defined(PYBIND11_HAS_VARIANT) using std::variant; +# define PYBIND11_TEST_VARIANT 1 #elif defined(PYBIND11_TEST_BOOST) # include -# define PYBIND11_HAS_VARIANT 1 +# define PYBIND11_TEST_VARIANT 1 using boost::variant; namespace pybind11 { @@ -424,7 +425,7 @@ TEST_SUBMODULE(stl, m) { m.def("parent_path", [](const std::filesystem::path &p) { return p.parent_path(); }); #endif -#ifdef PYBIND11_HAS_VARIANT +#ifdef PYBIND11_TEST_VARIANT static_assert(std::is_same::value, "visitor::result_type is required by boost::variant in C++11 mode"); @@ -435,6 +436,9 @@ TEST_SUBMODULE(stl, m) { result_type operator()(const std::string &) { return "std::string"; } result_type operator()(double) { return "double"; } result_type operator()(std::nullptr_t) { return "std::nullptr_t"; } +# if defined(PYBIND11_HAS_VARIANT) + result_type operator()(std::monostate) { return "std::monostate"; } +# endif }; // test_variant @@ -448,6 +452,18 @@ TEST_SUBMODULE(stl, m) { using V = variant; return py::make_tuple(V(5), V("Hello")); }); + +# if defined(PYBIND11_HAS_VARIANT) + // std::monostate tests. + m.def("load_monostate_variant", + [](const variant &v) -> const char * { + return py::detail::visit_helper::call(visitor(), v); + }); + m.def("cast_monostate_variant", []() { + using V = variant; + return py::make_tuple(V{}, V(5), V("Hello")); + }); +# endif #endif // #528: templated constructor diff --git a/tests/test_stl.py b/tests/test_stl.py index a3d686689..3dc55230a 100644 --- a/tests/test_stl.py +++ b/tests/test_stl.py @@ -263,6 +263,22 @@ def test_variant(doc): ) +@pytest.mark.skipif( + not hasattr(m, "load_monostate_variant"), reason="no std::monostate" +) +def test_variant_monostate(doc): + assert m.load_monostate_variant(None) == "std::monostate" + assert m.load_monostate_variant(1) == "int" + assert m.load_monostate_variant("1") == "std::string" + + assert m.cast_monostate_variant() == (None, 5, "Hello") + + assert ( + doc(m.load_monostate_variant) + == "load_monostate_variant(arg0: Union[None, int, str]) -> str" + ) + + def test_vec_of_reference_wrapper(): """#171: Can't return reference wrappers (or STL structures containing them)""" assert ( From 47079b9e7b81a4b6d93c46a452115d7d8fd3488f Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Thu, 24 Mar 2022 12:57:37 -0400 Subject: [PATCH 11/34] (perf): Add missing move in sp matrix caster and microopt char concats (#3823) * Add missing move in sp matrix caster and microopt char concat * Remove useless move * Add a couple more std::move * Missed one char * Improve error_string * Ensure no temp reallocs in errorString concat * Remove useless move --- include/pybind11/detail/type_caster_base.h | 14 +++++++++----- include/pybind11/eigen.h | 5 +++-- include/pybind11/numpy.h | 6 +++--- include/pybind11/pybind11.h | 12 ++++++------ 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h index a4154136a..5b2ec8e1e 100644 --- a/include/pybind11/detail/type_caster_base.h +++ b/include/pybind11/detail/type_caster_base.h @@ -225,8 +225,8 @@ PYBIND11_NOINLINE detail::type_info *get_type_info(const std::type_index &tp, if (throw_if_missing) { std::string tname = tp.name(); detail::clean_type_id(tname); - pybind11_fail("pybind11::detail::get_type_info: unable to find type info for \"" + tname - + "\""); + pybind11_fail("pybind11::detail::get_type_info: unable to find type info for \"" + + std::move(tname) + '"'); } return nullptr; } @@ -512,9 +512,13 @@ PYBIND11_NOINLINE std::string error_string() { Py_INCREF(f_code); # endif int lineno = PyFrame_GetLineNumber(frame); - errorString += " " + handle(f_code->co_filename).cast() + "(" - + std::to_string(lineno) - + "): " + handle(f_code->co_name).cast() + "\n"; + errorString += " "; + errorString += handle(f_code->co_filename).cast(); + errorString += '('; + errorString += std::to_string(lineno); + errorString += "): "; + errorString += handle(f_code->co_name).cast(); + errorString += '\n'; Py_DECREF(f_code); # if PY_VERSION_HEX >= 0x030900B1 auto *b_frame = PyFrame_GetBack(frame); diff --git a/include/pybind11/eigen.h b/include/pybind11/eigen.h index 930c4f7fa..f658168de 100644 --- a/include/pybind11/eigen.h +++ b/include/pybind11/eigen.h @@ -668,7 +668,7 @@ struct type_caster::value>> { Type::Flags &(Eigen::RowMajor | Eigen::ColMajor), StorageIndex>(shape[0].cast(), shape[1].cast(), - nnz, + std::move(nnz), outerIndices.mutable_data(), innerIndices.mutable_data(), values.mutable_data()); @@ -686,7 +686,8 @@ struct type_caster::value>> { array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr()); array innerIndices(src.nonZeros(), src.innerIndexPtr()); - return matrix_type(std::make_tuple(data, innerIndices, outerIndices), + return matrix_type(std::make_tuple( + std::move(data), std::move(innerIndices), std::move(outerIndices)), std::make_pair(src.rows(), src.cols())) .release(); } diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index 5e68f6053..07dea21b4 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -940,7 +940,7 @@ protected: void fail_dim_check(ssize_t dim, const std::string &msg) const { throw index_error(msg + ": " + std::to_string(dim) + " (ndim = " + std::to_string(ndim()) - + ")"); + + ')'); } template @@ -1144,11 +1144,11 @@ struct format_descriptor::value> template struct format_descriptor { - static std::string format() { return std::to_string(N) + "s"; } + static std::string format() { return std::to_string(N) + 's'; } }; template struct format_descriptor> { - static std::string format() { return std::to_string(N) + "s"; } + static std::string format() { return std::to_string(N) + 's'; } }; template diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 422d534c1..fa018b509 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -561,14 +561,14 @@ protected: for (auto *it = chain_start; it != nullptr; it = it->next) { if (options::show_function_signatures()) { if (index > 0) { - signatures += "\n"; + signatures += '\n'; } if (chain) { signatures += std::to_string(++index) + ". "; } signatures += rec->name; signatures += it->signature; - signatures += "\n"; + signatures += '\n'; } if (it->doc && it->doc[0] != '\0' && options::show_user_defined_docstrings()) { // If we're appending another docstring, and aren't printing function signatures, @@ -577,15 +577,15 @@ protected: if (first_user_def) { first_user_def = false; } else { - signatures += "\n"; + signatures += '\n'; } } if (options::show_function_signatures()) { - signatures += "\n"; + signatures += '\n'; } signatures += it->doc; if (options::show_function_signatures()) { - signatures += "\n"; + signatures += '\n'; } } } @@ -1055,7 +1055,7 @@ protected: msg += it2->signature; } - msg += "\n"; + msg += '\n'; } msg += "\nInvoked with: "; auto args_ = reinterpret_borrow(args_in); From 146695a904526adc70c97615f7c395c4b3115c18 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Fri, 25 Mar 2022 10:55:13 -0400 Subject: [PATCH 12/34] fix: better exception and error handling for capsules (#3825) * Make capsule errors better match python --- include/pybind11/numpy.h | 3 ++- include/pybind11/pytypes.h | 32 +++++++++++++++++++------------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index 07dea21b4..7624c9fbf 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -1288,7 +1288,8 @@ public: static pybind11::dtype dtype() { list shape; array_info::append_extents(shape); - return pybind11::dtype::from_args(pybind11::make_tuple(base_descr::dtype(), shape)); + return pybind11::dtype::from_args( + pybind11::make_tuple(base_descr::dtype(), std::move(shape))); } }; diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index e54941485..b9ec8af4e 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -1574,7 +1574,7 @@ public: void (*destructor)(PyObject *) = nullptr) : object(PyCapsule_New(const_cast(value), name, destructor), stolen_t{}) { if (!m_ptr) { - pybind11_fail("Could not allocate capsule object!"); + throw error_already_set(); } } @@ -1582,34 +1582,42 @@ public: capsule(const void *value, void (*destruct)(PyObject *)) : object(PyCapsule_New(const_cast(value), nullptr, destruct), stolen_t{}) { if (!m_ptr) { - pybind11_fail("Could not allocate capsule object!"); + throw error_already_set(); } } capsule(const void *value, void (*destructor)(void *)) { m_ptr = PyCapsule_New(const_cast(value), nullptr, [](PyObject *o) { auto destructor = reinterpret_cast(PyCapsule_GetContext(o)); + if (destructor == nullptr) { + if (PyErr_Occurred()) { + throw error_already_set(); + } + pybind11_fail("Unable to get capsule context"); + } void *ptr = PyCapsule_GetPointer(o, nullptr); + if (ptr == nullptr) { + throw error_already_set(); + } destructor(ptr); }); - if (!m_ptr) { - pybind11_fail("Could not allocate capsule object!"); - } - - if (PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) { - pybind11_fail("Could not set capsule context!"); + if (!m_ptr || PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) { + throw error_already_set(); } } explicit capsule(void (*destructor)()) { m_ptr = PyCapsule_New(reinterpret_cast(destructor), nullptr, [](PyObject *o) { auto destructor = reinterpret_cast(PyCapsule_GetPointer(o, nullptr)); + if (destructor == nullptr) { + throw error_already_set(); + } destructor(); }); if (!m_ptr) { - pybind11_fail("Could not allocate capsule object!"); + throw error_already_set(); } } @@ -1624,8 +1632,7 @@ public: const auto *name = this->name(); T *result = static_cast(PyCapsule_GetPointer(m_ptr, name)); if (!result) { - PyErr_Clear(); - pybind11_fail("Unable to extract capsule contents!"); + throw error_already_set(); } return result; } @@ -1633,8 +1640,7 @@ public: /// Replaces a capsule's pointer *without* calling the destructor on the existing one. void set_pointer(const void *value) { if (PyCapsule_SetPointer(m_ptr, const_cast(value)) != 0) { - PyErr_Clear(); - pybind11_fail("Could not set capsule pointer"); + throw error_already_set(); } } From 461937d3e545136f48adc08c8cb80dff4c5994cf Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 25 Mar 2022 12:34:32 -0400 Subject: [PATCH 13/34] ci: test pypy 3.9 (#3789) * ci: test pypy 3.9 * ci: try a use of FindPython with PyPy --- .github/workflows/ci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3523e82c0..78f39b0c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,6 +32,7 @@ jobs: - '3.10' - 'pypy-3.7' - 'pypy-3.8' + - 'pypy-3.9' # 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 @@ -45,6 +46,10 @@ jobs: args: > -DPYBIND11_FINDPYTHON=ON -DCMAKE_CXX_FLAGS="-D_=1" + - runs-on: ubuntu-latest + python: 'pypy-3.9' + args: > + -DPYBIND11_FINDPYTHON=ON - runs-on: windows-2019 python: '3.6' args: > From 7742be02d9d1231c7b541c44a32c4f0921c6f7f9 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 25 Mar 2022 14:54:43 -0400 Subject: [PATCH 14/34] Revert "ci: test pypy 3.9" (#3828) * Revert "ci: test pypy 3.9 (#3789)" This reverts commit 461937d3e545136f48adc08c8cb80dff4c5994cf. * Update ci.yml --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 78f39b0c1..b2fc52bf2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,7 +47,7 @@ jobs: -DPYBIND11_FINDPYTHON=ON -DCMAKE_CXX_FLAGS="-D_=1" - runs-on: ubuntu-latest - python: 'pypy-3.9' + python: 'pypy-3.8' args: > -DPYBIND11_FINDPYTHON=ON - runs-on: windows-2019 From 3a183d4b587841fb868cee23df7bfe0afe893bb8 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Fri, 25 Mar 2022 16:01:34 -0400 Subject: [PATCH 15/34] fix: improve str exceptions and consistency with python (#3826) * Improve str exceptions * Revert macro change just in case * Make clang-tidy happy * Fix one more clang-tidy issue * Refactor duplicate method --- include/pybind11/pytypes.h | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index b9ec8af4e..18cd71580 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -1243,8 +1243,8 @@ public: } char *buffer = nullptr; ssize_t length = 0; - if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) { - pybind11_fail("Unable to extract string contents! (invalid type)"); + if (PyBytes_AsStringAndSize(temp.ptr(), &buffer, &length) != 0) { + throw error_already_set(); } return std::string(buffer, (size_t) length); } @@ -1299,14 +1299,7 @@ public: explicit bytes(const pybind11::str &s); // NOLINTNEXTLINE(google-explicit-constructor) - operator std::string() const { - char *buffer = nullptr; - ssize_t length = 0; - if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length)) { - pybind11_fail("Unable to extract bytes contents!"); - } - return std::string(buffer, (size_t) length); - } + operator std::string() const { return string_op(); } #ifdef PYBIND11_HAS_STRING_VIEW // enable_if is needed to avoid "ambiguous conversion" errors (see PR #3521). @@ -1318,15 +1311,18 @@ public: // valid so long as the `bytes` instance remains alive and so generally should not outlive the // lifetime of the `bytes` instance. // NOLINTNEXTLINE(google-explicit-constructor) - operator std::string_view() const { + operator std::string_view() const { return string_op(); } +#endif +private: + template + T string_op() const { char *buffer = nullptr; ssize_t length = 0; - if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length)) { - pybind11_fail("Unable to extract bytes contents!"); + if (PyBytes_AsStringAndSize(m_ptr, &buffer, &length) != 0) { + throw error_already_set(); } return {buffer, static_cast(length)}; } -#endif }; // Note: breathe >= 4.17.0 will fail to build docs if the below two constructors // are included in the doxygen group; close here and reopen after as a workaround @@ -1337,13 +1333,13 @@ inline bytes::bytes(const pybind11::str &s) { if (PyUnicode_Check(s.ptr())) { temp = reinterpret_steal(PyUnicode_AsUTF8String(s.ptr())); if (!temp) { - pybind11_fail("Unable to extract string contents! (encoding issue)"); + throw error_already_set(); } } char *buffer = nullptr; ssize_t length = 0; - if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) { - pybind11_fail("Unable to extract string contents! (invalid type)"); + if (PyBytes_AsStringAndSize(temp.ptr(), &buffer, &length) != 0) { + throw error_already_set(); } auto obj = reinterpret_steal(PYBIND11_BYTES_FROM_STRING_AND_SIZE(buffer, length)); if (!obj) { @@ -1355,8 +1351,8 @@ inline bytes::bytes(const pybind11::str &s) { inline str::str(const bytes &b) { char *buffer = nullptr; ssize_t length = 0; - if (PYBIND11_BYTES_AS_STRING_AND_SIZE(b.ptr(), &buffer, &length)) { - pybind11_fail("Unable to extract bytes contents!"); + if (PyBytes_AsStringAndSize(b.ptr(), &buffer, &length) != 0) { + throw error_already_set(); } auto obj = reinterpret_steal(PyUnicode_FromStringAndSize(buffer, length)); if (!obj) { From 42d8593ad4225a634b481cd573f7aeb94de72418 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 28 Mar 2022 17:24:59 -0400 Subject: [PATCH 16/34] style: bump black (#3831) * style: bump black Signed-off-by: Henry Schreiner * fix: pycln broken by typer breakage --- .pre-commit-config.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 01a21e98d..6a00f2fce 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -45,7 +45,7 @@ repos: # Black, the code formatter, natively supports pre-commit - repo: https://github.com/psf/black - rev: "22.1.0" # Keep in sync with blacken-docs + rev: "22.3.0" # Keep in sync with blacken-docs hooks: - id: black @@ -55,7 +55,7 @@ repos: hooks: - id: blacken-docs additional_dependencies: - - black==22.1.0 # keep in sync with black hook + - black==22.3.0 # keep in sync with black hook # Changes tabs to spaces - repo: https://github.com/Lucas-C/pre-commit-hooks @@ -74,6 +74,8 @@ repos: rev: "v1.2.5" hooks: - id: pycln + additional_dependencies: [click<8.1] # Unpin when typer updates + stages: [manual] # Checking for common mistakes - repo: https://github.com/pre-commit/pygrep-hooks @@ -106,7 +108,7 @@ repos: # PyLint has native support - not always usable, but works for us - repo: https://github.com/PyCQA/pylint - rev: "v2.12.2" + rev: "v2.13.2" hooks: - id: pylint files: ^pybind11 @@ -122,7 +124,7 @@ repos: # Check static types with mypy - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v0.941" + rev: "v0.942" hooks: - id: mypy args: [--show-error-codes] From 65ec5de52fecc974157a0c28490fef61204c39a1 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Wed, 30 Mar 2022 23:02:00 -0400 Subject: [PATCH 17/34] chore: bump changelog for 2.9.2 (#3834) * chore: bump changelog for 2.9.2 Signed-off-by: Henry Schreiner * Update docs/changelog.rst --- docs/changelog.rst | 121 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 9d7693cdd..67ac79cdd 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -6,10 +6,129 @@ Changelog Starting with version 1.8.0, pybind11 releases use a `semantic versioning `_ policy. +Changes will be added here periodically from the "Suggested changelog entry" +block in pull request descriptions. + IN DEVELOPMENT -------------- -Changes will be added here periodically. +Removed support for Python 2.7, Python 3.5, and MSVC 2015. Support for MSVC +2017 is limited due to availability of CI runners; we highly recommend MSVC +2019 or 2022 be used. + +New features: + +* ``type_caster`` was added. ``std::monostate`` is a tag type + that allows ``std::variant`` to act as an optional, or allows default + construction of a ``std::variant`` holding a non-default constructible type. + `#3818 `_ + +* Support bytearray casting to string. + `#3707 `_ + +Changes: + +* Python 2 support was removed completely. + `#3688 `_ + +* The minimum version for MSVC is now 2017. + `#3722 `_ + +* Improve exception handling in python ``str`` bindings. + `#3826 `_ + +* The bindings for capsules now have more consistent exception handling. + `#3825 `_ + +* Fix exception handling when ``pybind11::weakref()`` fails. + `#3739 `_ + + +Bug fixes: + +* ``PYBIND11_OBJECT_CVT`` and ``PYBIND11_OBJECT_CVT_DEFAULT`` macro can be used + to define classes in namespaces other than pybind11. + `#3797 `_ + +Build system improvements: + +* Add MSVC builds in debug mode to CI. + `#3784 `_ + +* MSVC 2022 C++20 coverage was added to GitHub Actions, including Eigen. + `#3732 `_, + `#3741 `_ + +* Avoid ``setup.py `` usage in internal tests. + `#3734 `_ + + +Backend and tidying up: + +* Remove idioms in code comments. Use inclusive language. + `#3809 `_ + + +Version 2.9.2 (Mar 29, 2022) +---------------------------- + +Changes: + +* Enum now has an ``__index__`` method on Python <3.8 too. + `#3700 `_ + +* Local internals are now cleared after finalizing the interpreter. + `#3744 `_ + +Bug fixes: + +* Better support for Python 3.11 alphas. + `#3694 `_ + +* ``PYBIND11_TYPE_CASTER`` now uses fully qualified symbols, so it can be used + outside of ``pybind11::detail``. + `#3758 `_ + +* Some fixes for PyPy 3.9. + `#3768 `_ + +* Fixed a potential memleak in PyPy in ``get_type_override``. + `#3774 `_ + +* Fix usage of ``VISIBILITY_INLINES_HIDDEN``. + `#3721 `_ + + +Build system improvements: + +* Uses ``sysconfig`` module to determine installation locations on Python >= + 3.10, instead of ``distutils`` which has been deprecated. + `#3764 `_ + +* Support Catch 2.13.5+ (supporting GLIBC 2.34+). + `#3679 `_ + +* Fix test failures with numpy 1.22 by ignoring whitespace when comparing + ``str()`` of dtypes. + `#3682 `_ + + +Backend and tidying up: + +* clang-tidy: added ``readability-qualified-auto``, + ``readability-braces-around-statements``, + ``cppcoreguidelines-prefer-member-initializer``, + ``clang-analyzer-optin.performance.Padding``, + ``cppcoreguidelines-pro-type-static-cast-downcast``, and + ``readability-inconsistent-declaration-parameter-name``. + `#3702 `_, + `#3699 `_, + `#3716 `_, + `#3709 `_ + +* clang-format was added to the pre-commit actions, and the entire code base + automatically reformatted (after several iterations preparing for this leap). + `#3713 `_ Version 2.9.1 (Feb 2, 2022) From b3ebd11d9851007f525e2e41de53b7913b24787c Mon Sep 17 00:00:00 2001 From: "Lonnie L. Souder II" Date: Fri, 1 Apr 2022 01:16:10 -0400 Subject: [PATCH 18/34] feature: support compilers that use std::experimental::filesystem (#3840) * feature: support compilers that use std::experimental::filesystem such as gcc7 * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * only use this feature if cpp17 * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * more specific namespace alias + style * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * move to pybind11 namespace * no namespace alias * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Co-authored-by: Lonnie Souder II Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- include/pybind11/stl/filesystem.h | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/include/pybind11/stl/filesystem.h b/include/pybind11/stl/filesystem.h index 93727424c..e26f42177 100644 --- a/include/pybind11/stl/filesystem.h +++ b/include/pybind11/stl/filesystem.h @@ -13,21 +13,28 @@ #include #ifdef __has_include -# if defined(PYBIND11_CPP17) && __has_include() -# include -# define PYBIND11_HAS_FILESYSTEM 1 +# if defined(PYBIND11_CPP17) +# if __has_include() && \ + PY_VERSION_HEX >= 0x03060000 +# include +# define PYBIND11_HAS_FILESYSTEM 1 +# elif __has_include() +# include +# define PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM 1 +# endif # endif #endif -#if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL) +#if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM) \ + && !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL) # error \ - "#include is not available. (Use -DPYBIND11_HAS_FILESYSTEM_IS_OPTIONAL to ignore.)" + "Neither #include nor #include struct path_caster { @@ -94,9 +101,16 @@ public: PYBIND11_TYPE_CASTER(T, const_name("os.PathLike")); }; +#endif // PYBIND11_HAS_FILESYSTEM || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM) + +#if defined(PYBIND11_HAS_FILESYSTEM) template <> struct type_caster : public path_caster {}; -#endif // PYBIND11_HAS_FILESYSTEM +#elif defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM) +template <> +struct type_caster + : public path_caster {}; +#endif PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) From f2f0c69096f913f99d59dcde7258ab9c95f08d44 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Apr 2022 17:56:42 -0400 Subject: [PATCH 19/34] [pre-commit.ci] pre-commit autoupdate (#3848) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/pylint: v2.13.2 → v2.13.4](https://github.com/PyCQA/pylint/compare/v2.13.2...v2.13.4) 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 6a00f2fce..9ff2013ed 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -108,7 +108,7 @@ repos: # PyLint has native support - not always usable, but works for us - repo: https://github.com/PyCQA/pylint - rev: "v2.13.2" + rev: "v2.13.4" hooks: - id: pylint files: ^pybind11 From c4e295287b74c0b3f0f8a304cdb746ac2bcb37ad Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Tue, 5 Apr 2022 14:36:39 -0400 Subject: [PATCH 20/34] perf: Add more moves and optimize (#3845) * Make slice constructor consistent * Add more missing std::move for ref steals * Add missing perfect forwarding for arg_v ctor * Add missing move in arg_v constructor * Revert "Add missing move in arg_v constructor" This reverts commit 126fc7c524ea7a51b54720defd75de3470d69557. * Add another missing move in cast.h * Optimize object move ctor * Don't do useless move * Make move ctor same as nb * Make obj move ctor same as nb * Revert changes which break MSVC --- include/pybind11/cast.h | 6 +++--- include/pybind11/numpy.h | 6 +++--- include/pybind11/pytypes.h | 9 +++------ include/pybind11/stl.h | 2 +- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index d45b49c52..07a56e71f 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1243,8 +1243,8 @@ struct arg_v : arg { private: template arg_v(arg &&base, T &&x, const char *descr = nullptr) - : arg(base), value(reinterpret_steal( - detail::make_caster::cast(x, return_value_policy::automatic, {}))), + : arg(base), value(reinterpret_steal(detail::make_caster::cast( + std::forward(x), return_value_policy::automatic, {}))), descr(descr) #if !defined(NDEBUG) , @@ -1491,7 +1491,7 @@ private: type_id()); #endif } - args_list.append(o); + args_list.append(std::move(o)); } void process(list &args_list, detail::args_proxy ap) { diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index 7624c9fbf..d45fe4280 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -640,9 +640,9 @@ private: list names, formats, offsets; for (auto &descr : field_descriptors) { - names.append(descr.name); - formats.append(descr.format); - offsets.append(descr.offset); + names.append(std::move(descr.name)); + formats.append(std::move(descr.format)); + offsets.append(std::move(descr.offset)); } return dtype(std::move(names), std::move(formats), std::move(offsets), itemsize); } diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 18cd71580..ba0fda0a8 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -268,10 +268,7 @@ public: /// Copy constructor; always increases the reference count object(const object &o) : handle(o) { inc_ref(); } /// Move constructor; steals the object from ``other`` and preserves its reference count - object(object &&other) noexcept { - m_ptr = other.m_ptr; - other.m_ptr = nullptr; - } + object(object &&other) noexcept : handle(other) { other.m_ptr = nullptr; } /// Destructor; automatically calls `handle::dec_ref()` ~object() { dec_ref(); } @@ -1519,8 +1516,8 @@ private: class slice : public object { public: PYBIND11_OBJECT_DEFAULT(slice, object, PySlice_Check) - slice(handle start, handle stop, handle step) { - m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr()); + slice(handle start, handle stop, handle step) + : object(PySlice_New(start.ptr(), stop.ptr(), step.ptr()), stolen_t{}) { if (!m_ptr) { pybind11_fail("Could not allocate slice object!"); } diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h index 3d1ca7ac2..51b57a92b 100644 --- a/include/pybind11/stl.h +++ b/include/pybind11/stl.h @@ -79,7 +79,7 @@ struct set_caster { for (auto &&value : src) { auto value_ = reinterpret_steal( key_conv::cast(forward_like(value), policy, parent)); - if (!value_ || !s.add(value_)) { + if (!value_ || !s.add(std::move(value_))) { return handle(); } } From ab59f45d2ee05b1df299021b62ab1f59a768e285 Mon Sep 17 00:00:00 2001 From: Laramie Leavitt Date: Mon, 11 Apr 2022 10:36:24 -0700 Subject: [PATCH 21/34] Prefer make_caster to type_caster (#3859) --- include/pybind11/cast.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 07a56e71f..bead97f91 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -514,7 +514,7 @@ struct type_caster, template struct type_caster::value>> { using StringType = std::basic_string; - using StringCaster = type_caster; + using StringCaster = make_caster; StringCaster str_caster; bool none = false; CharT one_char = 0; From 1b27b744c151bfa2db60566112b4d8307cb05104 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Mon, 11 Apr 2022 13:53:30 -0400 Subject: [PATCH 22/34] chore: Make stl_bind take slice as const_ref (#3852) * Make stl_bind take slice as const_ref * Change eval order if * Silence MSVC warning --- include/pybind11/pybind11.h | 3 ++- include/pybind11/stl_bind.h | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index fa018b509..797c769d7 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1817,7 +1817,8 @@ private: if (holder_ptr) { init_holder_from_existing(v_h, holder_ptr, std::is_copy_constructible()); v_h.set_holder_constructed(); - } else if (inst->owned || detail::always_construct_holder::value) { + } else if (PYBIND11_SILENCE_MSVC_C4127(detail::always_construct_holder::value) + || inst->owned) { new (std::addressof(v_h.holder())) holder_type(v_h.value_ptr()); v_h.set_holder_constructed(); } diff --git a/include/pybind11/stl_bind.h b/include/pybind11/stl_bind.h index 3a3e54dd4..22a29b476 100644 --- a/include/pybind11/stl_bind.h +++ b/include/pybind11/stl_bind.h @@ -232,7 +232,7 @@ void vector_modifiers( /// Slicing protocol cl.def( "__getitem__", - [](const Vector &v, slice slice) -> Vector * { + [](const Vector &v, const slice &slice) -> Vector * { size_t start = 0, stop = 0, step = 0, slicelength = 0; if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) { @@ -253,7 +253,7 @@ void vector_modifiers( cl.def( "__setitem__", - [](Vector &v, slice slice, const Vector &value) { + [](Vector &v, const slice &slice, const Vector &value) { size_t start = 0, stop = 0, step = 0, slicelength = 0; if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) { throw error_already_set(); @@ -281,7 +281,7 @@ void vector_modifiers( cl.def( "__delitem__", - [](Vector &v, slice slice) { + [](Vector &v, const slice &slice) { size_t start = 0, stop = 0, step = 0, slicelength = 0; if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) { From e3aa215b020886d648add951186052c619c3cf9d Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Mon, 11 Apr 2022 14:03:43 -0400 Subject: [PATCH 23/34] Add perfect forwarding to make_iterator calls (#3860) --- include/pybind11/pybind11.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 797c769d7..97275e40a 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -2403,7 +2403,8 @@ template iterator make_iterator(Type &value, Extra &&...extra) { - return make_iterator(std::begin(value), std::end(value), extra...); + return make_iterator( + std::begin(value), std::end(value), std::forward(extra)...); } /// Makes an iterator over the keys (`.first`) of a stl map-like container supporting @@ -2412,7 +2413,8 @@ template iterator make_key_iterator(Type &value, Extra &&...extra) { - return make_key_iterator(std::begin(value), std::end(value), extra...); + return make_key_iterator( + std::begin(value), std::end(value), std::forward(extra)...); } /// Makes an iterator over the values (`.second`) of a stl map-like container supporting @@ -2421,7 +2423,8 @@ template iterator make_value_iterator(Type &value, Extra &&...extra) { - return make_value_iterator(std::begin(value), std::end(value), extra...); + return make_value_iterator( + std::begin(value), std::end(value), std::forward(extra)...); } template From 088ad4f2987d3da4b1ffab376b2b4812fd7634ef Mon Sep 17 00:00:00 2001 From: Laramie Leavitt Date: Mon, 11 Apr 2022 11:57:05 -0700 Subject: [PATCH 24/34] Cleanup cast_safe specialization (#3861) * Cleanup cast_safe specialization Replace explicit specialization of cast_safe with SFINAE. It's better for SFINAE cases to cover all type-sets rather than mixing SFINAE and explicit specialization. Extracted from #3674 * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update cast.h Use detail::none_of<> as suggested * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update cast.h Reorder: If TEMP_REF If VOID if (!VOID && !TEMP_REF) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- include/pybind11/cast.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index bead97f91..e8128710e 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1155,15 +1155,18 @@ enable_if_t::value, T> cast_ref(object &&, // static_assert, even though if it's in dead code, so we provide a "trampoline" to pybind11::cast // that only does anything in cases where pybind11::cast is valid. template -enable_if_t::value, T> cast_safe(object &&o) { - return pybind11::cast(std::move(o)); -} -template enable_if_t::value, T> cast_safe(object &&) { pybind11_fail("Internal error: cast_safe fallback invoked"); } -template <> -inline void cast_safe(object &&) {} +template +enable_if_t>::value, void> cast_safe(object &&) {} +template +enable_if_t, + std::is_same>>::value, + T> +cast_safe(object &&o) { + return pybind11::cast(std::move(o)); +} PYBIND11_NAMESPACE_END(detail) From 9969f3b5b5ccad5524a9dab237b551c0ea6359f4 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 11 Apr 2022 16:54:33 -0400 Subject: [PATCH 25/34] ci: drop win2016 (#3854) * ci: drop dead windows CI jobs * chore: touch up pre-commit Signed-off-by: Henry Schreiner * Update configure.yml * Update configure.yml --- .github/workflows/ci.yml | 49 --------------------------------- .github/workflows/configure.yml | 10 ++----- .pre-commit-config.yaml | 3 +- pyproject.toml | 4 ++- 4 files changed, 7 insertions(+), 59 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b2fc52bf2..0e018fb7f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -814,55 +814,6 @@ jobs: - name: Python tests run: cmake --build build --config Debug -t pytest - win32-msvc2017: - name: "🐍 ${{ matrix.python }} • MSVC 2017 • x64" - runs-on: windows-2016 - strategy: - fail-fast: false - matrix: - python: - - 3.6 - - 3.7 - std: - - 14 - - include: - - python: 3.7 - std: 17 - args: > - -DCMAKE_CXX_FLAGS="/permissive- /EHsc /GR" - - steps: - - uses: actions/checkout@v2 - - - name: Setup 🐍 ${{ matrix.python }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python }} - - - name: Update CMake - uses: jwlawson/actions-setup-cmake@v1.12 - - - name: Prepare env - run: | - python -m pip install -r tests/requirements.txt - - # First build - C++11 mode and inplace - - name: Configure - run: > - cmake -S . -B build - -G "Visual Studio 15 2017" -A x64 - -DPYBIND11_WERROR=ON - -DDOWNLOAD_CATCH=ON - -DDOWNLOAD_EIGEN=ON - -DCMAKE_CXX_STANDARD=${{ matrix.std }} - ${{ matrix.args }} - - - name: Build ${{ matrix.std }} - run: cmake --build build -j 2 - - - name: Run all checks - run: cmake --build build -t check windows-2022: strategy: diff --git a/.github/workflows/configure.yml b/.github/workflows/configure.yml index 66ab0e3d7..55be5bd34 100644 --- a/.github/workflows/configure.yml +++ b/.github/workflows/configure.yml @@ -18,7 +18,7 @@ jobs: matrix: runs-on: [ubuntu-latest, macos-latest, windows-latest] arch: [x64] - cmake: ["3.21"] + cmake: ["3.23"] include: - runs-on: ubuntu-latest @@ -29,12 +29,8 @@ jobs: arch: x64 cmake: 3.7 - - runs-on: windows-2016 - arch: x86 - cmake: 3.8 - - - runs-on: windows-2016 - arch: x86 + - runs-on: windows-2019 + arch: x64 # x86 compilers seem to be missing on 2019 image cmake: 3.18 name: 🐍 3.7 • CMake ${{ matrix.cmake }} • ${{ matrix.runs-on }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9ff2013ed..2bfd699a6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -74,7 +74,6 @@ repos: rev: "v1.2.5" hooks: - id: pycln - additional_dependencies: [click<8.1] # Unpin when typer updates stages: [manual] # Checking for common mistakes @@ -127,7 +126,7 @@ repos: rev: "v0.942" hooks: - id: mypy - args: [--show-error-codes] + args: [] exclude: ^(tests|docs)/ additional_dependencies: [nox, rich] diff --git a/pyproject.toml b/pyproject.toml index f80cdc1f4..3ba1b4b22 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,8 +24,10 @@ profile = "black" [tool.mypy] files = ["pybind11"] python_version = "3.6" -warn_unused_configs = true strict = true +show_error_codes = true +enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] +warn_unreachable = true [[tool.mypy.overrides]] module = ["ghapi.*", "setuptools.*"] From ad0de0f5a6bebbebbeb7f8f2f15c0c1430f34268 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 11 Apr 2022 19:50:42 -0400 Subject: [PATCH 26/34] [pre-commit.ci] pre-commit autoupdate (#3863) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.1.0 → v4.2.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.1.0...v4.2.0) - [github.com/asottile/pyupgrade: v2.31.1 → v2.32.0](https://github.com/asottile/pyupgrade/compare/v2.31.1...v2.32.0) - [github.com/PyCQA/pylint: v2.13.4 → v2.13.5](https://github.com/PyCQA/pylint/compare/v2.13.4...v2.13.5) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2bfd699a6..9cfcef21f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: # Standard hooks - repo: https://github.com/pre-commit/pre-commit-hooks - rev: "v4.1.0" + rev: "v4.2.0" hooks: - id: check-added-large-files - id: check-case-conflict @@ -32,7 +32,7 @@ repos: # Upgrade old Python syntax - repo: https://github.com/asottile/pyupgrade - rev: "v2.31.1" + rev: "v2.32.0" hooks: - id: pyupgrade args: [--py36-plus] @@ -107,7 +107,7 @@ repos: # PyLint has native support - not always usable, but works for us - repo: https://github.com/PyCQA/pylint - rev: "v2.13.4" + rev: "v2.13.5" hooks: - id: pylint files: ^pybind11 From fa98804a07982cef41d554ff96f71334bac92445 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Thu, 14 Apr 2022 09:51:27 -0500 Subject: [PATCH 27/34] Adds set_name method of pybind11::capsule class (#3866) * Adds set_name method of pybind11::capsule class This calls PyCapsule_SetName on the underlying capsule object. modified destructors to query capsules's Name [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Handle possible exception thrown by PyCapsule_GetName Also removed accidentally reintroduced use of `const char *&`. [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Fixed function name * Introduced private static function to reuse get_name_or_throw * added tests for capsule renaming * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * handle python error in flight * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Initialized PyObject * variables to nullptr * use write-unraisable if PyCapsule_GetName raises * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * get_name_or_throw->get_name_no_throw If PyCapsule_GetName raises an error we should write as unraisable to consume it and notify user, and then restore the error in flight if any. This way this method called from destructor would not modify interpreter error state. * used error_scope struct * Renamed get_name_no_throw->get_name_in_error_scope Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- include/pybind11/pytypes.h | 34 +++++++++++++++++++++++++++++++--- tests/test_pytypes.cpp | 20 ++++++++++++++++++++ tests/test_pytypes.py | 26 ++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index ba0fda0a8..7d52774c8 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -1588,7 +1588,8 @@ public: } pybind11_fail("Unable to get capsule context"); } - void *ptr = PyCapsule_GetPointer(o, nullptr); + const char *name = get_name_in_error_scope(o); + void *ptr = PyCapsule_GetPointer(o, name); if (ptr == nullptr) { throw error_already_set(); } @@ -1602,7 +1603,8 @@ public: explicit capsule(void (*destructor)()) { m_ptr = PyCapsule_New(reinterpret_cast(destructor), nullptr, [](PyObject *o) { - auto destructor = reinterpret_cast(PyCapsule_GetPointer(o, nullptr)); + const char *name = get_name_in_error_scope(o); + auto destructor = reinterpret_cast(PyCapsule_GetPointer(o, name)); if (destructor == nullptr) { throw error_already_set(); } @@ -1637,7 +1639,33 @@ public: } } - const char *name() const { return PyCapsule_GetName(m_ptr); } + const char *name() const { + const char *name = PyCapsule_GetName(m_ptr); + if ((name == nullptr) && PyErr_Occurred()) { + throw error_already_set(); + } + return name; + } + + /// Replaces a capsule's name *without* calling the destructor on the existing one. + void set_name(const char *new_name) { + if (PyCapsule_SetName(m_ptr, new_name) != 0) { + throw error_already_set(); + } + } + +private: + static const char *get_name_in_error_scope(PyObject *o) { + error_scope error_guard; + + const char *name = PyCapsule_GetName(o); + if ((name == nullptr) && PyErr_Occurred()) { + // write out and consume error raised by call to PyCapsule_GetName + PyErr_WriteUnraisable(o); + } + + return name; + } }; class tuple : public object { diff --git a/tests/test_pytypes.cpp b/tests/test_pytypes.cpp index b859497b8..d1e9b81a7 100644 --- a/tests/test_pytypes.cpp +++ b/tests/test_pytypes.cpp @@ -159,6 +159,15 @@ TEST_SUBMODULE(pytypes, m) { return py::capsule([]() { py::print("destructing capsule"); }); }); + m.def("return_renamed_capsule_with_destructor", []() { + py::print("creating capsule"); + auto cap = py::capsule([]() { py::print("destructing capsule"); }); + static const char *capsule_name = "test_name1"; + py::print("renaming capsule"); + cap.set_name(capsule_name); + return cap; + }); + m.def("return_capsule_with_destructor_2", []() { py::print("creating capsule"); return py::capsule((void *) 1234, [](void *ptr) { @@ -166,6 +175,17 @@ TEST_SUBMODULE(pytypes, m) { }); }); + m.def("return_renamed_capsule_with_destructor_2", []() { + py::print("creating capsule"); + auto cap = py::capsule((void *) 1234, [](void *ptr) { + py::print("destructing capsule: {}"_s.format((size_t) ptr)); + }); + static const char *capsule_name = "test_name2"; + py::print("renaming capsule"); + cap.set_name(capsule_name); + return cap; + }); + m.def("return_capsule_with_name_and_destructor", []() { auto capsule = py::capsule((void *) 12345, "pointer type description", [](PyObject *ptr) { if (ptr) { diff --git a/tests/test_pytypes.py b/tests/test_pytypes.py index 85afb9423..5c715ada6 100644 --- a/tests/test_pytypes.py +++ b/tests/test_pytypes.py @@ -195,6 +195,19 @@ def test_capsule(capture): """ ) + with capture: + a = m.return_renamed_capsule_with_destructor() + del a + pytest.gc_collect() + assert ( + capture.unordered + == """ + creating capsule + renaming capsule + destructing capsule + """ + ) + with capture: a = m.return_capsule_with_destructor_2() del a @@ -207,6 +220,19 @@ def test_capsule(capture): """ ) + with capture: + a = m.return_renamed_capsule_with_destructor_2() + del a + pytest.gc_collect() + assert ( + capture.unordered + == """ + creating capsule + renaming capsule + destructing capsule: 1234 + """ + ) + with capture: a = m.return_capsule_with_name_and_destructor() del a From ba7a0fac739554a4e24d2c4bcb836922a50314a0 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Thu, 14 Apr 2022 09:53:16 -0500 Subject: [PATCH 28/34] Expand dtype accessors (#3868) * Added constructor based on typenum, based on PyArray_DescrFromType Added accessors for typenum, alignment, byteorder and flags fields of PyArray_Descr struct. * Added tests for new py::dtype constructor, and for accessors * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fixed the comment for alignment method * Update include/pybind11/numpy.h Co-authored-by: Aaron Gokaslan * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Aaron Gokaslan --- include/pybind11/numpy.h | 24 ++++++++++++++++++++++++ tests/test_numpy_dtypes.cpp | 29 +++++++++++++++++++++++++++++ tests/test_numpy_dtypes.py | 8 +++++++- 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index d45fe4280..d71f08907 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -562,6 +562,13 @@ public: m_ptr = from_args(std::move(args)).release().ptr(); } + explicit dtype(int typenum) + : object(detail::npy_api::get().PyArray_DescrFromType_(typenum), stolen_t{}) { + if (m_ptr == nullptr) { + throw error_already_set(); + } + } + /// This is essentially the same as calling numpy.dtype(args) in Python. static dtype from_args(object args) { PyObject *ptr = nullptr; @@ -596,6 +603,23 @@ public: return detail::array_descriptor_proxy(m_ptr)->type; } + /// type number of dtype. + ssize_t num() const { + // Note: The signature, `dtype::num` follows the naming of NumPy's public + // Python API (i.e., ``dtype.num``), rather than its internal + // C API (``PyArray_Descr::type_num``). + return detail::array_descriptor_proxy(m_ptr)->type_num; + } + + /// Single character for byteorder + char byteorder() const { return detail::array_descriptor_proxy(m_ptr)->byteorder; } + + /// Alignment of the data type + int alignment() const { return detail::array_descriptor_proxy(m_ptr)->alignment; } + + /// Flags for the array descriptor + char flags() const { return detail::array_descriptor_proxy(m_ptr)->flags; } + private: static object _dtype_from_pep3118() { static PyObject *obj = module_::import("numpy.core._internal") diff --git a/tests/test_numpy_dtypes.cpp b/tests/test_numpy_dtypes.cpp index dd5b123dc..7de36f2fe 100644 --- a/tests/test_numpy_dtypes.cpp +++ b/tests/test_numpy_dtypes.cpp @@ -291,6 +291,7 @@ py::list test_dtype_ctors() { list.append(py::dtype(names, formats, offsets, 20)); list.append(py::dtype(py::buffer_info((void *) 0, sizeof(unsigned int), "I", 1))); list.append(py::dtype(py::buffer_info((void *) 0, 0, "T{i:a:f:b:}", 1))); + list.append(py::dtype(py::detail::npy_api::NPY_DOUBLE_)); return list; } @@ -440,6 +441,34 @@ TEST_SUBMODULE(numpy_dtypes, m) { } return list; }); + m.def("test_dtype_num", [dtype_names]() { + py::list list; + for (const auto &dt_name : dtype_names) { + list.append(py::dtype(dt_name).num()); + } + return list; + }); + m.def("test_dtype_byteorder", [dtype_names]() { + py::list list; + for (const auto &dt_name : dtype_names) { + list.append(py::dtype(dt_name).byteorder()); + } + return list; + }); + m.def("test_dtype_alignment", [dtype_names]() { + py::list list; + for (const auto &dt_name : dtype_names) { + list.append(py::dtype(dt_name).alignment()); + } + return list; + }); + m.def("test_dtype_flags", [dtype_names]() { + py::list list; + for (const auto &dt_name : dtype_names) { + list.append(py::dtype(dt_name).flags()); + } + return list; + }); m.def("test_dtype_methods", []() { py::list list; auto dt1 = py::dtype::of(); diff --git a/tests/test_numpy_dtypes.py b/tests/test_numpy_dtypes.py index 7df60583f..fcfd587b1 100644 --- a/tests/test_numpy_dtypes.py +++ b/tests/test_numpy_dtypes.py @@ -160,6 +160,7 @@ def test_dtype(simple_dtype): d1, np.dtype("uint32"), d2, + np.dtype("d"), ] assert m.test_dtype_methods() == [ @@ -175,8 +176,13 @@ def test_dtype(simple_dtype): np.zeros(1, m.trailing_padding_dtype()) ) + expected_chars = "bhilqBHILQefdgFDG?MmO" assert m.test_dtype_kind() == list("iiiiiuuuuuffffcccbMmO") - assert m.test_dtype_char_() == list("bhilqBHILQefdgFDG?MmO") + assert m.test_dtype_char_() == list(expected_chars) + assert m.test_dtype_num() == [np.dtype(ch).num for ch in expected_chars] + assert m.test_dtype_byteorder() == [np.dtype(ch).byteorder for ch in expected_chars] + assert m.test_dtype_alignment() == [np.dtype(ch).alignment for ch in expected_chars] + assert m.test_dtype_flags() == [chr(np.dtype(ch).flags) for ch in expected_chars] def test_recarray(simple_dtype, packed_dtype): From 45164c1fcb7b4af1c5f8263f37c16beea1aabb98 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Thu, 14 Apr 2022 11:16:58 -0500 Subject: [PATCH 29/34] Added deleted copy constructor for error_scope to comply with rule of 3. (#3870) * Added deleted copy constructor for error_scope to comply with rule of 3. --- include/pybind11/detail/common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index ea09bb3fd..b49313e44 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -992,6 +992,7 @@ constexpr const char struct error_scope { PyObject *type, *value, *trace; error_scope() { PyErr_Fetch(&type, &value, &trace); } + error_scope(const error_scope &) = delete; ~error_scope() { PyErr_Restore(type, value, trace); } }; From 3829b7624c644c2691a5675130acb12a55d30934 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Thu, 14 Apr 2022 17:12:44 -0400 Subject: [PATCH 30/34] chore: simplify numpy dtype ctor (#3869) * Simplify numpy dtype ctor * Simplify c_str ctor * Remove compat macro for str in numpy --- include/pybind11/numpy.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index d71f08907..d06ddfa11 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -540,18 +540,16 @@ public: PYBIND11_OBJECT_DEFAULT(dtype, object, detail::npy_api::get().PyArrayDescr_Check_); explicit dtype(const buffer_info &info) { - dtype descr(_dtype_from_pep3118()(PYBIND11_STR_TYPE(info.format))); + dtype descr(_dtype_from_pep3118()(pybind11::str(info.format))); // If info.itemsize == 0, use the value calculated from the format string m_ptr = descr.strip_padding(info.itemsize != 0 ? info.itemsize : descr.itemsize()) .release() .ptr(); } - explicit dtype(const std::string &format) { - m_ptr = from_args(pybind11::str(format)).release().ptr(); - } + explicit dtype(const std::string &format) : dtype(from_args(pybind11::str(format))) {} - explicit dtype(const char *format) : dtype(std::string(format)) {} + explicit dtype(const char *format) : dtype(from_args(pybind11::str(format))) {} dtype(list names, list formats, list offsets, ssize_t itemsize) { dict args; @@ -638,7 +636,7 @@ private: } struct field_descr { - PYBIND11_STR_TYPE name; + pybind11::str name; object format; pybind11::int_ offset; }; @@ -653,7 +651,7 @@ private: continue; } field_descriptors.push_back( - {(PYBIND11_STR_TYPE) name, format.strip_padding(format.itemsize()), offset}); + {(pybind11::str) name, format.strip_padding(format.itemsize()), offset}); } std::sort(field_descriptors.begin(), @@ -1359,7 +1357,7 @@ PYBIND11_NOINLINE void register_structured_dtype(any_container pybind11_fail(std::string("NumPy: unsupported field dtype: `") + field.name + "` @ " + tinfo.name()); } - names.append(PYBIND11_STR_TYPE(field.name)); + names.append(pybind11::str(field.name)); formats.append(field.descr); offsets.append(pybind11::int_(field.offset)); } From 30716c67a16fca836c447a263a87025ba080a6f2 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 15 Apr 2022 11:44:48 -0700 Subject: [PATCH 31/34] Also add error_scope assignment operator to complete the rule-of-3 (follow-on to PR #3870). (#3872) --- include/pybind11/detail/common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index b49313e44..a130ebea0 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -993,6 +993,7 @@ struct error_scope { PyObject *type, *value, *trace; error_scope() { PyErr_Fetch(&type, &value, &trace); } error_scope(const error_scope &) = delete; + error_scope &operator=(const error_scope &) = delete; ~error_scope() { PyErr_Restore(type, value, trace); } }; From fbcde3f0af59c5ae26561a774046623e1cc8a7c9 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Mon, 18 Apr 2022 11:09:45 -0400 Subject: [PATCH 32/34] chore: enable clang-tidy check modernize-use-nullptr (#3881) * Enable clang-tidy check modernize-use-nullptr * Sort clang-tidy * Sorted again --- .clang-tidy | 5 +++-- include/pybind11/numpy.h | 4 ++-- include/pybind11/pybind11.h | 2 +- include/pybind11/pytypes.h | 6 +++--- tests/cross_module_gil_utils.cpp | 6 +++--- tests/test_numpy_dtypes.cpp | 4 ++-- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index d01ca352c..e82443c4c 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -25,11 +25,12 @@ modernize-replace-random-shuffle, modernize-shrink-to-fit, modernize-use-auto, modernize-use-bool-literals, +modernize-use-default-member-init, modernize-use-equals-default, modernize-use-equals-delete, -modernize-use-default-member-init, -modernize-use-noexcept, modernize-use-emplace, +modernize-use-noexcept, +modernize-use-nullptr, modernize-use-override, modernize-use-using, *performance*, diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index d06ddfa11..335b78ff1 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -263,7 +263,7 @@ private: static npy_api lookup() { module_ m = module_::import("numpy.core.multiarray"); auto c = m.attr("_ARRAY_API"); - void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), NULL); + void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), nullptr); npy_api api; #define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func]; DECL_NPY_API(PyArray_GetNDArrayCFeatureVersion); @@ -1549,7 +1549,7 @@ public: void *data() const { return p_ptr; } private: - char *p_ptr{0}; + char *p_ptr{nullptr}; container_type m_strides; }; diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 97275e40a..ce05b6e4e 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -2489,7 +2489,7 @@ public: exception(handle scope, const char *name, handle base = PyExc_Exception) { std::string full_name = scope.attr("__name__").cast() + std::string(".") + name; - m_ptr = PyErr_NewException(const_cast(full_name.c_str()), base.ptr(), NULL); + m_ptr = PyErr_NewException(const_cast(full_name.c_str()), base.ptr(), nullptr); if (hasattr(scope, "__dict__") && scope.attr("__dict__").contains(name)) { pybind11_fail("Error during initialization: multiple incompatible " "definitions with name \"" diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 7d52774c8..26d9025c5 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -600,13 +600,13 @@ inline handle get_function(handle value) { inline PyObject *dict_getitemstring(PyObject *v, const char *key) { PyObject *kv = nullptr, *rv = nullptr; kv = PyUnicode_FromString(key); - if (kv == NULL) { + if (kv == nullptr) { throw error_already_set(); } rv = PyDict_GetItemWithError(v, kv); Py_DECREF(kv); - if (rv == NULL && PyErr_Occurred()) { + if (rv == nullptr && PyErr_Occurred()) { throw error_already_set(); } return rv; @@ -614,7 +614,7 @@ inline PyObject *dict_getitemstring(PyObject *v, const char *key) { inline PyObject *dict_getitem(PyObject *v, PyObject *key) { PyObject *rv = PyDict_GetItemWithError(v, key); - if (rv == NULL && PyErr_Occurred()) { + if (rv == nullptr && PyErr_Occurred()) { throw error_already_set(); } return rv; diff --git a/tests/cross_module_gil_utils.cpp b/tests/cross_module_gil_utils.cpp index 2e64da052..1436c35d6 100644 --- a/tests/cross_module_gil_utils.cpp +++ b/tests/cross_module_gil_utils.cpp @@ -25,8 +25,8 @@ void gil_acquire() { py::gil_scoped_acquire gil; } constexpr char kModuleName[] = "cross_module_gil_utils"; -struct PyModuleDef moduledef - = {PyModuleDef_HEAD_INIT, kModuleName, NULL, 0, NULL, NULL, NULL, NULL, NULL}; +struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, kModuleName, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr}; } // namespace @@ -34,7 +34,7 @@ extern "C" PYBIND11_EXPORT PyObject *PyInit_cross_module_gil_utils() { PyObject *m = PyModule_Create(&moduledef); - if (m != NULL) { + if (m != nullptr) { static_assert(sizeof(&gil_acquire) == sizeof(void *), "Function pointer must have the same size as void*"); PyModule_AddObject( diff --git a/tests/test_numpy_dtypes.cpp b/tests/test_numpy_dtypes.cpp index 7de36f2fe..38f2afa07 100644 --- a/tests/test_numpy_dtypes.cpp +++ b/tests/test_numpy_dtypes.cpp @@ -289,8 +289,8 @@ py::list test_dtype_ctors() { dict["itemsize"] = py::int_(20); list.append(py::dtype::from_args(dict)); list.append(py::dtype(names, formats, offsets, 20)); - list.append(py::dtype(py::buffer_info((void *) 0, sizeof(unsigned int), "I", 1))); - list.append(py::dtype(py::buffer_info((void *) 0, 0, "T{i:a:f:b:}", 1))); + list.append(py::dtype(py::buffer_info((void *) nullptr, sizeof(unsigned int), "I", 1))); + list.append(py::dtype(py::buffer_info((void *) nullptr, 0, "T{i:a:f:b:}", 1))); list.append(py::dtype(py::detail::npy_api::NPY_DOUBLE_)); return list; } From 1c636f4dce8414d458fee3a00df72ed769b7f79a Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Mon, 18 Apr 2022 11:11:24 -0400 Subject: [PATCH 33/34] chore: Change numpy dtype from_args call sig to const ref (#3878) * Change numpy from_args call signature to avoid copy * Reorder ctors * Rename arg * Fix unnecessary move * Fix clang-tidy and Add a few missing moves to memory_view pytype --- include/pybind11/numpy.h | 10 ++++++---- include/pybind11/pytypes.h | 7 ++++--- tests/test_numpy_dtypes.cpp | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index 335b78ff1..2713e13a8 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -547,9 +547,11 @@ public: .ptr(); } - explicit dtype(const std::string &format) : dtype(from_args(pybind11::str(format))) {} + explicit dtype(const pybind11::str &format) : dtype(from_args(format)) {} - explicit dtype(const char *format) : dtype(from_args(pybind11::str(format))) {} + explicit dtype(const std::string &format) : dtype(pybind11::str(format)) {} + + explicit dtype(const char *format) : dtype(pybind11::str(format)) {} dtype(list names, list formats, list offsets, ssize_t itemsize) { dict args; @@ -557,7 +559,7 @@ public: args["formats"] = std::move(formats); args["offsets"] = std::move(offsets); args["itemsize"] = pybind11::int_(itemsize); - m_ptr = from_args(std::move(args)).release().ptr(); + m_ptr = from_args(args).release().ptr(); } explicit dtype(int typenum) @@ -568,7 +570,7 @@ public: } /// This is essentially the same as calling numpy.dtype(args) in Python. - static dtype from_args(object args) { + static dtype from_args(const object &args) { PyObject *ptr = nullptr; if ((detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) == 0) || !ptr) { throw error_already_set(); diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 26d9025c5..324fa932f 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -1914,8 +1914,8 @@ public: return memoryview::from_buffer(reinterpret_cast(ptr), sizeof(T), format_descriptor::value, - shape, - strides, + std::move(shape), + std::move(strides), readonly); } @@ -1923,7 +1923,8 @@ public: static memoryview from_buffer(const T *ptr, detail::any_container shape, detail::any_container strides) { - return memoryview::from_buffer(const_cast(ptr), shape, strides, true); + return memoryview::from_buffer( + const_cast(ptr), std::move(shape), std::move(strides), true); } /** \rst diff --git a/tests/test_numpy_dtypes.cpp b/tests/test_numpy_dtypes.cpp index 38f2afa07..c25bc042b 100644 --- a/tests/test_numpy_dtypes.cpp +++ b/tests/test_numpy_dtypes.cpp @@ -610,5 +610,5 @@ TEST_SUBMODULE(numpy_dtypes, m) { []() { PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); }); // test_str_leak - m.def("dtype_wrapper", [](py::object d) { return py::dtype::from_args(std::move(d)); }); + m.def("dtype_wrapper", [](const py::object &d) { return py::dtype::from_args(d); }); } From e8e229fa0b486118bf91321b923f8158055c053c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 18 Apr 2022 17:44:01 -0400 Subject: [PATCH 34/34] [pre-commit.ci] pre-commit autoupdate (#3885) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/hadialqattan/pycln: v1.2.5 → v1.3.1](https://github.com/hadialqattan/pycln/compare/v1.2.5...v1.3.1) - [github.com/pre-commit/mirrors-clang-format: v13.0.1 → v14.0.1](https://github.com/pre-commit/mirrors-clang-format/compare/v13.0.1...v14.0.1) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9cfcef21f..099f0dc26 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -71,7 +71,7 @@ repos: # Autoremoves unused imports - repo: https://github.com/hadialqattan/pycln - rev: "v1.2.5" + rev: "v1.3.1" hooks: - id: pycln stages: [manual] @@ -164,7 +164,7 @@ repos: # Clang format the codebase automatically - repo: https://github.com/pre-commit/mirrors-clang-format - rev: "v13.0.1" + rev: "v14.0.1" hooks: - id: clang-format types_or: [c++, c, cuda]