From 8f5a8ab4ac693efc9610aba1e3bb1f5e0d711533 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Fri, 23 Aug 2019 17:18:05 +0300 Subject: [PATCH 001/768] Don't strip debug symbols in RelWithDebInfo mode (#1892) --- tools/pybind11Tools.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pybind11Tools.cmake b/tools/pybind11Tools.cmake index e3ec572b5..c7156c020 100644 --- a/tools/pybind11Tools.cmake +++ b/tools/pybind11Tools.cmake @@ -197,7 +197,7 @@ function(pybind11_add_module target_name) _pybind11_add_lto_flags(${target_name} ${ARG_THIN_LTO}) - if (NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug) + if (NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug|RelWithDebInfo) # Strip unnecessary sections of the binary on Linux/Mac OS if(CMAKE_STRIP) if(APPLE) From 5b4751af269afab9a2e40a92b486bd29214f352b Mon Sep 17 00:00:00 2001 From: Stephen Larew Date: Tue, 27 Aug 2019 08:05:47 -0700 Subject: [PATCH 002/768] Add const to buffer:request() (#1890) --- include/pybind11/pytypes.h | 2 +- tests/test_buffers.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 78a604e1d..96eab9662 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -1312,7 +1312,7 @@ class buffer : public object { public: PYBIND11_OBJECT_DEFAULT(buffer, object, PyObject_CheckBuffer) - buffer_info request(bool writable = false) { + buffer_info request(bool writable = false) const { int flags = PyBUF_STRIDES | PyBUF_FORMAT; if (writable) flags |= PyBUF_WRITABLE; Py_buffer *view = new Py_buffer(); diff --git a/tests/test_buffers.cpp b/tests/test_buffers.cpp index 5199cf646..433dfeee6 100644 --- a/tests/test_buffers.cpp +++ b/tests/test_buffers.cpp @@ -78,7 +78,7 @@ TEST_SUBMODULE(buffers, m) { py::class_(m, "Matrix", py::buffer_protocol()) .def(py::init()) /// Construct from a buffer - .def(py::init([](py::buffer b) { + .def(py::init([](py::buffer const b) { py::buffer_info info = b.request(); if (info.format != py::format_descriptor::format() || info.ndim != 2) throw std::runtime_error("Incompatible buffer format!"); From f6c4c1047a293ea77223c21f84f888e062212d78 Mon Sep 17 00:00:00 2001 From: "Lori A. Burns" Date: Wed, 4 Sep 2019 16:16:21 -0400 Subject: [PATCH 003/768] restores __invert__ to arithmetic-enabled enum, fixes #1907 (#1909) --- include/pybind11/pybind11.h | 2 ++ tests/test_enum.py | 1 + 2 files changed, 3 insertions(+) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index fbd971cfb..a7fe1898a 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1484,6 +1484,8 @@ struct enum_base { PYBIND11_ENUM_OP_CONV("__ror__", a | b); PYBIND11_ENUM_OP_CONV("__xor__", a ^ b); PYBIND11_ENUM_OP_CONV("__rxor__", a ^ b); + m_base.attr("__invert__") = cpp_function( + [](object arg) { return ~(int_(arg)); }, is_method(m_base)); } } else { PYBIND11_ENUM_OP_STRICT("__eq__", int_(a).equal(int_(b)), return false); diff --git a/tests/test_enum.py b/tests/test_enum.py index d0989adcd..2f119a3a9 100644 --- a/tests/test_enum.py +++ b/tests/test_enum.py @@ -140,6 +140,7 @@ def test_binary_operators(): assert int(m.Flags.Read | m.Flags.Execute) == 5 assert int(m.Flags.Write | m.Flags.Execute) == 3 assert int(m.Flags.Write | 1) == 3 + assert ~m.Flags.Write == -3 state = m.Flags.Read | m.Flags.Write assert (state & m.Flags.Read) != 0 From 09f082940113661256310e3f4811aa7261a9fa05 Mon Sep 17 00:00:00 2001 From: Sergei Izmailov Date: Thu, 19 Sep 2019 19:23:27 +0300 Subject: [PATCH 004/768] Avoid conversion to `int_` rhs argument of enum eq/ne (#1912) * fix: Avoid conversion to `int_` rhs argument of enum eq/ne * test: compare unscoped enum with strings * suppress comparison to None warning * test unscoped enum arithmetic and comparision with unsupported type --- include/pybind11/pybind11.h | 13 +++++++-- tests/test_enum.cpp | 4 ++- tests/test_enum.py | 58 ++++++++++++++++++++++++++++++------- 3 files changed, 62 insertions(+), 13 deletions(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index a7fe1898a..204aaa43a 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1469,9 +1469,17 @@ struct enum_base { }, \ is_method(m_base)) + #define PYBIND11_ENUM_OP_CONV_LHS(op, expr) \ + m_base.attr(op) = cpp_function( \ + [](object a_, object b) { \ + int_ a(a_); \ + return expr; \ + }, \ + is_method(m_base)) + if (is_convertible) { - PYBIND11_ENUM_OP_CONV("__eq__", !b.is_none() && a.equal(b)); - PYBIND11_ENUM_OP_CONV("__ne__", b.is_none() || !a.equal(b)); + PYBIND11_ENUM_OP_CONV_LHS("__eq__", !b.is_none() && a.equal(b)); + PYBIND11_ENUM_OP_CONV_LHS("__ne__", b.is_none() || !a.equal(b)); if (is_arithmetic) { PYBIND11_ENUM_OP_CONV("__lt__", a < b); @@ -1501,6 +1509,7 @@ struct enum_base { } } + #undef PYBIND11_ENUM_OP_CONV_LHS #undef PYBIND11_ENUM_OP_CONV #undef PYBIND11_ENUM_OP_STRICT diff --git a/tests/test_enum.cpp b/tests/test_enum.cpp index 498a00e16..315308920 100644 --- a/tests/test_enum.cpp +++ b/tests/test_enum.cpp @@ -13,11 +13,13 @@ TEST_SUBMODULE(enums, m) { // test_unscoped_enum enum UnscopedEnum { EOne = 1, - ETwo + ETwo, + EThree }; py::enum_(m, "UnscopedEnum", py::arithmetic(), "An unscoped enumeration") .value("EOne", EOne, "Docstring for EOne") .value("ETwo", ETwo, "Docstring for ETwo") + .value("EThree", EThree, "Docstring for EThree") .export_values(); // test_scoped_enum diff --git a/tests/test_enum.py b/tests/test_enum.py index 2f119a3a9..7fe9b618d 100644 --- a/tests/test_enum.py +++ b/tests/test_enum.py @@ -21,7 +21,7 @@ def test_unscoped_enum(): # __members__ property assert m.UnscopedEnum.__members__ == \ - {"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo} + {"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo, "EThree": m.UnscopedEnum.EThree} # __members__ readonly with pytest.raises(AttributeError): m.UnscopedEnum.__members__ = {} @@ -29,23 +29,18 @@ def test_unscoped_enum(): foo = m.UnscopedEnum.__members__ foo["bar"] = "baz" assert m.UnscopedEnum.__members__ == \ - {"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo} + {"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo, "EThree": m.UnscopedEnum.EThree} - assert m.UnscopedEnum.__doc__ == \ - '''An unscoped enumeration + for docstring_line in '''An unscoped enumeration Members: EOne : Docstring for EOne - ETwo : Docstring for ETwo''' or m.UnscopedEnum.__doc__ == \ - '''An unscoped enumeration - -Members: - ETwo : Docstring for ETwo - EOne : Docstring for EOne''' + EThree : Docstring for EThree'''.split('\n'): + assert docstring_line in m.UnscopedEnum.__doc__ # Unscoped enums will accept ==/!= int comparisons y = m.UnscopedEnum.ETwo @@ -53,6 +48,38 @@ Members: assert 2 == y assert y != 3 assert 3 != y + # Compare with None + assert (y != None) # noqa: E711 + assert not (y == None) # noqa: E711 + # Compare with an object + assert (y != object()) + assert not (y == object()) + # Compare with string + assert y != "2" + assert "2" != y + assert not ("2" == y) + assert not (y == "2") + + with pytest.raises(TypeError): + y < object() + + with pytest.raises(TypeError): + y <= object() + + with pytest.raises(TypeError): + y > object() + + with pytest.raises(TypeError): + y >= object() + + with pytest.raises(TypeError): + y | object() + + with pytest.raises(TypeError): + y & object() + + with pytest.raises(TypeError): + y ^ object() assert int(m.UnscopedEnum.ETwo) == 2 assert str(m.UnscopedEnum(2)) == "UnscopedEnum.ETwo" @@ -71,6 +98,11 @@ Members: assert not (m.UnscopedEnum.ETwo < m.UnscopedEnum.EOne) assert not (2 < m.UnscopedEnum.EOne) + # arithmetic + assert m.UnscopedEnum.EOne & m.UnscopedEnum.EThree == m.UnscopedEnum.EOne + assert m.UnscopedEnum.EOne | m.UnscopedEnum.ETwo == m.UnscopedEnum.EThree + assert m.UnscopedEnum.EOne ^ m.UnscopedEnum.EThree == m.UnscopedEnum.ETwo + def test_scoped_enum(): assert m.test_scoped_enum(m.ScopedEnum.Three) == "ScopedEnum::Three" @@ -82,6 +114,12 @@ def test_scoped_enum(): assert not 3 == z assert z != 3 assert 3 != z + # Compare with None + assert (z != None) # noqa: E711 + assert not (z == None) # noqa: E711 + # Compare with an object + assert (z != object()) + assert not (z == object()) # Scoped enums will *NOT* accept >, <, >= and <= int comparisons (Will throw exceptions) with pytest.raises(TypeError): z > 3 From c9f5a464bc8ebe91dee8578b2b4a23d9997ffefe Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Thu, 19 Sep 2019 21:07:17 +0200 Subject: [PATCH 005/768] pybind11 internals: separate different compilers --- include/pybind11/detail/internals.h | 31 +++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 2369d8fed..067780c26 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -147,6 +147,33 @@ struct type_info { # define PYBIND11_BUILD_TYPE "" #endif +/// Let's assume that different compilers are ABI-incompatible. +#if defined(_MSC_VER) +# define PYBIND11_COMPILER_TYPE "_msvc" +#elif defined(__INTEL_COMPILER) +# define PYBIND11_COMPILER_TYPE "_icc" +#elif defined(__clang__) +# define PYBIND11_COMPILER_TYPE "_clang" +#elif defined(__PGI) +# define PYBIND11_COMPILER_TYPE "_pgi" +#elif defined(__MINGW32__) +# define PYBIND11_COMPILER_TYPE "_mingw" +#elif defined(__CYGWIN__) +# define PYBIND11_COMPILER_TYPE "_gcc_cygwin" +#elif defined(__GNUC__) +# define PYBIND11_COMPILER_TYPE "_gcc" +#else +# define PYBIND11_COMPILER_TYPE "_unknown" +#endif + +#if defined(_LIBCPP_VERSION) +# define PYBIND11_STDLIB "_libcpp" +#elif defined(__GLIBCXX__) || defined(__GLIBCPP__) +# define PYBIND11_STDLIB "_libstdcpp" +#else +# define PYBIND11_STDLIB "" +#endif + /// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility. #if defined(__GXX_ABI_VERSION) # define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION) @@ -161,10 +188,10 @@ struct type_info { #endif #define PYBIND11_INTERNALS_ID "__pybind11_internals_v" \ - PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__" + PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__" #define PYBIND11_MODULE_LOCAL_ID "__pybind11_module_local_v" \ - PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__" + PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__" /// Each module locally stores a pointer to the `internals` data. The data /// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`. From 6ca312b3bcdccdd55321dcf7111a50cad37a6c99 Mon Sep 17 00:00:00 2001 From: Samuel Debionne Date: Thu, 19 Sep 2019 21:23:03 +0200 Subject: [PATCH 006/768] Avoid infinite recursion in is_copy_constructible (#1910) --- include/pybind11/cast.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 67397c4ee..605acb366 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -775,7 +775,9 @@ template struct is_copy_constructible : std // so, copy constructability depends on whether the value_type is copy constructible. template struct is_copy_constructible, - std::is_same + std::is_same, + // Avoid infinite recursion + negation> >::value>> : is_copy_constructible {}; #if !defined(PYBIND11_CPP17) From 00a0aa992953d6482114a0f539a21bb535a16383 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Thu, 19 Sep 2019 23:06:22 +0200 Subject: [PATCH 007/768] v2.4.0 release --- docs/changelog.rst | 59 ++++++++++++++++++++++++++++++-- docs/conf.py | 4 +-- include/pybind11/detail/common.h | 4 +-- pybind11/_version.py | 2 +- 4 files changed, 62 insertions(+), 7 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 9576a8bc2..eaf8c2533 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -6,14 +6,69 @@ Changelog Starting with version 1.8.0, pybind11 releases use a `semantic versioning `_ policy. - -v2.3.1 (Not yet released) +v2.4.0 (Sep 19, 2019) ----------------------------------------------------- +* Try harder to keep pybind11-internal data structures separate when there + are potential ABI incompatibilities. Fixes crashes that occurred when loading + multiple pybind11 extensions that were e.g. compiled by GCC (libstdc++) + and Clang (libc++). + `1588 `_ and + `c9f5a `_. + +* Added support for ``__await__``, ``__aiter__``, and ``__anext__`` protocols. + `1842 `_. + +* ``pybind11_add_module()``: don't strip symbols when compiling in + ``RelWithDebInfo`` mode. `1980 + `_. + +* ``enum_``: Reproduce Python behavior when comparing against invalid values + (e.g. ``None``, strings, etc.). Add back support for ``__invert__()``. + `1912 `_, + `1907 `_. + +* List insertion operation for ``py::list``. + Added ``.empty()`` to all collection types. + Added ``py::set::contains()`` and ``py::dict::contains()``. + `1887 `_, + `1884 `_, + `1888 `_. + * ``py::details::overload_cast_impl`` is available in C++11 mode, can be used like ``overload_cast`` with an additional set of parantheses. `1581 `_. +* ``overload_cast_impl`` is now available in C++11. + `1581 `_. + +* Fixed ``get_include()`` on Conda. + `1877 `_. + +* ``stl_bind.h``: negative indexing support. + `1882 `_. + +* Minor CMake fix to add MinGW compatibility. + `1851 `_. + +* GIL-related fixes. + `1836 `_, + `8b90b `_. + +* Other very minor/subtle fixes and improvements. + `1329 `_, + `1910 `_, + `1863 `_, + `1847 `_, + `1890 `_, + `1860 `_, + `1848 `_, + `1821 `_, + `1837 `_, + `1833 `_, + `1748 `_, + `1852 `_. + v2.3.0 (June 11, 2019) ----------------------------------------------------- diff --git a/docs/conf.py b/docs/conf.py index d17e4ba30..da9dd1929 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -61,9 +61,9 @@ author = 'Wenzel Jakob' # built documents. # # The short X.Y version. -version = '2.3' +version = '2.4' # The full version, including alpha/beta/rc tags. -release = '2.3.dev1' +release = '2.4.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 7fb427abd..d1c6c2bc5 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -93,8 +93,8 @@ #endif #define PYBIND11_VERSION_MAJOR 2 -#define PYBIND11_VERSION_MINOR 3 -#define PYBIND11_VERSION_PATCH dev1 +#define PYBIND11_VERSION_MINOR 4 +#define PYBIND11_VERSION_PATCH 0 /// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode #if defined(_MSC_VER) diff --git a/pybind11/_version.py b/pybind11/_version.py index fef541bdb..fdd1ea341 100644 --- a/pybind11/_version.py +++ b/pybind11/_version.py @@ -1,2 +1,2 @@ -version_info = (2, 3, 'dev1') +version_info = (2, 4, 0) __version__ = '.'.join(map(str, version_info)) From e825205ac6995dad6f548217838a0e7544c98e2c Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Thu, 19 Sep 2019 23:18:04 +0200 Subject: [PATCH 008/768] begin working on v2.4.1 --- docs/conf.py | 2 +- include/pybind11/detail/common.h | 2 +- pybind11/_version.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index da9dd1929..fec6bfb61 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -63,7 +63,7 @@ author = 'Wenzel Jakob' # The short X.Y version. version = '2.4' # The full version, including alpha/beta/rc tags. -release = '2.4.0' +release = '2.4.dev1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index d1c6c2bc5..678a58c0c 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -94,7 +94,7 @@ #define PYBIND11_VERSION_MAJOR 2 #define PYBIND11_VERSION_MINOR 4 -#define PYBIND11_VERSION_PATCH 0 +#define PYBIND11_VERSION_PATCH dev1 /// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode #if defined(_MSC_VER) diff --git a/pybind11/_version.py b/pybind11/_version.py index fdd1ea341..e11cfe308 100644 --- a/pybind11/_version.py +++ b/pybind11/_version.py @@ -1,2 +1,2 @@ -version_info = (2, 4, 0) +version_info = (2, 4, 'dev1') __version__ = '.'.join(map(str, version_info)) From 21d0eb460f3d6932cbf9544d636d22080bf386b6 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Fri, 20 Sep 2019 09:38:30 +0200 Subject: [PATCH 009/768] Fix Python 3.8 test regression --- tests/test_enum.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/test_enum.py b/tests/test_enum.py index 7fe9b618d..cea834d01 100644 --- a/tests/test_enum.py +++ b/tests/test_enum.py @@ -192,12 +192,15 @@ def test_binary_operators(): def test_enum_to_int(): - m.test_enum_to_int(m.Flags.Read) - m.test_enum_to_int(m.ClassWithUnscopedEnum.EMode.EFirstMode) - m.test_enum_to_uint(m.Flags.Read) - m.test_enum_to_uint(m.ClassWithUnscopedEnum.EMode.EFirstMode) - m.test_enum_to_long_long(m.Flags.Read) - m.test_enum_to_long_long(m.ClassWithUnscopedEnum.EMode.EFirstMode) + import sys + # Implicit conversion to integers is deprecated in Python >= 3.8 + if sys.version_info < (3, 8): + m.test_enum_to_int(m.Flags.Read) + m.test_enum_to_int(m.ClassWithUnscopedEnum.EMode.EFirstMode) + m.test_enum_to_uint(m.Flags.Read) + m.test_enum_to_uint(m.ClassWithUnscopedEnum.EMode.EFirstMode) + m.test_enum_to_long_long(m.Flags.Read) + m.test_enum_to_long_long(m.ClassWithUnscopedEnum.EMode.EFirstMode) def test_duplicate_enum_name(): From 5fd187ebe92b3fbd3e467a08c194dc254a1edd74 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Fri, 20 Sep 2019 10:49:52 +0200 Subject: [PATCH 010/768] minor changelog cleanup [ci skip] --- docs/changelog.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index eaf8c2533..534f10e17 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -39,9 +39,6 @@ v2.4.0 (Sep 19, 2019) like ``overload_cast`` with an additional set of parantheses. `1581 `_. -* ``overload_cast_impl`` is now available in C++11. - `1581 `_. - * Fixed ``get_include()`` on Conda. `1877 `_. From 31680e6f9c1bbe582bc36d457f8e010121ff16bb Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Fri, 20 Sep 2019 11:06:10 +0200 Subject: [PATCH 011/768] Implicit conversion from enum to int for Python 3.8 (fix by @sizmailov) --- include/pybind11/pybind11.h | 4 ++++ tests/test_enum.py | 15 ++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 204aaa43a..a0e639583 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1566,6 +1566,10 @@ public: #if PY_MAJOR_VERSION < 3 def("__long__", [](Type value) { return (Scalar) value; }); #endif + #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 8 + def("__index__", [](Type value) { return (Scalar) value; }); + #endif + cpp_function setstate( [](Type &value, Scalar arg) { value = static_cast(arg); }, is_method(*this)); diff --git a/tests/test_enum.py b/tests/test_enum.py index cea834d01..7fe9b618d 100644 --- a/tests/test_enum.py +++ b/tests/test_enum.py @@ -192,15 +192,12 @@ def test_binary_operators(): def test_enum_to_int(): - import sys - # Implicit conversion to integers is deprecated in Python >= 3.8 - if sys.version_info < (3, 8): - m.test_enum_to_int(m.Flags.Read) - m.test_enum_to_int(m.ClassWithUnscopedEnum.EMode.EFirstMode) - m.test_enum_to_uint(m.Flags.Read) - m.test_enum_to_uint(m.ClassWithUnscopedEnum.EMode.EFirstMode) - m.test_enum_to_long_long(m.Flags.Read) - m.test_enum_to_long_long(m.ClassWithUnscopedEnum.EMode.EFirstMode) + m.test_enum_to_int(m.Flags.Read) + m.test_enum_to_int(m.ClassWithUnscopedEnum.EMode.EFirstMode) + m.test_enum_to_uint(m.Flags.Read) + m.test_enum_to_uint(m.ClassWithUnscopedEnum.EMode.EFirstMode) + m.test_enum_to_long_long(m.Flags.Read) + m.test_enum_to_long_long(m.ClassWithUnscopedEnum.EMode.EFirstMode) def test_duplicate_enum_name(): From e44fcc3c15b41f0720c72832c0b9cd07de819781 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Fri, 20 Sep 2019 11:10:49 +0200 Subject: [PATCH 012/768] v2.4.1 release --- docs/changelog.rst | 56 ++++++++++++++++++-------------- docs/conf.py | 2 +- include/pybind11/detail/common.h | 2 +- pybind11/_version.py | 2 +- 4 files changed, 34 insertions(+), 28 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 534f10e17..25c7808d2 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -6,6 +6,12 @@ Changelog Starting with version 1.8.0, pybind11 releases use a `semantic versioning `_ policy. +v2.4.1 (Sep 20, 2019) +----------------------------------------------------- + +* Fixed a problem involving implicit conversion from enumerations to integers + on Python 3.8. `1780 `_. + v2.4.0 (Sep 19, 2019) ----------------------------------------------------- @@ -13,58 +19,58 @@ v2.4.0 (Sep 19, 2019) are potential ABI incompatibilities. Fixes crashes that occurred when loading multiple pybind11 extensions that were e.g. compiled by GCC (libstdc++) and Clang (libc++). - `1588 `_ and + `#1588 `_ and `c9f5a `_. * Added support for ``__await__``, ``__aiter__``, and ``__anext__`` protocols. - `1842 `_. + `#1842 `_. * ``pybind11_add_module()``: don't strip symbols when compiling in - ``RelWithDebInfo`` mode. `1980 + ``RelWithDebInfo`` mode. `#1980 `_. * ``enum_``: Reproduce Python behavior when comparing against invalid values (e.g. ``None``, strings, etc.). Add back support for ``__invert__()``. - `1912 `_, - `1907 `_. + `#1912 `_, + `#1907 `_. * List insertion operation for ``py::list``. Added ``.empty()`` to all collection types. Added ``py::set::contains()`` and ``py::dict::contains()``. - `1887 `_, - `1884 `_, - `1888 `_. + `#1887 `_, + `#1884 `_, + `#1888 `_. * ``py::details::overload_cast_impl`` is available in C++11 mode, can be used like ``overload_cast`` with an additional set of parantheses. - `1581 `_. + `#1581 `_. * Fixed ``get_include()`` on Conda. - `1877 `_. + `#1877 `_. * ``stl_bind.h``: negative indexing support. - `1882 `_. + `#1882 `_. * Minor CMake fix to add MinGW compatibility. - `1851 `_. + `#1851 `_. * GIL-related fixes. - `1836 `_, + `#1836 `_, `8b90b `_. * Other very minor/subtle fixes and improvements. - `1329 `_, - `1910 `_, - `1863 `_, - `1847 `_, - `1890 `_, - `1860 `_, - `1848 `_, - `1821 `_, - `1837 `_, - `1833 `_, - `1748 `_, - `1852 `_. + `#1329 `_, + `#1910 `_, + `#1863 `_, + `#1847 `_, + `#1890 `_, + `#1860 `_, + `#1848 `_, + `#1821 `_, + `#1837 `_, + `#1833 `_, + `#1748 `_, + `#1852 `_. v2.3.0 (June 11, 2019) ----------------------------------------------------- diff --git a/docs/conf.py b/docs/conf.py index fec6bfb61..5e9b9b2a4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -63,7 +63,7 @@ author = 'Wenzel Jakob' # The short X.Y version. version = '2.4' # The full version, including alpha/beta/rc tags. -release = '2.4.dev1' +release = '2.4.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 678a58c0c..879fb6ca9 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -94,7 +94,7 @@ #define PYBIND11_VERSION_MAJOR 2 #define PYBIND11_VERSION_MINOR 4 -#define PYBIND11_VERSION_PATCH dev1 +#define PYBIND11_VERSION_PATCH 1 /// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode #if defined(_MSC_VER) diff --git a/pybind11/_version.py b/pybind11/_version.py index e11cfe308..39550aa23 100644 --- a/pybind11/_version.py +++ b/pybind11/_version.py @@ -1,2 +1,2 @@ -version_info = (2, 4, 'dev1') +version_info = (2, 4, 1) __version__ = '.'.join(map(str, version_info)) From 82cf7935883020b7fd89f0ff9f8b8ad2c1d924f8 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Fri, 20 Sep 2019 11:12:22 +0200 Subject: [PATCH 013/768] begin working on next version --- docs/conf.py | 2 +- include/pybind11/detail/common.h | 2 +- pybind11/_version.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 5e9b9b2a4..040b896cc 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -63,7 +63,7 @@ author = 'Wenzel Jakob' # The short X.Y version. version = '2.4' # The full version, including alpha/beta/rc tags. -release = '2.4.1' +release = '2.4.dev2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 879fb6ca9..6ed75b6c0 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -94,7 +94,7 @@ #define PYBIND11_VERSION_MAJOR 2 #define PYBIND11_VERSION_MINOR 4 -#define PYBIND11_VERSION_PATCH 1 +#define PYBIND11_VERSION_PATCH dev2 /// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode #if defined(_MSC_VER) diff --git a/pybind11/_version.py b/pybind11/_version.py index 39550aa23..326c9139d 100644 --- a/pybind11/_version.py +++ b/pybind11/_version.py @@ -1,2 +1,2 @@ -version_info = (2, 4, 1) +version_info = (2, 4, 'dev2') __version__ = '.'.join(map(str, version_info)) From f3109d8419b3ed56cf9795f6343ab08b0c27746a Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Sat, 21 Sep 2019 18:09:35 +0200 Subject: [PATCH 014/768] future-proof Python version check from commit 31680e6 (@lgritz) --- 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 a0e639583..c6237056b 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1566,7 +1566,7 @@ public: #if PY_MAJOR_VERSION < 3 def("__long__", [](Type value) { return (Scalar) value; }); #endif - #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 8 + #if PY_MAJOR_VERSION > 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 8) def("__index__", [](Type value) { return (Scalar) value; }); #endif From 7f5dad7d5fba3fb6fccef966f7cde5ca24509473 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Sat, 21 Sep 2019 18:54:10 +0200 Subject: [PATCH 015/768] Remove usage of C++14 constructs (fixes #1929) --- include/pybind11/numpy.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index 8b21d3d43..ba41a223d 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -113,12 +113,12 @@ template struct same_size { template using as = bool_constant; }; +template constexpr int platform_lookup() { return -1; } + // Lookup a type according to its size, and return a value corresponding to the NumPy typenum. -template -constexpr int platform_lookup(Int... codes) { - using code_index = std::integral_constant::template as, Check...>()>; - static_assert(code_index::value != sizeof...(Check), "Unable to match type on this platform"); - return std::get(std::make_tuple(codes...)); +template +constexpr int platform_lookup(int I, Ints... Is) { + return sizeof(Concrete) == sizeof(T) ? I : platform_lookup(Is...); } struct npy_api { From 7ec2ddfc95f65d1e986d359466a6c254aa514ef3 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Sat, 21 Sep 2019 20:19:58 +0200 Subject: [PATCH 016/768] v2.4.2 release --- docs/changelog.rst | 11 ++++++++++- docs/conf.py | 2 +- include/pybind11/detail/common.h | 2 +- pybind11/_version.py | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 25c7808d2..1ac83ec3e 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -6,11 +6,20 @@ Changelog Starting with version 1.8.0, pybind11 releases use a `semantic versioning `_ policy. +v2.4.2 (Sep 21, 2019) +----------------------------------------------------- + +* Replaced usage of a C++14 only construct. `#1929 + `_. + +* Made an ifdef future-proof for Python >= 4. `f3109d + `_. + v2.4.1 (Sep 20, 2019) ----------------------------------------------------- * Fixed a problem involving implicit conversion from enumerations to integers - on Python 3.8. `1780 `_. + on Python 3.8. `#1780 `_. v2.4.0 (Sep 19, 2019) ----------------------------------------------------- diff --git a/docs/conf.py b/docs/conf.py index 040b896cc..b071d2c72 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -63,7 +63,7 @@ author = 'Wenzel Jakob' # The short X.Y version. version = '2.4' # The full version, including alpha/beta/rc tags. -release = '2.4.dev2' +release = '2.4.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 6ed75b6c0..0a6792eb9 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -94,7 +94,7 @@ #define PYBIND11_VERSION_MAJOR 2 #define PYBIND11_VERSION_MINOR 4 -#define PYBIND11_VERSION_PATCH dev2 +#define PYBIND11_VERSION_PATCH 2 /// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode #if defined(_MSC_VER) diff --git a/pybind11/_version.py b/pybind11/_version.py index 326c9139d..492138ea4 100644 --- a/pybind11/_version.py +++ b/pybind11/_version.py @@ -1,2 +1,2 @@ -version_info = (2, 4, 'dev2') +version_info = (2, 4, 2) __version__ = '.'.join(map(str, version_info)) From 2abd7e1eb48ce8549b936a3e19581ce82256a20f Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Sat, 21 Sep 2019 20:22:33 +0200 Subject: [PATCH 017/768] updated release.rst to remove parts that are now automated --- docs/release.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/release.rst b/docs/release.rst index b31bbe97e..9846f971a 100644 --- a/docs/release.rst +++ b/docs/release.rst @@ -13,10 +13,6 @@ To release a new version of pybind11: - ``git push --tags``. - ``python setup.py sdist upload``. - ``python setup.py bdist_wheel upload``. -- Update conda-forge (https://github.com/conda-forge/pybind11-feedstock) via PR - - download release package from Github: ``wget https://github.com/pybind/pybind11/archive/vX.Y.Z.tar.gz`` - - compute checksum: ``shasum -a 256 vX.Y.Z.tar.gz`` - - change version number and checksum in ``recipe/meta.yml`` - Get back to work - Update ``_version.py`` (add 'dev' and increment minor). - Update version in ``docs/conf.py`` From 34c2281e315c51f5270321101dc733c1cf26214f Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Sat, 21 Sep 2019 20:23:01 +0200 Subject: [PATCH 018/768] begin working on next version --- docs/conf.py | 2 +- include/pybind11/detail/common.h | 2 +- pybind11/_version.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index b071d2c72..dfb20df4a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -63,7 +63,7 @@ author = 'Wenzel Jakob' # The short X.Y version. version = '2.4' # The full version, including alpha/beta/rc tags. -release = '2.4.2' +release = '2.4.dev3' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 0a6792eb9..3e4549490 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -94,7 +94,7 @@ #define PYBIND11_VERSION_MAJOR 2 #define PYBIND11_VERSION_MINOR 4 -#define PYBIND11_VERSION_PATCH 2 +#define PYBIND11_VERSION_PATCH dev3 /// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode #if defined(_MSC_VER) diff --git a/pybind11/_version.py b/pybind11/_version.py index 492138ea4..85c7f94e2 100644 --- a/pybind11/_version.py +++ b/pybind11/_version.py @@ -1,2 +1,2 @@ -version_info = (2, 4, 2) +version_info = (2, 4, 'dev3') __version__ = '.'.join(map(str, version_info)) From 96be2c154f296da7ca8d5d7159773970622d0c77 Mon Sep 17 00:00:00 2001 From: Boris Dalstein Date: Sun, 6 Oct 2019 23:23:10 +0200 Subject: [PATCH 019/768] Fix version mismatch typos in .travis.yml (#1948) --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4cc5cf07c..381148e04 100644 --- a/.travis.yml +++ b/.travis.yml @@ -61,7 +61,7 @@ matrix: - os: linux dist: trusty env: PYTHON=2.7 CPP=14 GCC=6 CMAKE=1 - name: Python 2.7, c++14, gcc 4.8, CMake test + name: Python 2.7, c++14, gcc 6, CMake test addons: apt: sources: @@ -130,7 +130,7 @@ matrix: dist: trusty services: docker env: DOCKER=i386/debian:stretch PYTHON=3.5 CPP=14 GCC=6 INSTALL=1 - name: Python 3.4, c++14, gcc 6, 32-bit + name: Python 3.5, c++14, gcc 6, 32-bit script: - | # Consolidated 32-bit Docker Build + Install From 6cb584e9de6e8d54f5576c299a308f89bfdcb519 Mon Sep 17 00:00:00 2001 From: Sergei Izmailov Date: Tue, 8 Oct 2019 19:25:09 +0300 Subject: [PATCH 020/768] Adapt to python3.8 C API change (#1950) * Adapt to python3.8 C API change Do `Py_DECREF(type)` on all python objects on deallocation fix #1946 * Add bare python3.8 build to CI matrix While numpy/scipy wheels are available, run python3.8 test without them --- .travis.yml | 27 +++++++++++++++++++++++++++ include/pybind11/detail/class.h | 6 ++++++ 2 files changed, 33 insertions(+) diff --git a/.travis.yml b/.travis.yml index 381148e04..28f35f995 100644 --- a/.travis.yml +++ b/.travis.yml @@ -106,6 +106,33 @@ matrix: - lld-7 - libc++-7-dev - libc++abi-7-dev # Why is this necessary??? + - os: linux + dist: xenial + env: PYTHON=3.8 CPP=17 GCC=7 + name: Python 3.8, c++17, gcc 7 (w/o numpy/scipy) # TODO: update build name when the numpy/scipy wheels become available + addons: + apt: + sources: + - deadsnakes + - ubuntu-toolchain-r-test + packages: + - g++-7 + - python3.8-dev + - python3.8-venv + # Currently there is no numpy/scipy wheels available for python3.8 + # TODO: remove next before_install, install and script clause when the wheels become available + before_install: + - pyenv global $(pyenv whence 2to3) # activate all python versions + - PY_CMD=python3 + - $PY_CMD -m pip install --user --upgrade pip wheel setuptools + install: + - $PY_CMD -m pip install --user --upgrade pytest + script: + - | + # Barebones build + cmake -DCMAKE_BUILD_TYPE=Debug -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DPYTHON_EXECUTABLE=$(which $PY_CMD) . + make pytest -j 2 + make cpptest -j 2 - os: osx name: Python 2.7, c++14, AppleClang 7.3, CMake test osx_image: xcode7.3 diff --git a/include/pybind11/detail/class.h b/include/pybind11/detail/class.h index ffdfefe74..230ae81ae 100644 --- a/include/pybind11/detail/class.h +++ b/include/pybind11/detail/class.h @@ -350,6 +350,7 @@ extern "C" inline void pybind11_object_dealloc(PyObject *self) { auto type = Py_TYPE(self); type->tp_free(self); +#if PY_VERSION_HEX < 0x03080000 // `type->tp_dealloc != pybind11_object_dealloc` means that we're being called // as part of a derived type's dealloc, in which case we're not allowed to decref // the type here. For cross-module compatibility, we shouldn't compare directly @@ -357,6 +358,11 @@ extern "C" inline void pybind11_object_dealloc(PyObject *self) { auto pybind11_object_type = (PyTypeObject *) get_internals().instance_base; if (type->tp_dealloc == pybind11_object_type->tp_dealloc) Py_DECREF(type); +#else + // This was not needed before Python 3.8 (Python issue 35810) + // https://github.com/pybind/pybind11/issues/1946 + Py_DECREF(type); +#endif } /** Create the type which can be used as a common base for all classes. This is From 80d452484c5409444b0ec19383faa84bb7a4d351 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Tue, 15 Oct 2019 01:57:24 +0200 Subject: [PATCH 021/768] v2.4.3 release --- docs/changelog.rst | 6 ++++++ docs/conf.py | 2 +- include/pybind11/detail/common.h | 2 +- pybind11/_version.py | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 1ac83ec3e..d65c2d800 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -6,6 +6,12 @@ Changelog Starting with version 1.8.0, pybind11 releases use a `semantic versioning `_ policy. +v2.4.3 (Oct 15, 2019) +----------------------------------------------------- + +* Adapt pybind11 to a C API convention change in Python 3.8. `#1950 + `_. + v2.4.2 (Sep 21, 2019) ----------------------------------------------------- diff --git a/docs/conf.py b/docs/conf.py index dfb20df4a..c43854629 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -63,7 +63,7 @@ author = 'Wenzel Jakob' # The short X.Y version. version = '2.4' # The full version, including alpha/beta/rc tags. -release = '2.4.dev3' +release = '2.4.3' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 3e4549490..6da547060 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -94,7 +94,7 @@ #define PYBIND11_VERSION_MAJOR 2 #define PYBIND11_VERSION_MINOR 4 -#define PYBIND11_VERSION_PATCH dev3 +#define PYBIND11_VERSION_PATCH 3 /// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode #if defined(_MSC_VER) diff --git a/pybind11/_version.py b/pybind11/_version.py index 85c7f94e2..2709cc556 100644 --- a/pybind11/_version.py +++ b/pybind11/_version.py @@ -1,2 +1,2 @@ -version_info = (2, 4, 'dev3') +version_info = (2, 4, 3) __version__ = '.'.join(map(str, version_info)) From dfde1554ea3c9d43a914b868b46d3ddf3e3c6274 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Tue, 15 Oct 2019 01:58:43 +0200 Subject: [PATCH 022/768] begin working on next version --- docs/conf.py | 2 +- include/pybind11/detail/common.h | 2 +- pybind11/_version.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index c43854629..a1e4e0058 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -63,7 +63,7 @@ author = 'Wenzel Jakob' # The short X.Y version. version = '2.4' # The full version, including alpha/beta/rc tags. -release = '2.4.3' +release = '2.4.dev4' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 6da547060..bb1affcea 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -94,7 +94,7 @@ #define PYBIND11_VERSION_MAJOR 2 #define PYBIND11_VERSION_MINOR 4 -#define PYBIND11_VERSION_PATCH 3 +#define PYBIND11_VERSION_PATCH dev4 /// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode #if defined(_MSC_VER) diff --git a/pybind11/_version.py b/pybind11/_version.py index 2709cc556..5bf3483d2 100644 --- a/pybind11/_version.py +++ b/pybind11/_version.py @@ -1,2 +1,2 @@ -version_info = (2, 4, 3) +version_info = (2, 4, 'dev4') __version__ = '.'.join(map(str, version_info)) From de5a29c0d4ad15271c172cf5dd60c7fd33febb80 Mon Sep 17 00:00:00 2001 From: nicolov Date: Thu, 17 Oct 2019 10:43:33 +0200 Subject: [PATCH 023/768] Fix build with -Wmissing-prototypes (#1954) When building with `-Werror,-Wmissing-prototypes`, `clang` complains about missing prototypes for functions defined through macro expansions. This PR adds the missing prototypes. ``` error: no previous prototype for function 'pybind11_init_impl_embedded' [ -Werror,-Wmissing-prototypes] PYBIND11_EMBEDDED_MODULE(embedded, mod) { ^ external/pybind11/include/pybind11/embed.h:61:5: note: expanded from macro 'PYBIND11_EMBEDDED_MODULE' PYBIND11_EMBEDDED_MODULE_IMPL(name) \ ^ external/pybind11/include/pybind11/embed.h:26:23: note: expanded from macro 'PYBIND11_EMBEDDED_MODULE_IMPL' extern "C" void pybind11_init_impl_##name() { \ ^ :380:1: note: expanded from here pybind11_init_impl_embedded ^ 1 error generated. ``` --- include/pybind11/embed.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/pybind11/embed.h b/include/pybind11/embed.h index 72655885e..f814c783e 100644 --- a/include/pybind11/embed.h +++ b/include/pybind11/embed.h @@ -18,11 +18,13 @@ #if PY_MAJOR_VERSION >= 3 # define PYBIND11_EMBEDDED_MODULE_IMPL(name) \ + extern "C" PyObject *pybind11_init_impl_##name(); \ extern "C" PyObject *pybind11_init_impl_##name() { \ return pybind11_init_wrapper_##name(); \ } #else # define PYBIND11_EMBEDDED_MODULE_IMPL(name) \ + extern "C" void pybind11_init_impl_##name(); \ extern "C" void pybind11_init_impl_##name() { \ pybind11_init_wrapper_##name(); \ } From 6c29cbf88de0df177ec730fc4c85e52bdf8d82c0 Mon Sep 17 00:00:00 2001 From: Riccardo Bertossa <33728857+rikigigi@users.noreply.github.com> Date: Fri, 18 Oct 2019 17:55:17 +0200 Subject: [PATCH 024/768] misleading comment corrected (strides in buffer_info is bytes and not number of entries) (#1958) --- include/pybind11/buffer_info.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/buffer_info.h b/include/pybind11/buffer_info.h index 9f072fa73..b106d2cc6 100644 --- a/include/pybind11/buffer_info.h +++ b/include/pybind11/buffer_info.h @@ -21,7 +21,7 @@ struct buffer_info { std::string format; // For homogeneous buffers, this should be set to format_descriptor::format() ssize_t ndim = 0; // Number of dimensions std::vector shape; // Shape of the tensor (1 entry per dimension) - std::vector strides; // Number of entries between adjacent entries (for each per dimension) + std::vector strides; // Number of bytes between adjacent entries (for each per dimension) buffer_info() { } From 759221f5c56939f59d8f342a41f8e2d2cacbc8cf Mon Sep 17 00:00:00 2001 From: Jeremy Nimmer Date: Fri, 14 Jun 2019 12:12:51 -0400 Subject: [PATCH 025/768] Obey __cpp_sized_deallocation and __cpp_aligned_new Don't assume that just because the language version is C++17 that the standard library offers all C++17 features, too. When using clang-6.0 and --std=c++17 on Ubuntu 18.04 with libstdc++, __cpp_sized_deallocation is false. --- include/pybind11/cast.h | 4 ++-- include/pybind11/pybind11.h | 21 ++++++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 605acb366..efc10d65c 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -574,10 +574,10 @@ public: if (type->operator_new) { vptr = type->operator_new(type->type_size); } else { - #if defined(PYBIND11_CPP17) + #ifdef __cpp_aligned_new if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__) vptr = ::operator new(type->type_size, - (std::align_val_t) type->type_align); + std::align_val_t(type->type_align)); else #endif vptr = ::operator new(type->type_size); diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index c6237056b..513ceed5d 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1003,14 +1003,21 @@ void call_operator_delete(T *p, size_t s, size_t) { T::operator delete(p, s); } inline void call_operator_delete(void *p, size_t s, size_t a) { (void)s; (void)a; -#if defined(PYBIND11_CPP17) - if (a > __STDCPP_DEFAULT_NEW_ALIGNMENT__) - ::operator delete(p, s, std::align_val_t(a)); - else + #ifdef __cpp_aligned_new + if (a > __STDCPP_DEFAULT_NEW_ALIGNMENT__) { + #ifdef __cpp_sized_deallocation + ::operator delete(p, s, std::align_val_t(a)); + #else + ::operator delete(p, std::align_val_t(a)); + #endif + return; + } + #endif + #ifdef __cpp_sized_deallocation ::operator delete(p, s); -#else - ::operator delete(p); -#endif + #else + ::operator delete(p); + #endif } NAMESPACE_END(detail) From c27a6e1378e6e3e438ed3542246db470fea35fa7 Mon Sep 17 00:00:00 2001 From: Hans Dembinski Date: Tue, 22 Oct 2019 16:19:15 +0100 Subject: [PATCH 026/768] make builds with python tests and cpp tests fail if either one fails (#1967) --- .travis.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 28f35f995..2d242b4b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,8 +32,7 @@ matrix: - | # Barebones build cmake -DCMAKE_BUILD_TYPE=Debug -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DPYTHON_EXECUTABLE=$(which $PY_CMD) . - make pytest -j 2 - make cpptest -j 2 + make pytest -j 2 && make cpptest -j 2 # The following are regular test configurations, including optional dependencies. # With regard to each other they differ in Python version, C++ standard and compiler. - os: linux @@ -131,8 +130,7 @@ matrix: - | # Barebones build cmake -DCMAKE_BUILD_TYPE=Debug -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DPYTHON_EXECUTABLE=$(which $PY_CMD) . - make pytest -j 2 - make cpptest -j 2 + make pytest -j 2 && make cpptest -j 2 - os: osx name: Python 2.7, c++14, AppleClang 7.3, CMake test osx_image: xcode7.3 From bdf6a5e8708abe87d42e0e4c8bef51db0f0957ff Mon Sep 17 00:00:00 2001 From: Hans Dembinski Date: Wed, 23 Oct 2019 12:19:58 +0100 Subject: [PATCH 027/768] Report type names in return value policy-related cast exceptions (#1965) --- include/pybind11/cast.h | 29 +++++++++++++++++++++++------ tests/test_copy_move.py | 6 +++--- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index efc10d65c..e1bbf03aa 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -533,9 +533,17 @@ public: case return_value_policy::copy: if (copy_constructor) valueptr = copy_constructor(src); - else - throw cast_error("return_value_policy = copy, but the " - "object is non-copyable!"); + else { +#if defined(NDEBUG) + throw cast_error("return_value_policy = copy, but type is " + "non-copyable! (compile in debug mode for details)"); +#else + std::string type_name(tinfo->cpptype->name()); + detail::clean_type_id(type_name); + throw cast_error("return_value_policy = copy, but type " + + type_name + " is non-copyable!"); +#endif + } wrapper->owned = true; break; @@ -544,9 +552,18 @@ public: valueptr = move_constructor(src); else if (copy_constructor) valueptr = copy_constructor(src); - else - throw cast_error("return_value_policy = move, but the " - "object is neither movable nor copyable!"); + else { +#if defined(NDEBUG) + throw cast_error("return_value_policy = move, but type is neither " + "movable nor copyable! " + "(compile in debug mode for details)"); +#else + std::string type_name(tinfo->cpptype->name()); + detail::clean_type_id(type_name); + throw cast_error("return_value_policy = move, but type " + + type_name + " is neither movable nor copyable!"); +#endif + } wrapper->owned = true; break; diff --git a/tests/test_copy_move.py b/tests/test_copy_move.py index aff2d99f2..0e671d969 100644 --- a/tests/test_copy_move.py +++ b/tests/test_copy_move.py @@ -5,13 +5,13 @@ from pybind11_tests import copy_move_policies as m def test_lacking_copy_ctor(): with pytest.raises(RuntimeError) as excinfo: m.lacking_copy_ctor.get_one() - assert "the object is non-copyable!" in str(excinfo.value) + assert "is non-copyable!" in str(excinfo.value) def test_lacking_move_ctor(): with pytest.raises(RuntimeError) as excinfo: m.lacking_move_ctor.get_one() - assert "the object is neither movable nor copyable!" in str(excinfo.value) + assert "is neither movable nor copyable!" in str(excinfo.value) def test_move_and_copy_casts(): @@ -98,7 +98,7 @@ def test_private_op_new(): with pytest.raises(RuntimeError) as excinfo: m.private_op_new_value() - assert "the object is neither movable nor copyable" in str(excinfo.value) + assert "is neither movable nor copyable" in str(excinfo.value) assert m.private_op_new_reference().value == 1 From a83d69e78ffe58bbd410aa7503384a312e08963b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Gs=C3=A4nger?= <8004308+sgsaenger@users.noreply.github.com> Date: Thu, 31 Oct 2019 12:38:24 +0100 Subject: [PATCH 028/768] test pair-copyability on C++17 upwards (#1886) * test pair-copyability on C++17 upwards The stdlib falsely detects containers like M=std::map as copyable, even when one of T and U is not copyable. Therefore we cannot rely on the stdlib dismissing std::pair by itself, even on C++17. * fix is_copy_assignable bind_map used std::is_copy_assignable which suffers from the same problems as std::is_copy_constructible, therefore the same fix has been applied. * created tests for copyability --- include/pybind11/cast.h | 16 ++++++++++++---- include/pybind11/stl_bind.h | 4 ++-- tests/test_stl_binders.cpp | 22 +++++++++++++++++++++ tests/test_stl_binders.py | 38 +++++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 6 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index e1bbf03aa..90407eb98 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -797,12 +797,20 @@ template struct is_copy_constructible> >::value>> : is_copy_constructible {}; -#if !defined(PYBIND11_CPP17) -// Likewise for std::pair before C++17 (which mandates that the copy constructor not exist when the -// two types aren't themselves copy constructible). +// Likewise for std::pair +// (after C++17 it is mandatory that the copy constructor not exist when the two types aren't themselves +// copy constructible, but this can not be relied upon when T1 or T2 are themselves containers). template struct is_copy_constructible> : all_of, is_copy_constructible> {}; -#endif + +// The same problems arise with std::is_copy_assignable, so we use the same workaround. +template struct is_copy_assignable : std::is_copy_assignable {}; +template struct is_copy_assignable, + std::is_same + >::value>> : is_copy_assignable {}; +template struct is_copy_assignable> + : all_of, is_copy_assignable> {}; NAMESPACE_END(detail) diff --git a/include/pybind11/stl_bind.h b/include/pybind11/stl_bind.h index d3adaed3a..62bd90819 100644 --- a/include/pybind11/stl_bind.h +++ b/include/pybind11/stl_bind.h @@ -512,7 +512,7 @@ template void map_assignment(const Args & // Map assignment when copy-assignable: just copy the value template -void map_assignment(enable_if_t::value, Class_> &cl) { +void map_assignment(enable_if_t::value, Class_> &cl) { using KeyType = typename Map::key_type; using MappedType = typename Map::mapped_type; @@ -528,7 +528,7 @@ void map_assignment(enable_if_t void map_assignment(enable_if_t< - !std::is_copy_assignable::value && + !is_copy_assignable::value && is_copy_constructible::value, Class_> &cl) { using KeyType = typename Map::key_type; diff --git a/tests/test_stl_binders.cpp b/tests/test_stl_binders.cpp index a88b589e1..868887409 100644 --- a/tests/test_stl_binders.cpp +++ b/tests/test_stl_binders.cpp @@ -54,6 +54,14 @@ template Map *times_ten(int n) { return m; } +template NestMap *times_hundred(int n) { + auto m = new NestMap(); + for (int i = 1; i <= n; i++) + for (int j = 1; j <= n; j++) + (*m)[i].emplace(int(j*10), E_nc(100*j)); + return m; +} + TEST_SUBMODULE(stl_binders, m) { // test_vector_int py::bind_vector>(m, "VectorInt", py::buffer_protocol()); @@ -85,6 +93,20 @@ TEST_SUBMODULE(stl_binders, m) { m.def("get_mnc", ×_ten>, py::return_value_policy::reference); py::bind_map>(m, "UmapENC"); m.def("get_umnc", ×_ten>, py::return_value_policy::reference); + // Issue #1885: binding nested std::map> with E non-copyable + py::bind_map>>(m, "MapVecENC"); + m.def("get_nvnc", [](int n) + { + auto m = new std::map>(); + for (int i = 1; i <= n; i++) + for (int j = 1; j <= n; j++) + (*m)[i].emplace_back(j); + return m; + }, py::return_value_policy::reference); + py::bind_map>>(m, "MapMapENC"); + m.def("get_nmnc", ×_hundred>>, py::return_value_policy::reference); + py::bind_map>>(m, "UmapUmapENC"); + m.def("get_numnc", ×_hundred>>, py::return_value_policy::reference); // test_vector_buffer py::bind_vector>(m, "VectorUChar", py::buffer_protocol()); diff --git a/tests/test_stl_binders.py b/tests/test_stl_binders.py index 6d5a15983..b83a587f2 100644 --- a/tests/test_stl_binders.py +++ b/tests/test_stl_binders.py @@ -212,6 +212,44 @@ def test_noncopyable_containers(): assert vsum == 150 + # nested std::map + nvnc = m.get_nvnc(5) + for i in range(1, 6): + for j in range(0, 5): + assert nvnc[i][j].value == j + 1 + + for k, v in nvnc.items(): + for i, j in enumerate(v, start=1): + assert j.value == i + + # nested std::map + nmnc = m.get_nmnc(5) + for i in range(1, 6): + for j in range(10, 60, 10): + assert nmnc[i][j].value == 10 * j + + vsum = 0 + for k_o, v_o in nmnc.items(): + for k_i, v_i in v_o.items(): + assert v_i.value == 10 * k_i + vsum += v_i.value + + assert vsum == 7500 + + # nested std::unordered_map + numnc = m.get_numnc(5) + for i in range(1, 6): + for j in range(10, 60, 10): + assert numnc[i][j].value == 10 * j + + vsum = 0 + for k_o, v_o in numnc.items(): + for k_i, v_i in v_o.items(): + assert v_i.value == 10 * k_i + vsum += v_i.value + + assert vsum == 7500 + def test_map_delitem(): mm = m.MapStringDouble() From a6355b00f84d997a9ddcf209b6464447432be78a Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Thu, 31 Oct 2019 04:40:15 -0700 Subject: [PATCH 029/768] CMake: Add Python 3.8 to pybind11Tools (#1974) Add Python 3.8 to considered versions in CMake for additional hints. https://cmake.org/cmake/help/v3.2/module/FindPythonLibs.html --- tools/pybind11Tools.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pybind11Tools.cmake b/tools/pybind11Tools.cmake index c7156c020..d0a2bfc8b 100644 --- a/tools/pybind11Tools.cmake +++ b/tools/pybind11Tools.cmake @@ -12,7 +12,7 @@ if(NOT PYBIND11_PYTHON_VERSION) set(PYBIND11_PYTHON_VERSION "" CACHE STRING "Python version to use for compiling modules") endif() -set(Python_ADDITIONAL_VERSIONS 3.7 3.6 3.5 3.4) +set(Python_ADDITIONAL_VERSIONS 3.8 3.7 3.6 3.5 3.4) find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} REQUIRED) include(CheckCXXCompilerFlag) From 6f11347a3077fd859153967bcea4b82a418beb1b Mon Sep 17 00:00:00 2001 From: Matthew Dawkins Date: Thu, 14 Nov 2019 02:53:06 -0500 Subject: [PATCH 030/768] Prevent cmake error when prefix empty (#1986) --- tools/FindPythonLibsNew.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/FindPythonLibsNew.cmake b/tools/FindPythonLibsNew.cmake index e660c5f3e..52c92f1e4 100644 --- a/tools/FindPythonLibsNew.cmake +++ b/tools/FindPythonLibsNew.cmake @@ -140,9 +140,9 @@ list(GET _PYTHON_VERSION_LIST 1 PYTHON_VERSION_MINOR) list(GET _PYTHON_VERSION_LIST 2 PYTHON_VERSION_PATCH) # Make sure all directory separators are '/' -string(REGEX REPLACE "\\\\" "/" PYTHON_PREFIX ${PYTHON_PREFIX}) -string(REGEX REPLACE "\\\\" "/" PYTHON_INCLUDE_DIR ${PYTHON_INCLUDE_DIR}) -string(REGEX REPLACE "\\\\" "/" PYTHON_SITE_PACKAGES ${PYTHON_SITE_PACKAGES}) +string(REGEX REPLACE "\\\\" "/" PYTHON_PREFIX "${PYTHON_PREFIX}") +string(REGEX REPLACE "\\\\" "/" PYTHON_INCLUDE_DIR "${PYTHON_INCLUDE_DIR}") +string(REGEX REPLACE "\\\\" "/" PYTHON_SITE_PACKAGES "${PYTHON_SITE_PACKAGES}") if(CMAKE_HOST_WIN32 AND NOT (MSYS OR MINGW)) set(PYTHON_LIBRARY From b32b762c60c0325fe5b3577de3061ba3ed893605 Mon Sep 17 00:00:00 2001 From: Erick Matsen Date: Wed, 13 Nov 2019 23:53:30 -0800 Subject: [PATCH 031/768] Fixing minor typo in basics.rst (#1984) --- docs/basics.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/basics.rst b/docs/basics.rst index 447250ed9..7bf4d426d 100644 --- a/docs/basics.rst +++ b/docs/basics.rst @@ -164,7 +164,7 @@ load and execute the example: Keyword arguments ================= -With a simple modification code, it is possible to inform Python about the +With a simple code modification, it is possible to inform Python about the names of the arguments ("i" and "j" in this case). .. code-block:: cpp From 55ff464233a189a085f1f7b1f7969b2f4fbc344b Mon Sep 17 00:00:00 2001 From: Yannick Jadoul Date: Thu, 14 Nov 2019 08:55:34 +0100 Subject: [PATCH 032/768] Fixing SystemError when nb_bool/nb_nonzero sets a Python exception in type_caster::load (#1976) --- include/pybind11/cast.h | 2 ++ tests/test_builtin_casters.py | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 90407eb98..3d4a759c3 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1172,6 +1172,8 @@ public: if (res == 0 || res == 1) { value = (bool) res; return true; + } else { + PyErr_Clear(); } } return false; diff --git a/tests/test_builtin_casters.py b/tests/test_builtin_casters.py index 73cc465f5..abbfcec49 100644 --- a/tests/test_builtin_casters.py +++ b/tests/test_builtin_casters.py @@ -318,11 +318,15 @@ def test_numpy_bool(): import numpy as np convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert + def cant_convert(v): + pytest.raises(TypeError, convert, v) + # np.bool_ is not considered implicit assert convert(np.bool_(True)) is True assert convert(np.bool_(False)) is False assert noconvert(np.bool_(True)) is True assert noconvert(np.bool_(False)) is False + cant_convert(np.zeros(2, dtype='int')) def test_int_long(): From deb3cb238a9f299d7c57f810165e90a1b14b3e6f Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Thu, 14 Nov 2019 08:56:58 +0100 Subject: [PATCH 033/768] Add exception translation for std::overflow_error. (#1977) --- docs/advanced/exceptions.rst | 2 ++ include/pybind11/detail/internals.h | 1 + tests/test_exceptions.cpp | 1 + tests/test_exceptions.py | 4 ++++ 4 files changed, 8 insertions(+) diff --git a/docs/advanced/exceptions.rst b/docs/advanced/exceptions.rst index 75ac24ae9..75ad7f7f4 100644 --- a/docs/advanced/exceptions.rst +++ b/docs/advanced/exceptions.rst @@ -28,6 +28,8 @@ exceptions: +--------------------------------------+--------------------------------------+ | :class:`std::range_error` | ``ValueError`` | +--------------------------------------+--------------------------------------+ +| :class:`std::overflow_error` | ``OverflowError`` | ++--------------------------------------+--------------------------------------+ | :class:`pybind11::stop_iteration` | ``StopIteration`` (used to implement | | | custom iterators) | +--------------------------------------+--------------------------------------+ diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 067780c26..87952daba 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -211,6 +211,7 @@ inline void translate_exception(std::exception_ptr p) { } catch (const std::length_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; } catch (const std::out_of_range &e) { PyErr_SetString(PyExc_IndexError, e.what()); return; } catch (const std::range_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; + } catch (const std::overflow_error &e) { PyErr_SetString(PyExc_OverflowError, e.what()); return; } catch (const std::exception &e) { PyErr_SetString(PyExc_RuntimeError, e.what()); return; } catch (...) { PyErr_SetString(PyExc_RuntimeError, "Caught an unknown exception!"); diff --git a/tests/test_exceptions.cpp b/tests/test_exceptions.cpp index d30139037..56cd9bc48 100644 --- a/tests/test_exceptions.cpp +++ b/tests/test_exceptions.cpp @@ -116,6 +116,7 @@ TEST_SUBMODULE(exceptions, m) { m.def("throws5", []() { throw MyException5("this is a helper-defined translated exception"); }); m.def("throws5_1", []() { throw MyException5_1("MyException5 subclass"); }); m.def("throws_logic_error", []() { throw std::logic_error("this error should fall through to the standard handler"); }); + m.def("throws_overflow_error", []() {throw std::overflow_error(""); }); m.def("exception_matches", []() { py::dict foo; try { diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 6edff9fe4..ac2b3603e 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -79,6 +79,10 @@ def test_custom(msg): m.throws_logic_error() assert msg(excinfo.value) == "this error should fall through to the standard handler" + # OverFlow error translation. + with pytest.raises(OverflowError) as excinfo: + m.throws_overflow_error() + # Can we handle a helper-declared exception? with pytest.raises(m.MyException5) as excinfo: m.throws5() From bd24155b8bf798f9f7022b39acd6d92e52d642d6 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Sat, 16 Nov 2019 01:18:24 +0100 Subject: [PATCH 034/768] Aligned allocation fix for clang-cl (#1988) --- include/pybind11/cast.h | 2 +- include/pybind11/pybind11.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 3d4a759c3..ad225312d 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -591,7 +591,7 @@ public: if (type->operator_new) { vptr = type->operator_new(type->type_size); } else { - #ifdef __cpp_aligned_new + #if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912) if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__) vptr = ::operator new(type->type_size, std::align_val_t(type->type_align)); diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 513ceed5d..d95d61f7b 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1003,7 +1003,7 @@ void call_operator_delete(T *p, size_t s, size_t) { T::operator delete(p, s); } inline void call_operator_delete(void *p, size_t s, size_t a) { (void)s; (void)a; - #ifdef __cpp_aligned_new + #if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912) if (a > __STDCPP_DEFAULT_NEW_ALIGNMENT__) { #ifdef __cpp_sized_deallocation ::operator delete(p, s, std::align_val_t(a)); From dc65d661718ed10a9d212f1949813f7a7acf9437 Mon Sep 17 00:00:00 2001 From: Sebastian Koslowski Date: Sun, 24 Nov 2019 08:33:05 +0100 Subject: [PATCH 035/768] support for readonly buffers (#863) (#1466) --- include/pybind11/buffer_info.h | 28 +++++++++++++++++----------- include/pybind11/detail/class.h | 7 +++++++ include/pybind11/pytypes.h | 2 +- tests/constructor_stats.h | 2 +- tests/test_buffers.cpp | 26 ++++++++++++++++++++++++++ tests/test_buffers.py | 31 +++++++++++++++++++++++++++++++ 6 files changed, 83 insertions(+), 13 deletions(-) diff --git a/include/pybind11/buffer_info.h b/include/pybind11/buffer_info.h index b106d2cc6..1f4115a1f 100644 --- a/include/pybind11/buffer_info.h +++ b/include/pybind11/buffer_info.h @@ -22,13 +22,14 @@ struct buffer_info { ssize_t ndim = 0; // Number of dimensions std::vector shape; // Shape of the tensor (1 entry per dimension) std::vector strides; // Number of bytes between adjacent entries (for each per dimension) + bool readonly = false; // flag to indicate if the underlying storage may be written to buffer_info() { } buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim, - detail::any_container shape_in, detail::any_container strides_in) + detail::any_container shape_in, detail::any_container strides_in, bool readonly=false) : ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim), - shape(std::move(shape_in)), strides(std::move(strides_in)) { + shape(std::move(shape_in)), strides(std::move(strides_in)), readonly(readonly) { if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length"); for (size_t i = 0; i < (size_t) ndim; ++i) @@ -36,19 +37,23 @@ struct buffer_info { } template - buffer_info(T *ptr, detail::any_container shape_in, detail::any_container strides_in) - : buffer_info(private_ctr_tag(), ptr, sizeof(T), format_descriptor::format(), static_cast(shape_in->size()), std::move(shape_in), std::move(strides_in)) { } + buffer_info(T *ptr, detail::any_container shape_in, detail::any_container strides_in, bool readonly=false) + : buffer_info(private_ctr_tag(), ptr, sizeof(T), format_descriptor::format(), static_cast(shape_in->size()), std::move(shape_in), std::move(strides_in), readonly) { } - buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t size) - : buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}) { } + buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t size, bool readonly=false) + : buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}, readonly) { } template - buffer_info(T *ptr, ssize_t size) - : buffer_info(ptr, sizeof(T), format_descriptor::format(), size) { } + buffer_info(T *ptr, ssize_t size, bool readonly=false) + : buffer_info(ptr, sizeof(T), format_descriptor::format(), size, readonly) { } + + template + buffer_info(const T *ptr, ssize_t size, bool readonly=true) + : buffer_info(const_cast(ptr), sizeof(T), format_descriptor::format(), size, readonly) { } explicit buffer_info(Py_buffer *view, bool ownview = true) : buffer_info(view->buf, view->itemsize, view->format, view->ndim, - {view->shape, view->shape + view->ndim}, {view->strides, view->strides + view->ndim}) { + {view->shape, view->shape + view->ndim}, {view->strides, view->strides + view->ndim}, view->readonly) { this->view = view; this->ownview = ownview; } @@ -70,6 +75,7 @@ struct buffer_info { strides = std::move(rhs.strides); std::swap(view, rhs.view); std::swap(ownview, rhs.ownview); + readonly = rhs.readonly; return *this; } @@ -81,8 +87,8 @@ private: struct private_ctr_tag { }; buffer_info(private_ctr_tag, void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim, - detail::any_container &&shape_in, detail::any_container &&strides_in) - : buffer_info(ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in)) { } + detail::any_container &&shape_in, detail::any_container &&strides_in, bool readonly) + : buffer_info(ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) { } Py_buffer *view = nullptr; bool ownview = false; diff --git a/include/pybind11/detail/class.h b/include/pybind11/detail/class.h index 230ae81ae..edfa7de68 100644 --- a/include/pybind11/detail/class.h +++ b/include/pybind11/detail/class.h @@ -491,6 +491,13 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla view->len = view->itemsize; for (auto s : info->shape) view->len *= s; + view->readonly = info->readonly; + if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE && info->readonly) { + if (view) + view->obj = nullptr; + PyErr_SetString(PyExc_BufferError, "Writable buffer requested for readonly storage"); + return -1; + } if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) view->format = const_cast(info->format.c_str()); if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) { diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 96eab9662..4003d6918 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -1345,7 +1345,7 @@ public: buf.strides = py_strides.data(); buf.shape = py_shape.data(); buf.suboffsets = nullptr; - buf.readonly = false; + buf.readonly = info.readonly; buf.internal = nullptr; m_ptr = PyMemoryView_FromBuffer(&buf); diff --git a/tests/constructor_stats.h b/tests/constructor_stats.h index f026e70f9..431e5acef 100644 --- a/tests/constructor_stats.h +++ b/tests/constructor_stats.h @@ -180,7 +180,7 @@ public: } } } - catch (const std::out_of_range &) {} + catch (const std::out_of_range&) {} if (!t1) throw std::runtime_error("Unknown class passed to ConstructorStats::get()"); auto &cs1 = get(*t1); // If we have both a t1 and t2 match, one is probably the trampoline class; return whichever diff --git a/tests/test_buffers.cpp b/tests/test_buffers.cpp index 433dfeee6..1bc67ff7b 100644 --- a/tests/test_buffers.cpp +++ b/tests/test_buffers.cpp @@ -166,4 +166,30 @@ TEST_SUBMODULE(buffers, m) { .def_readwrite("value", (int32_t DerivedBuffer::*) &DerivedBuffer::value) .def_buffer(&DerivedBuffer::get_buffer_info); + struct BufferReadOnly { + const uint8_t value = 0; + BufferReadOnly(uint8_t value): value(value) {} + + py::buffer_info get_buffer_info() { + return py::buffer_info(&value, 1); + } + }; + py::class_(m, "BufferReadOnly", py::buffer_protocol()) + .def(py::init()) + .def_buffer(&BufferReadOnly::get_buffer_info); + + struct BufferReadOnlySelect { + uint8_t value = 0; + bool readonly = false; + + py::buffer_info get_buffer_info() { + return py::buffer_info(&value, 1, readonly); + } + }; + py::class_(m, "BufferReadOnlySelect", py::buffer_protocol()) + .def(py::init<>()) + .def_readwrite("value", &BufferReadOnlySelect::value) + .def_readwrite("readonly", &BufferReadOnlySelect::readonly) + .def_buffer(&BufferReadOnlySelect::get_buffer_info); + } diff --git a/tests/test_buffers.py b/tests/test_buffers.py index f006552bf..bf7aaed70 100644 --- a/tests/test_buffers.py +++ b/tests/test_buffers.py @@ -1,8 +1,14 @@ +import io import struct +import sys + import pytest + from pybind11_tests import buffers as m from pybind11_tests import ConstructorStats +PY3 = sys.version_info[0] >= 3 + pytestmark = pytest.requires_numpy with pytest.suppress(ImportError): @@ -85,3 +91,28 @@ def test_pointer_to_member_fn(): buf.value = 0x12345678 value = struct.unpack('i', bytearray(buf))[0] assert value == 0x12345678 + + +@pytest.unsupported_on_pypy +def test_readonly_buffer(): + buf = m.BufferReadOnly(0x64) + view = memoryview(buf) + assert view[0] == 0x64 if PY3 else b'd' + assert view.readonly + + +@pytest.unsupported_on_pypy +def test_selective_readonly_buffer(): + buf = m.BufferReadOnlySelect() + + memoryview(buf)[0] = 0x64 if PY3 else b'd' + assert buf.value == 0x64 + + io.BytesIO(b'A').readinto(buf) + assert buf.value == ord(b'A') + + buf.readonly = True + with pytest.raises(TypeError): + memoryview(buf)[0] = 0 if PY3 else b'\0' + with pytest.raises(TypeError): + io.BytesIO(b'1').readinto(buf) From 0f1d3bfee2b5a7e52643fbaa46268c73ebb0497a Mon Sep 17 00:00:00 2001 From: Charles Brossollet Date: Mon, 25 Nov 2019 10:59:53 +0100 Subject: [PATCH 036/768] Add FAQ entry for dealing with long functions interruption (#2000) * Add FAQ entry, with code example, for dealing with long functions interruption --- docs/faq.rst | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/docs/faq.rst b/docs/faq.rst index 93ccf10e5..a7cbbfdf4 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -248,6 +248,41 @@ that that were ``malloc()``-ed in another shared library, using data structures with incompatible ABIs, and so on. pybind11 is very careful not to make these types of mistakes. +How can I properly handle Ctrl-C in long-running functions? +=========================================================== + +Ctrl-C is received by the Python interpreter, and holds it until the GIL +is released, so a long-running function won't be interrupted. + +To interrupt from inside your function, you can use the ``PyErr_CheckSignals()`` +function, that will tell if a signal has been raised on the Python side. This +function merely checks a flag, so its impact is negligible. When a signal has +been received, you can explicitely interrupt execution by throwing an exception +that gets translated to KeyboardInterrupt (see :doc:`advanced/exceptions` +section): + +.. code-block:: cpp + + class interruption_error: public std::exception { + public: + const char* what() const noexcept { + return "Interruption signal caught."; + } + }; + + PYBIND11_MODULE(example, m) + { + m.def("long running_func", []() + { + for (;;) { + if (PyErr_CheckSignals() != 0) + throw interruption_error(); + // Long running iteration + } + }); + py::register_exception(m, "KeyboardInterrupt"); + } + Inconsistent detection of Python version in CMake and pybind11 ============================================================== From baf69345f6f252302ca5378a4568f33be178b8a8 Mon Sep 17 00:00:00 2001 From: Eric Cousineau Date: Mon, 25 Nov 2019 09:14:06 -0500 Subject: [PATCH 037/768] Minor modifications to interrupt handling FAQ (#2007) --- docs/faq.rst | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/docs/faq.rst b/docs/faq.rst index a7cbbfdf4..4d491fb87 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -257,30 +257,22 @@ is released, so a long-running function won't be interrupted. To interrupt from inside your function, you can use the ``PyErr_CheckSignals()`` function, that will tell if a signal has been raised on the Python side. This function merely checks a flag, so its impact is negligible. When a signal has -been received, you can explicitely interrupt execution by throwing an exception -that gets translated to KeyboardInterrupt (see :doc:`advanced/exceptions` -section): +been received, you must either explicitly interrupt execution by throwing +``py::error_already_set`` (which will propagate the existing +``KeyboardInterrupt``), or clear the error (which you usually will not want): .. code-block:: cpp - class interruption_error: public std::exception { - public: - const char* what() const noexcept { - return "Interruption signal caught."; - } - }; - PYBIND11_MODULE(example, m) { m.def("long running_func", []() { for (;;) { if (PyErr_CheckSignals() != 0) - throw interruption_error(); + throw py::error_already_set(); // Long running iteration } }); - py::register_exception(m, "KeyboardInterrupt"); } Inconsistent detection of Python version in CMake and pybind11 From 61e4f1182357cc0f55b567b128011c579e4c7ccd Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Thu, 28 Nov 2019 07:42:34 +0100 Subject: [PATCH 038/768] numpy.h: minor preprocessor fix suggested by @chaekwan --- 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 ba41a223d..c544c544f 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -311,7 +311,7 @@ template using remove_all_extents_t = typename array_info::type; template using is_pod_struct = all_of< std::is_standard_layout, // since we're accessing directly in memory we need a standard layout type -#if !defined(__GNUG__) || defined(_LIBCPP_VERSION) || defined(_GLIBCXX_USE_CXX11_ABI) +#if !defined(__GNUG__) || defined(_LIBCPP_VERSION) || (defined(_GLIBCXX_USE_CXX11_ABI) && _GLIBCXX_USE_CXX11_ABI != 0) // _GLIBCXX_USE_CXX11_ABI indicates that we're using libstdc++ from GCC 5 or newer, independent // of the actual compiler (Clang can also use libstdc++, but it always defines __GNUC__ == 4). std::is_trivially_copyable, From a60648223d409c51804be63a097eeaae383e8a7c Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Thu, 28 Nov 2019 08:07:32 +0100 Subject: [PATCH 039/768] Revert "numpy.h: minor preprocessor fix suggested by @chaekwan" This reverts commit 61e4f1182357cc0f55b567b128011c579e4c7ccd. --- 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 c544c544f..ba41a223d 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -311,7 +311,7 @@ template using remove_all_extents_t = typename array_info::type; template using is_pod_struct = all_of< std::is_standard_layout, // since we're accessing directly in memory we need a standard layout type -#if !defined(__GNUG__) || defined(_LIBCPP_VERSION) || (defined(_GLIBCXX_USE_CXX11_ABI) && _GLIBCXX_USE_CXX11_ABI != 0) +#if !defined(__GNUG__) || defined(_LIBCPP_VERSION) || defined(_GLIBCXX_USE_CXX11_ABI) // _GLIBCXX_USE_CXX11_ABI indicates that we're using libstdc++ from GCC 5 or newer, independent // of the actual compiler (Clang can also use libstdc++, but it always defines __GNUC__ == 4). std::is_trivially_copyable, From 37352491225358b97ce302273bf2d887a477efb0 Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Thu, 28 Nov 2019 01:59:23 -0600 Subject: [PATCH 040/768] Install headers using both headers and package_data (#1995) --- pybind11/__init__.py | 36 ++++------------------- pybind11/__main__.py | 3 +- setup.py | 68 ++++++++++++++++++++++++++------------------ 3 files changed, 48 insertions(+), 59 deletions(-) diff --git a/pybind11/__init__.py b/pybind11/__init__.py index c625e8c94..4b1de3efa 100644 --- a/pybind11/__init__.py +++ b/pybind11/__init__.py @@ -2,35 +2,11 @@ from ._version import version_info, __version__ # noqa: F401 imported but unuse def get_include(user=False): - from distutils.dist import Distribution import os - import sys - - # Are we running in a virtual environment? - virtualenv = hasattr(sys, 'real_prefix') or \ - sys.prefix != getattr(sys, "base_prefix", sys.prefix) - - # Are we running in a conda environment? - conda = os.path.exists(os.path.join(sys.prefix, 'conda-meta')) - - if virtualenv: - return os.path.join(sys.prefix, 'include', 'site', - 'python' + sys.version[:3]) - elif conda: - if os.name == 'nt': - return os.path.join(sys.prefix, 'Library', 'include') - else: - return os.path.join(sys.prefix, 'include') + d = os.path.dirname(__file__) + if os.path.exists(os.path.join(d, "include")): + # Package is installed + return os.path.join(d, "include") else: - dist = Distribution({'name': 'pybind11'}) - dist.parse_config_files() - - dist_cobj = dist.get_command_obj('install', create=True) - - # Search for packages in user's home directory? - if user: - dist_cobj.user = user - dist_cobj.prefix = "" - dist_cobj.finalize_options() - - return os.path.dirname(dist_cobj.install_headers) + # Package is from a source directory + return os.path.join(os.path.dirname(d), "include") diff --git a/pybind11/__main__.py b/pybind11/__main__.py index 9ef837802..89b263a8a 100644 --- a/pybind11/__main__.py +++ b/pybind11/__main__.py @@ -10,8 +10,7 @@ from . import get_include def print_includes(): dirs = [sysconfig.get_path('include'), sysconfig.get_path('platinclude'), - get_include(), - get_include(True)] + get_include()] # Make unique but preserve order unique_dirs = [] diff --git a/setup.py b/setup.py index f677f2af4..473ea1ee0 100644 --- a/setup.py +++ b/setup.py @@ -4,40 +4,43 @@ from setuptools import setup from distutils.command.install_headers import install_headers +from distutils.command.build_py import build_py from pybind11 import __version__ import os +package_data = [ + 'include/pybind11/detail/class.h', + 'include/pybind11/detail/common.h', + 'include/pybind11/detail/descr.h', + 'include/pybind11/detail/init.h', + 'include/pybind11/detail/internals.h', + 'include/pybind11/detail/typeid.h', + 'include/pybind11/attr.h', + 'include/pybind11/buffer_info.h', + 'include/pybind11/cast.h', + 'include/pybind11/chrono.h', + 'include/pybind11/common.h', + 'include/pybind11/complex.h', + 'include/pybind11/eigen.h', + 'include/pybind11/embed.h', + 'include/pybind11/eval.h', + 'include/pybind11/functional.h', + 'include/pybind11/iostream.h', + 'include/pybind11/numpy.h', + 'include/pybind11/operators.h', + 'include/pybind11/options.h', + 'include/pybind11/pybind11.h', + 'include/pybind11/pytypes.h', + 'include/pybind11/stl.h', + 'include/pybind11/stl_bind.h', +] + # Prevent installation of pybind11 headers by setting # PYBIND11_USE_CMAKE. if os.environ.get('PYBIND11_USE_CMAKE'): headers = [] else: - headers = [ - 'include/pybind11/detail/class.h', - 'include/pybind11/detail/common.h', - 'include/pybind11/detail/descr.h', - 'include/pybind11/detail/init.h', - 'include/pybind11/detail/internals.h', - 'include/pybind11/detail/typeid.h', - 'include/pybind11/attr.h', - 'include/pybind11/buffer_info.h', - 'include/pybind11/cast.h', - 'include/pybind11/chrono.h', - 'include/pybind11/common.h', - 'include/pybind11/complex.h', - 'include/pybind11/eigen.h', - 'include/pybind11/embed.h', - 'include/pybind11/eval.h', - 'include/pybind11/functional.h', - 'include/pybind11/iostream.h', - 'include/pybind11/numpy.h', - 'include/pybind11/operators.h', - 'include/pybind11/options.h', - 'include/pybind11/pybind11.h', - 'include/pybind11/pytypes.h', - 'include/pybind11/stl.h', - 'include/pybind11/stl_bind.h', - ] + headers = package_data class InstallHeaders(install_headers): @@ -55,6 +58,16 @@ class InstallHeaders(install_headers): self.outfiles.append(out) +# Install the headers inside the package as well +class BuildPy(build_py): + def build_package_data(self): + build_py.build_package_data(self) + for header in package_data: + target = os.path.join(self.build_lib, 'pybind11', header) + self.mkpath(os.path.dirname(target)) + self.copy_file(header, target, preserve_mode=False) + + setup( name='pybind11', version=__version__, @@ -66,7 +79,8 @@ setup( packages=['pybind11'], license='BSD', headers=headers, - cmdclass=dict(install_headers=InstallHeaders), + zip_safe=False, + cmdclass=dict(install_headers=InstallHeaders, build_py=BuildPy), classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', From fe2a06e339ac8d10eb0b23dc8d77afbf08044667 Mon Sep 17 00:00:00 2001 From: Boris Staletic Date: Wed, 11 Dec 2019 12:04:35 +0100 Subject: [PATCH 041/768] Pin breathe to 4.13.1 --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2d242b4b3..b421d8f6c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,8 @@ matrix: - PY_CMD=python3 - $PY_CMD -m pip install --user --upgrade pip wheel setuptools install: - - $PY_CMD -m pip install --user --upgrade sphinx sphinx_rtd_theme breathe flake8 pep8-naming pytest + # breathe 4.14 doesn't work with bit fields. See https://github.com/michaeljones/breathe/issues/462 + - $PY_CMD -m pip install --user --upgrade sphinx sphinx_rtd_theme breathe==4.13.1 flake8 pep8-naming pytest - curl -fsSL https://sourceforge.net/projects/doxygen/files/rel-1.8.15/doxygen-1.8.15.linux.bin.tar.gz/download | tar xz - export PATH="$PWD/doxygen-1.8.15/bin:$PATH" script: From dc9006db4f97d9b73cb919b2db691c0fe56bcdb4 Mon Sep 17 00:00:00 2001 From: Boris Staletic Date: Wed, 11 Dec 2019 12:05:01 +0100 Subject: [PATCH 042/768] Use newer macOS image for python3 testing --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b421d8f6c..56682556d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -138,7 +138,7 @@ matrix: env: PYTHON=2.7 CPP=14 CLANG CMAKE=1 - os: osx name: Python 3.7, c++14, AppleClang 9, Debug build - osx_image: xcode9 + osx_image: xcode9.4 env: PYTHON=3.7 CPP=14 CLANG DEBUG=1 # Test a PyPy 2.7 build - os: linux From 819802da9926535714acf2bffe690b04f90cb12b Mon Sep 17 00:00:00 2001 From: Nils Berg Date: Wed, 11 Dec 2019 15:01:45 +0000 Subject: [PATCH 043/768] Fix a memory leak when creating Python3 modules. (#2019) --- include/pybind11/pybind11.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index d95d61f7b..8e9c55d1a 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -794,11 +794,16 @@ public: explicit module(const char *name, const char *doc = nullptr) { if (!options::show_user_defined_docstrings()) doc = nullptr; #if PY_MAJOR_VERSION >= 3 - PyModuleDef *def = new PyModuleDef(); + PyModuleDef *def = PyMem_New(PyModuleDef, 1); std::memset(def, 0, sizeof(PyModuleDef)); def->m_name = name; def->m_doc = doc; def->m_size = -1; + def->m_free = [](void* module ) { + if (module != nullptr) { + Py_XDECREF(PyModule_GetDef((PyObject*) module)); + } + }; Py_INCREF(def); m_ptr = PyModule_Create(def); #else From fb910ae92b4a489e9b31f9ec545bde9d09d6a40e Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Wed, 11 Dec 2019 21:26:46 +0100 Subject: [PATCH 044/768] Revert "Fix a memory leak when creating Python3 modules. (#2019)" This reverts commit 819802da9926535714acf2bffe690b04f90cb12b. --- include/pybind11/pybind11.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 8e9c55d1a..d95d61f7b 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -794,16 +794,11 @@ public: explicit module(const char *name, const char *doc = nullptr) { if (!options::show_user_defined_docstrings()) doc = nullptr; #if PY_MAJOR_VERSION >= 3 - PyModuleDef *def = PyMem_New(PyModuleDef, 1); + PyModuleDef *def = new PyModuleDef(); std::memset(def, 0, sizeof(PyModuleDef)); def->m_name = name; def->m_doc = doc; def->m_size = -1; - def->m_free = [](void* module ) { - if (module != nullptr) { - Py_XDECREF(PyModule_GetDef((PyObject*) module)); - } - }; Py_INCREF(def); m_ptr = PyModule_Create(def); #else From 1376eb0e518ff2b7b412c84a907dd1cd3f7f2dcd Mon Sep 17 00:00:00 2001 From: Boris Staletic Date: Thu, 12 Dec 2019 15:55:54 +0100 Subject: [PATCH 045/768] Free tstate on python 3.7+ on finalize_interpreter (#2020) --- include/pybind11/detail/internals.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 87952daba..6224dfb22 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -25,6 +25,7 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass); # define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key)) # define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value)) # define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr) +# define PYBIND11_TLS_FREE(key) PyThread_tss_free(key) #else // Usually an int but a long on Cygwin64 with Python 3.x # define PYBIND11_TLS_KEY_INIT(var) decltype(PyThread_create_key()) var = 0 @@ -43,6 +44,7 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass); # define PYBIND11_TLS_REPLACE_VALUE(key, value) \ PyThread_set_key_value((key), (value)) # endif +# define PYBIND11_TLS_FREE(key) (void)key #endif // Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly @@ -108,6 +110,16 @@ struct internals { #if defined(WITH_THREAD) PYBIND11_TLS_KEY_INIT(tstate); PyInterpreterState *istate = nullptr; + ~internals() { + // This destructor is called *after* Py_Finalize() in finalize_interpreter(). + // That *SHOULD BE* fine. The following details what happens whe PyThread_tss_free is called. + // PYBIND11_TLS_FREE is PyThread_tss_free on python 3.7+. On older python, it does nothing. + // PyThread_tss_free calls PyThread_tss_delete and PyMem_RawFree. + // PyThread_tss_delete just calls TlsFree (on Windows) or pthread_key_delete (on *NIX). Neither + // of those have anything to do with CPython internals. + // PyMem_RawFree *requires* that the `tstate` be allocated with the CPython allocator. + PYBIND11_TLS_FREE(tstate); + } #endif }; @@ -138,7 +150,7 @@ struct type_info { }; /// Tracks the `internals` and `type_info` ABI version independent of the main library version -#define PYBIND11_INTERNALS_VERSION 3 +#define PYBIND11_INTERNALS_VERSION 4 /// On MSVC, debug and release builds are not ABI-compatible! #if defined(_MSC_VER) && defined(_DEBUG) From b4e5d582cb656a590b256bcf4a8ffa7c8ce9ba19 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Fri, 13 Dec 2019 11:11:33 +0100 Subject: [PATCH 046/768] undo #define copysign in pyconfig.h --- include/pybind11/detail/common.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index bb1affcea..e2330bbe6 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -113,6 +113,9 @@ #include #include +/* Python #defines overrides on all sorts of core functions, which + tends to weak havok in C++ codebases that expect these to work + like regular functions (potentially with several overloads) */ #if defined(isalnum) # undef isalnum # undef isalpha @@ -123,6 +126,10 @@ # undef toupper #endif +#if defined(copysign) +# undef copysign +#endif + #if defined(_MSC_VER) # if defined(PYBIND11_DEBUG_MARKER) # define _DEBUG From 37d04abdee11403e98bc5c09e386dd49d58a58bd Mon Sep 17 00:00:00 2001 From: JGamache-autodesk <56274617+JGamache-autodesk@users.noreply.github.com> Date: Thu, 19 Dec 2019 06:15:42 -0500 Subject: [PATCH 047/768] Fixes #1295: Handle debug interpreter (#2025) If a debug interpreter is detected, we allow linking with pythonXX_d.lib under windows. --- include/pybind11/detail/common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index e2330bbe6..de10f73b5 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -103,7 +103,7 @@ # endif # pragma warning(push) # pragma warning(disable: 4510 4610 4512 4005) -# if defined(_DEBUG) +# if defined(_DEBUG) && !defined(Py_DEBUG) # define PYBIND11_DEBUG_MARKER # undef _DEBUG # endif From 6e39b765b2333cd191001f22fe57ea218bd6ccf2 Mon Sep 17 00:00:00 2001 From: Vemund Handeland Date: Thu, 19 Dec 2019 12:16:24 +0100 Subject: [PATCH 048/768] Add C++20 char8_t/u8string support (#2026) * Fix test build in C++20 * Add C++20 char8_t/u8string support --- include/pybind11/cast.h | 16 +++++++++++--- tests/test_builtin_casters.cpp | 22 +++++++++++++++++-- tests/test_builtin_casters.py | 39 ++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 5 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index ad225312d..3af673511 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -32,6 +32,10 @@ #include #endif +#if defined(__cpp_lib_char8_t) && __cpp_lib_char8_t >= 201811L +# define PYBIND11_HAS_U8STRING +#endif + NAMESPACE_BEGIN(PYBIND11_NAMESPACE) NAMESPACE_BEGIN(detail) @@ -988,6 +992,9 @@ public: template using is_std_char_type = any_of< std::is_same, /* std::string */ +#if defined(PYBIND11_HAS_U8STRING) + std::is_same, /* std::u8string */ +#endif std::is_same, /* std::u16string */ std::is_same, /* std::u32string */ std::is_same /* std::wstring */ @@ -1191,6 +1198,9 @@ template struct string_caster { // Simplify life by being able to assume standard char sizes (the standard only guarantees // minimums, but Python requires exact sizes) static_assert(!std::is_same::value || sizeof(CharT) == 1, "Unsupported char size != 1"); +#if defined(PYBIND11_HAS_U8STRING) + static_assert(!std::is_same::value || sizeof(CharT) == 1, "Unsupported char8_t size != 1"); +#endif static_assert(!std::is_same::value || sizeof(CharT) == 2, "Unsupported char16_t size != 2"); static_assert(!std::is_same::value || sizeof(CharT) == 4, "Unsupported char32_t size != 4"); // wchar_t can be either 16 bits (Windows) or 32 (everywhere else) @@ -1209,7 +1219,7 @@ template struct string_caster { #if PY_MAJOR_VERSION >= 3 return load_bytes(load_src); #else - if (sizeof(CharT) == 1) { + if (std::is_same::value) { return load_bytes(load_src); } @@ -1269,7 +1279,7 @@ private: // without any encoding/decoding attempt). For other C++ char sizes this is a no-op. // which supports loading a unicode from a str, doesn't take this path. template - bool load_bytes(enable_if_t src) { + bool load_bytes(enable_if_t::value, handle> src) { if (PYBIND11_BYTES_CHECK(src.ptr())) { // We were passed a Python 3 raw bytes; accept it into a std::string or char* // without any encoding attempt. @@ -1284,7 +1294,7 @@ private: } template - bool load_bytes(enable_if_t) { return false; } + bool load_bytes(enable_if_t::value, handle>) { return false; } }; template diff --git a/tests/test_builtin_casters.cpp b/tests/test_builtin_casters.cpp index e026127f8..acb244691 100644 --- a/tests/test_builtin_casters.cpp +++ b/tests/test_builtin_casters.cpp @@ -30,7 +30,7 @@ TEST_SUBMODULE(builtin_casters, m) { else { wstr.push_back((wchar_t) mathbfA32); } // 𝐀, utf32 wstr.push_back(0x7a); // z - m.def("good_utf8_string", []() { return std::string(u8"Say utf8\u203d \U0001f382 \U0001d400"); }); // Say utf8‽ 🎂 𝐀 + m.def("good_utf8_string", []() { return std::string((const char*)u8"Say utf8\u203d \U0001f382 \U0001d400"); }); // Say utf8‽ 🎂 𝐀 m.def("good_utf16_string", [=]() { return std::u16string({ b16, ib16, cake16_1, cake16_2, mathbfA16_1, mathbfA16_2, z16 }); }); // b‽🎂𝐀z m.def("good_utf32_string", [=]() { return std::u32string({ a32, mathbfA32, cake32, ib32, z32 }); }); // a𝐀🎂‽z m.def("good_wchar_string", [=]() { return wstr; }); // a‽𝐀z @@ -60,6 +60,18 @@ TEST_SUBMODULE(builtin_casters, m) { m.def("strlen", [](char *s) { return strlen(s); }); m.def("string_length", [](std::string s) { return s.length(); }); +#ifdef PYBIND11_HAS_U8STRING + m.attr("has_u8string") = true; + m.def("good_utf8_u8string", []() { return std::u8string(u8"Say utf8\u203d \U0001f382 \U0001d400"); }); // Say utf8‽ 🎂 𝐀 + m.def("bad_utf8_u8string", []() { return std::u8string((const char8_t*)"abc\xd0" "def"); }); + + m.def("u8_char8_Z", []() -> char8_t { return u8'Z'; }); + + // test_single_char_arguments + m.def("ord_char8", [](char8_t c) -> int { return static_cast(c); }); + m.def("ord_char8_lv", [](char8_t &c) -> int { return static_cast(c); }); +#endif + // test_string_view #ifdef PYBIND11_HAS_STRING_VIEW m.attr("has_string_view") = true; @@ -69,9 +81,15 @@ TEST_SUBMODULE(builtin_casters, m) { m.def("string_view_chars", [](std::string_view s) { py::list l; for (auto c : s) l.append((std::uint8_t) c); return l; }); m.def("string_view16_chars", [](std::u16string_view s) { py::list l; for (auto c : s) l.append((int) c); return l; }); m.def("string_view32_chars", [](std::u32string_view s) { py::list l; for (auto c : s) l.append((int) c); return l; }); - m.def("string_view_return", []() { return std::string_view(u8"utf8 secret \U0001f382"); }); + m.def("string_view_return", []() { return std::string_view((const char*)u8"utf8 secret \U0001f382"); }); m.def("string_view16_return", []() { return std::u16string_view(u"utf16 secret \U0001f382"); }); m.def("string_view32_return", []() { return std::u32string_view(U"utf32 secret \U0001f382"); }); + +# ifdef PYBIND11_HAS_U8STRING + m.def("string_view8_print", [](std::u8string_view s) { py::print(s, s.size()); }); + m.def("string_view8_chars", [](std::u8string_view s) { py::list l; for (auto c : s) l.append((std::uint8_t) c); return l; }); + m.def("string_view8_return", []() { return std::u8string_view(u8"utf8 secret \U0001f382"); }); +# endif #endif // test_integer_casting diff --git a/tests/test_builtin_casters.py b/tests/test_builtin_casters.py index abbfcec49..91422588c 100644 --- a/tests/test_builtin_casters.py +++ b/tests/test_builtin_casters.py @@ -15,6 +15,8 @@ def test_unicode_conversion(): assert m.good_utf16_string() == u"b‽🎂𝐀z" assert m.good_utf32_string() == u"a𝐀🎂‽z" assert m.good_wchar_string() == u"a⸘𝐀z" + if hasattr(m, "has_u8string"): + assert m.good_utf8_u8string() == u"Say utf8‽ 🎂 𝐀" with pytest.raises(UnicodeDecodeError): m.bad_utf8_string() @@ -29,12 +31,17 @@ def test_unicode_conversion(): if hasattr(m, "bad_wchar_string"): with pytest.raises(UnicodeDecodeError): m.bad_wchar_string() + if hasattr(m, "has_u8string"): + with pytest.raises(UnicodeDecodeError): + m.bad_utf8_u8string() assert m.u8_Z() == 'Z' assert m.u8_eacute() == u'é' assert m.u16_ibang() == u'‽' assert m.u32_mathbfA() == u'𝐀' assert m.wchar_heart() == u'♥' + if hasattr(m, "has_u8string"): + assert m.u8_char8_Z() == 'Z' def test_single_char_arguments(): @@ -92,6 +99,17 @@ def test_single_char_arguments(): assert m.ord_wchar(u'aa') assert str(excinfo.value) == toolong_message + if hasattr(m, "has_u8string"): + assert m.ord_char8(u'a') == 0x61 # simple ASCII + assert m.ord_char8_lv(u'b') == 0x62 + assert m.ord_char8(u'é') == 0xE9 # requires 2 bytes in utf-8, but can be stuffed in a char + with pytest.raises(ValueError) as excinfo: + assert m.ord_char8(u'Ā') == 0x100 # requires 2 bytes, doesn't fit in a char + assert str(excinfo.value) == toobig_message(0x100) + with pytest.raises(ValueError) as excinfo: + assert m.ord_char8(u'ab') + assert str(excinfo.value) == toolong_message + def test_bytes_to_string(): """Tests the ability to pass bytes to C++ string-accepting functions. Note that this is @@ -116,10 +134,15 @@ def test_string_view(capture): assert m.string_view_chars("Hi 🎂") == [72, 105, 32, 0xf0, 0x9f, 0x8e, 0x82] assert m.string_view16_chars("Hi 🎂") == [72, 105, 32, 0xd83c, 0xdf82] assert m.string_view32_chars("Hi 🎂") == [72, 105, 32, 127874] + if hasattr(m, "has_u8string"): + assert m.string_view8_chars("Hi") == [72, 105] + assert m.string_view8_chars("Hi 🎂") == [72, 105, 32, 0xf0, 0x9f, 0x8e, 0x82] assert m.string_view_return() == "utf8 secret 🎂" assert m.string_view16_return() == "utf16 secret 🎂" assert m.string_view32_return() == "utf32 secret 🎂" + if hasattr(m, "has_u8string"): + assert m.string_view8_return() == "utf8 secret 🎂" with capture: m.string_view_print("Hi") @@ -132,6 +155,14 @@ def test_string_view(capture): utf16 🎂 8 utf32 🎂 7 """ + if hasattr(m, "has_u8string"): + with capture: + m.string_view8_print("Hi") + m.string_view8_print("utf8 🎂") + assert capture == """ + Hi 2 + utf8 🎂 9 + """ with capture: m.string_view_print("Hi, ascii") @@ -144,6 +175,14 @@ def test_string_view(capture): Hi, utf16 🎂 12 Hi, utf32 🎂 11 """ + if hasattr(m, "has_u8string"): + with capture: + m.string_view8_print("Hi, ascii") + m.string_view8_print("Hi, utf8 🎂") + assert capture == """ + Hi, ascii 9 + Hi, utf8 🎂 13 + """ def test_integer_casting(): From f9f3bd711f266c435fa7cd8198e5696e3fb37eef Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Mon, 30 Dec 2019 01:26:32 +0100 Subject: [PATCH 049/768] Use C++17 fold expressions when casting tuples and argument lists (#2043) This commit introduces the use of C++17-style fold expressions when casting tuples & the argument lists of functions. This change can improve performance of the resulting bindings: because fold expressions have short-circuiting semantics, pybind11 e.g. won't try to cast the second argument of a function if the first one failed. This is particularly effective when working with functions that have many overloads with long argument lists. --- include/pybind11/cast.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 3af673511..38eb8a88f 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1432,9 +1432,14 @@ protected: template bool load_impl(const sequence &seq, bool convert, index_sequence) { +#ifdef __cpp_fold_expressions + if ((... || !std::get(subcasters).load(seq[Is], convert))) + return false; +#else for (bool r : {std::get(subcasters).load(seq[Is], convert)...}) if (!r) return false; +#endif return true; } @@ -1961,9 +1966,14 @@ private: template bool load_impl_sequence(function_call &call, index_sequence) { +#ifdef __cpp_fold_expressions + if ((... || !std::get(argcasters).load(call.args[Is], call.args_convert[Is]))) + return false; +#else for (bool r : {std::get(argcasters).load(call.args[Is], call.args_convert[Is])...}) if (!r) return false; +#endif return true; } From 2fda9d5dd876de2fc0c530e4a375b1f8c52e6758 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Tue, 31 Dec 2019 01:26:40 +0100 Subject: [PATCH 050/768] Travis CI fix (MacOS, Py3) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 56682556d..d81cd8c7b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -219,7 +219,7 @@ before_install: PY_CMD=python$PYTHON if [ "$TRAVIS_OS_NAME" = "osx" ]; then if [ "$PY" = "3" ]; then - brew update && brew upgrade python + brew update && brew unlink python@2 && brew upgrade python else curl -fsSL https://bootstrap.pypa.io/get-pip.py | $PY_CMD - --user fi From 4c206e8c79bcbd3784fd05491b3c139e8fadaa4e Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Thu, 2 Jan 2020 22:17:20 +0100 Subject: [PATCH 051/768] bindings for import_error exception --- 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 de10f73b5..928e0a9aa 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -681,6 +681,7 @@ PYBIND11_RUNTIME_EXCEPTION(key_error, PyExc_KeyError) 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(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 bf2b031449c8c8156443655a80bdaf41433b2534 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Thu, 2 Jan 2020 22:18:01 +0100 Subject: [PATCH 052/768] Handle cases where binding code immediately throws py::error_already_set When binding code immediately throws an exception of type py::error_already_set (e.g. via py::module::import that fails), the catch block sets an import error as expected. Unfortunately, following this, the deconstructor of py::error_already_set decides to call py::detail::get_internals() and set up various internal data structures of pybind11, which fails given that the error flag is active. The call stack of this looks as follows: Py_init_mymodule() -> __cxa_decrement_exception_refcount -> error_already_set::~error_already_set() -> gil_scoped_acquire::gil_scoped_acquire() -> detail::get_internals() -> ... -> pybind11::detail::simple_collector() -> uh oh.. The solution is simple: we call detail::get_internals() once before running any binding code to make sure that the internal data structures are ready. --- include/pybind11/detail/common.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 928e0a9aa..362421dfe 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -218,6 +218,8 @@ extern "C" { #define PYBIND11_STRINGIFY(x) #x #define PYBIND11_TOSTRING(x) PYBIND11_STRINGIFY(x) #define PYBIND11_CONCAT(first, second) first##second +#define PYBIND11_ENSURE_INTERNALS_READY \ + pybind11::detail::get_internals(); #define PYBIND11_CHECK_PYTHON_VERSION \ { \ @@ -264,6 +266,7 @@ extern "C" { static PyObject *pybind11_init(); \ PYBIND11_PLUGIN_IMPL(name) { \ PYBIND11_CHECK_PYTHON_VERSION \ + PYBIND11_ENSURE_INTERNALS_READY \ try { \ return pybind11_init(); \ } PYBIND11_CATCH_INIT_EXCEPTIONS \ @@ -291,6 +294,7 @@ extern "C" { static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &); \ PYBIND11_PLUGIN_IMPL(name) { \ PYBIND11_CHECK_PYTHON_VERSION \ + PYBIND11_ENSURE_INTERNALS_READY \ auto m = pybind11::module(PYBIND11_TOSTRING(name)); \ try { \ PYBIND11_CONCAT(pybind11_init_, name)(m); \ From 370a2ae2b364cc91792ecf2a343b14fca5d488ad Mon Sep 17 00:00:00 2001 From: Robert Haschke Date: Sun, 5 Jan 2020 15:49:24 +0100 Subject: [PATCH 053/768] Declare call_impl() as && (#2057) --- 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 38eb8a88f..a0b4d1ba9 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1978,7 +1978,7 @@ private: } template - Return call_impl(Func &&f, index_sequence, Guard &&) { + Return call_impl(Func &&f, index_sequence, Guard &&) && { return std::forward(f)(cast_op(std::move(std::get(argcasters)))...); } From 07e225932235ccb0db5271b0874d00f086f28423 Mon Sep 17 00:00:00 2001 From: Baljak Date: Sun, 5 Jan 2020 15:49:59 +0100 Subject: [PATCH 054/768] Fix compilation with MinGW only (#2053) --- tools/FindPythonLibsNew.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/FindPythonLibsNew.cmake b/tools/FindPythonLibsNew.cmake index 52c92f1e4..c9b95a9a1 100644 --- a/tools/FindPythonLibsNew.cmake +++ b/tools/FindPythonLibsNew.cmake @@ -144,7 +144,7 @@ string(REGEX REPLACE "\\\\" "/" PYTHON_PREFIX "${PYTHON_PREFIX}") string(REGEX REPLACE "\\\\" "/" PYTHON_INCLUDE_DIR "${PYTHON_INCLUDE_DIR}") string(REGEX REPLACE "\\\\" "/" PYTHON_SITE_PACKAGES "${PYTHON_SITE_PACKAGES}") -if(CMAKE_HOST_WIN32 AND NOT (MSYS OR MINGW)) +if(CMAKE_HOST_WIN32 AND NOT DEFINED ENV{MSYSTEM}) set(PYTHON_LIBRARY "${PYTHON_PREFIX}/libs/Python${PYTHON_LIBRARY_SUFFIX}.lib") From e97c735fc44bd39b390a321a276f41b3095ea2fe Mon Sep 17 00:00:00 2001 From: fwjavox Date: Fri, 17 Jan 2020 01:16:56 +0100 Subject: [PATCH 055/768] stl_bind: add binding for std::vector::clear (#2074) --- include/pybind11/stl_bind.h | 7 +++++++ tests/test_stl_binders.py | 3 +++ 2 files changed, 10 insertions(+) diff --git a/include/pybind11/stl_bind.h b/include/pybind11/stl_bind.h index 62bd90819..da233eca9 100644 --- a/include/pybind11/stl_bind.h +++ b/include/pybind11/stl_bind.h @@ -136,6 +136,13 @@ void vector_modifiers(enable_if_t Date: Wed, 22 Jan 2020 11:49:56 +0100 Subject: [PATCH 056/768] Fix the use of MSVC in an MSYS environment (#2087) --- tools/FindPythonLibsNew.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/FindPythonLibsNew.cmake b/tools/FindPythonLibsNew.cmake index c9b95a9a1..9ea6036e3 100644 --- a/tools/FindPythonLibsNew.cmake +++ b/tools/FindPythonLibsNew.cmake @@ -144,7 +144,7 @@ string(REGEX REPLACE "\\\\" "/" PYTHON_PREFIX "${PYTHON_PREFIX}") string(REGEX REPLACE "\\\\" "/" PYTHON_INCLUDE_DIR "${PYTHON_INCLUDE_DIR}") string(REGEX REPLACE "\\\\" "/" PYTHON_SITE_PACKAGES "${PYTHON_SITE_PACKAGES}") -if(CMAKE_HOST_WIN32 AND NOT DEFINED ENV{MSYSTEM}) +if(CMAKE_HOST_WIN32 AND NOT (MINGW AND DEFINED ENV{MSYSTEM})) set(PYTHON_LIBRARY "${PYTHON_PREFIX}/libs/Python${PYTHON_LIBRARY_SUFFIX}.lib") From bb9c91cce826122a3d7361d8fb9217831a07c4c6 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Wed, 4 Mar 2020 16:17:20 +0100 Subject: [PATCH 057/768] pybind11Tools.cmake: search for Python 3.9 --- tools/pybind11Tools.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pybind11Tools.cmake b/tools/pybind11Tools.cmake index d0a2bfc8b..508e47429 100644 --- a/tools/pybind11Tools.cmake +++ b/tools/pybind11Tools.cmake @@ -12,7 +12,7 @@ if(NOT PYBIND11_PYTHON_VERSION) set(PYBIND11_PYTHON_VERSION "" CACHE STRING "Python version to use for compiling modules") endif() -set(Python_ADDITIONAL_VERSIONS 3.8 3.7 3.6 3.5 3.4) +set(Python_ADDITIONAL_VERSIONS 3.9 3.8 3.7 3.6 3.5 3.4) find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} REQUIRED) include(CheckCXXCompilerFlag) From 3b1dbebabc801c9cf6f0953a4c20b904d444f879 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Tue, 31 Mar 2020 12:55:48 +0200 Subject: [PATCH 058/768] v2.5.0 release --- docs/changelog.rst | 45 ++++++++++++++++++++++++++++++++ docs/conf.py | 4 +-- include/pybind11/detail/common.h | 4 +-- pybind11/_version.py | 2 +- 4 files changed, 50 insertions(+), 5 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index d65c2d800..2def2b071 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -6,6 +6,51 @@ Changelog Starting with version 1.8.0, pybind11 releases use a `semantic versioning `_ policy. +v2.5.0 (Mar 31, 2020) +----------------------------------------------------- + +* Use C++17 fold expressions in type casters, if available. This can + improve performance during overload resolution when functions have + multiple arguments. + `#2043 `_. + +* Changed include directory resolution in ``pybind11/__init__.py`` + and installation in ``setup.py``. This fixes a number of open issues + where pybind11 headers could not be found in certain environments. + `#1995 `_. + +* C++20 ``char8_t`` and ``u8string`` support. `#2026 + `_. + +* CMake: search for Python 3.9. `bb9c91 + `_. + +* Fixes for MSYS-based build environments. + `#2087 `_, + `#2053 `_. + +* STL bindings for ``std::vector<...>::clear``. `#2074 + `_. + +* Read-only flag for ``py::buffer``. `#1466 + `_. + +* Exception handling during module initialization. + `bf2b031 `_. + +* Support linking against a CPython debug build. + `#2025 `_. + +* Fixed issues involving the availability and use of aligned ``new`` and + ``delete``. `#1988 `_, + `759221 `_. + +* Fixed a resource leak upon interpreter shutdown. + `#2020 `_. + +* Fixed error handling in the boolean caster. + `#1976 `_. + v2.4.3 (Oct 15, 2019) ----------------------------------------------------- diff --git a/docs/conf.py b/docs/conf.py index a1e4e0058..fa6332de5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -61,9 +61,9 @@ author = 'Wenzel Jakob' # built documents. # # The short X.Y version. -version = '2.4' +version = '2.5' # The full version, including alpha/beta/rc tags. -release = '2.4.dev4' +release = '2.5.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 362421dfe..e53f502d6 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -93,8 +93,8 @@ #endif #define PYBIND11_VERSION_MAJOR 2 -#define PYBIND11_VERSION_MINOR 4 -#define PYBIND11_VERSION_PATCH dev4 +#define PYBIND11_VERSION_MINOR 5 +#define PYBIND11_VERSION_PATCH 0 /// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode #if defined(_MSC_VER) diff --git a/pybind11/_version.py b/pybind11/_version.py index 5bf3483d2..8d5aa5c76 100644 --- a/pybind11/_version.py +++ b/pybind11/_version.py @@ -1,2 +1,2 @@ -version_info = (2, 4, 'dev4') +version_info = (2, 5, 0) __version__ = '.'.join(map(str, version_info)) From 023487164915c5b62e16a9b4e0b37cb01cd5500a Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Tue, 31 Mar 2020 13:09:41 +0200 Subject: [PATCH 059/768] begin working on next version --- docs/conf.py | 2 +- include/pybind11/detail/common.h | 2 +- pybind11/_version.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index fa6332de5..585987ec6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -63,7 +63,7 @@ author = 'Wenzel Jakob' # The short X.Y version. version = '2.5' # The full version, including alpha/beta/rc tags. -release = '2.5.0' +release = '2.5.dev1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index e53f502d6..dd6267936 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -94,7 +94,7 @@ #define PYBIND11_VERSION_MAJOR 2 #define PYBIND11_VERSION_MINOR 5 -#define PYBIND11_VERSION_PATCH 0 +#define PYBIND11_VERSION_PATCH dev1 /// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode #if defined(_MSC_VER) diff --git a/pybind11/_version.py b/pybind11/_version.py index 8d5aa5c76..d0eb659bd 100644 --- a/pybind11/_version.py +++ b/pybind11/_version.py @@ -1,2 +1,2 @@ -version_info = (2, 5, 0) +version_info = (2, 5, 'dev1') __version__ = '.'.join(map(str, version_info)) From 4697149d19738a674ab59b08492becfcf69a87f8 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 4 Dec 2019 15:03:22 -0800 Subject: [PATCH 060/768] Allows users to specialize polymorphic_type_hook with std::enable_if. Currently user specializations of the form template struct polymorphic_type_hook> { ... }; will fail if itype is also polymorphic, because the existing specialization will also be enabled, which leads to 2 equally viable candidates. With this change, user provided specializations have higher priority than the built in specialization for polymorphic types. --- include/pybind11/cast.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index a0b4d1ba9..fcfd0a8e3 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -835,19 +835,25 @@ NAMESPACE_END(detail) // You may specialize polymorphic_type_hook yourself for types that want to appear // polymorphic to Python but do not use C++ RTTI. (This is a not uncommon pattern // in performance-sensitive applications, used most notably in LLVM.) +// +// polymorphic_type_hook_base allows users to specialize polymorphic_type_hook with +// std::enable_if. User provided specializations will always have higher priority than +// the default implementation and specialization provided in polymorphic_type_hook_base. template -struct polymorphic_type_hook +struct polymorphic_type_hook_base { static const void *get(const itype *src, const std::type_info*&) { return src; } }; template -struct polymorphic_type_hook::value>> +struct polymorphic_type_hook_base::value>> { static const void *get(const itype *src, const std::type_info*& type) { type = src ? &typeid(*src) : nullptr; return dynamic_cast(src); } }; +template +struct polymorphic_type_hook : public polymorphic_type_hook_base {}; NAMESPACE_BEGIN(detail) From f6e543b15ec0aaf39c494936440f91a16f161c9a Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 16 Jan 2020 00:20:44 +0000 Subject: [PATCH 061/768] Adding a default virtual destructor to Animal type in test_tagbased_polymorphic.cpp. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this change, and cast.h as-is in master, test_tagbased_polymorphic.cpp fails to compile with the error message below. With the cast.h change in pull/2016, building and testing succeeds. cd pybind11/build/tests && /usr/bin/c++ -DPYBIND11_TEST_BOOST -DPYBIND11_TEST_EIGEN -Dpybind11_tests_EXPORTS -Ipybind11/include -I/usr/include/python3.7m -isystem /usr/include/eigen3 -Os -DNDEBUG -fPIC -fvisibility=hidden -std=c++2a -flto -fno-fat-lto-objects -Wall -Wextra -Wconversion -Wcast-qual -Wdeprecated -o CMakeFiles/pybind11_tests.dir/test_tagbased_polymorphic.cpp.o -c pybind11/tests/test_tagbased_polymorphic.cpp In file included from pybind11/include/pybind11/attr.h:13, from pybind11/include/pybind11/pybind11.h:44, from pybind11/tests/pybind11_tests.h:2, from pybind11/tests/test_tagbased_polymorphic.cpp:10: pybind11/include/pybind11/cast.h: In instantiation of ‘static std::pair pybind11::detail::type_caster_base::src_and_type(const itype*) [with type = Animal; pybind11::detail::type_caster_base::itype = Animal]’: pybind11/include/pybind11/cast.h:906:31: required from ‘static pybind11::handle pybind11::detail::type_caster_base::cast_holder(const itype*, const void*) [with type = Animal; pybind11::detail::type_caster_base::itype = Animal]’ pybind11/include/pybind11/cast.h:1566:51: required from ‘static pybind11::handle pybind11::detail::move_only_holder_caster::cast(holder_type&&, pybind11::return_value_policy, pybind11::handle) [with type = Animal; holder_type = std::unique_ptr]’ pybind11/include/pybind11/stl.h:175:69: required from ‘static pybind11::handle pybind11::detail::list_caster::cast(T&&, pybind11::return_value_policy, pybind11::handle) [with T = std::vector >; Type = std::vector >; Value = std::unique_ptr]’ pybind11/include/pybind11/pybind11.h:159:43: required from ‘void pybind11::cpp_function::initialize(Func&&, Return (*)(Args ...), const Extra& ...) [with Func = std::vector > (*&)(); Return = std::vector >; Args = {}; Extra = {pybind11::name, pybind11::scope, pybind11::sibling}]’ pybind11/include/pybind11/pybind11.h:64:9: required from ‘pybind11::cpp_function::cpp_function(Return (*)(Args ...), const Extra& ...) [with Return = std::vector >; Args = {}; Extra = {pybind11::name, pybind11::scope, pybind11::sibling}]’ pybind11/include/pybind11/pybind11.h:819:22: required from ‘pybind11::module& pybind11::module::def(const char*, Func&&, const Extra& ...) [with Func = std::vector > (*)(); Extra = {}]’ pybind11/tests/test_tagbased_polymorphic.cpp:141:36: required from here pybind11/include/pybind11/cast.h:880:61: error: ambiguous template instantiation for ‘struct pybind11::polymorphic_type_hook’ const void *vsrc = polymorphic_type_hook::get(src, instance_type); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~ pybind11/include/pybind11/cast.h:844:8: note: candidates are: ‘template struct pybind11::polymorphic_type_hook::value, void>::type> [with itype = Animal]’ struct polymorphic_type_hook::value>> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ pybind11/tests/test_tagbased_polymorphic.cpp:115:12: note: ‘template struct pybind11::polymorphic_type_hook::value, void>::type> [with itype = Animal]’ struct polymorphic_type_hook::value>> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from pybind11/include/pybind11/attr.h:13, from pybind11/include/pybind11/pybind11.h:44, from pybind11/tests/pybind11_tests.h:2, from pybind11/tests/test_tagbased_polymorphic.cpp:10: pybind11/include/pybind11/cast.h:880:61: error: incomplete type ‘pybind11::polymorphic_type_hook’ used in nested name specifier const void *vsrc = polymorphic_type_hook::get(src, instance_type); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~ --- tests/test_tagbased_polymorphic.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/test_tagbased_polymorphic.cpp b/tests/test_tagbased_polymorphic.cpp index 272e460c9..dcc005126 100644 --- a/tests/test_tagbased_polymorphic.cpp +++ b/tests/test_tagbased_polymorphic.cpp @@ -12,6 +12,12 @@ struct Animal { + // Make this type also a "standard" polymorphic type, to confirm that + // specializing polymorphic_type_hook using enable_if_t still works + // (https://github.com/pybind/pybind11/pull/2016/). + virtual ~Animal() = default; + + // Enum for tag-based polymorphism. enum class Kind { Unknown = 0, Dog = 100, Labrador, Chihuahua, LastDog = 199, From d730fbc0d54a3c3a7655cabe0d4f091f122b4998 Mon Sep 17 00:00:00 2001 From: Chuck Atkins Date: Tue, 12 Jun 2018 13:18:48 -0400 Subject: [PATCH 062/768] Utilize CMake's language standards abstraction when possible --- tools/pybind11Tools.cmake | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/tools/pybind11Tools.cmake b/tools/pybind11Tools.cmake index 508e47429..8d85dd4eb 100644 --- a/tools/pybind11Tools.cmake +++ b/tools/pybind11Tools.cmake @@ -18,24 +18,40 @@ find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} REQUIRED) include(CheckCXXCompilerFlag) include(CMakeParseArguments) -if(NOT PYBIND11_CPP_STANDARD AND NOT CMAKE_CXX_STANDARD) - if(NOT MSVC) - check_cxx_compiler_flag("-std=c++14" HAS_CPP14_FLAG) +# Use the language standards abstraction if CMake supports it with the current compiler +if(NOT CMAKE_VERSION VERSION_LESS 3.1) + if(NOT CMAKE_CXX_STANDARD) + if(CMAKE_CXX14_STANDARD_COMPILE_OPTION) + set(CMAKE_CXX_STANDARD 14) + elseif(CMAKE_CXX11_STANDARD_COMPILE_OPTION) + set(CMAKE_CXX_STANDARD 11) + endif() + endif() + if(CMAKE_CXX_STANDARD) + set(CMAKE_CXX_EXTENSIONS OFF) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + endif() +endif() - if (HAS_CPP14_FLAG) +# Fall back to heuristics +if(NOT PYBIND11_CPP_STANDARD AND NOT CMAKE_CXX_STANDARD) + if(MSVC) + set(PYBIND11_CPP_STANDARD /std:c++14) + else() + check_cxx_compiler_flag("-std=c++14" HAS_CPP14_FLAG) + if(HAS_CPP14_FLAG) set(PYBIND11_CPP_STANDARD -std=c++14) else() check_cxx_compiler_flag("-std=c++11" HAS_CPP11_FLAG) - if (HAS_CPP11_FLAG) + if(HAS_CPP11_FLAG) set(PYBIND11_CPP_STANDARD -std=c++11) - else() - message(FATAL_ERROR "Unsupported compiler -- pybind11 requires C++11 support!") endif() endif() - elseif(MSVC) - set(PYBIND11_CPP_STANDARD /std:c++14) endif() + if(NOT PYBIND11_CPP_STANDARD) + message(FATAL_ERROR "Unsupported compiler -- pybind11 requires C++11 support!") + endif() set(PYBIND11_CPP_STANDARD ${PYBIND11_CPP_STANDARD} CACHE STRING "C++ standard flag, e.g. -std=c++11, -std=c++14, /std:c++14. Defaults to C++14 mode." FORCE) endif() From 6ebfc4b2b09036eec6a2caeb55d2801ae2df361f Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Sat, 25 Apr 2020 18:10:53 -0700 Subject: [PATCH 063/768] Document CMAKE_CXX_STANDARD This variable is a CMake community standard to set the C++ standard of a build. Document it in favor of the previous variable, which stays as a legacy flag for existing projects. https://cmake.org/cmake/help/v3.17/variable/CMAKE_CXX_STANDARD.html --- docs/compiling.rst | 12 ++++-------- tools/pybind11Config.cmake.in | 4 ++-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/docs/compiling.rst b/docs/compiling.rst index c50c7d8af..ea8d1ec16 100644 --- a/docs/compiling.rst +++ b/docs/compiling.rst @@ -105,18 +105,14 @@ on the target compiler, falling back to C++11 if C++14 support is not available. Note, however, that this default is subject to change: future pybind11 releases are expected to migrate to newer C++ standards as they become available. To override this, the standard flag can be given explicitly in -``PYBIND11_CPP_STANDARD``: +`CMAKE_CXX_STANDARD `_: .. code-block:: cmake # Use just one of these: - # GCC/clang: - set(PYBIND11_CPP_STANDARD -std=c++11) - set(PYBIND11_CPP_STANDARD -std=c++14) - set(PYBIND11_CPP_STANDARD -std=c++1z) # Experimental C++17 support - # MSVC: - set(PYBIND11_CPP_STANDARD /std:c++14) - set(PYBIND11_CPP_STANDARD /std:c++latest) # Enables some MSVC C++17 features + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD 14) + set(CMAKE_CXX_STANDARD 17) # Experimental C++17 support add_subdirectory(pybind11) # or find_package(pybind11) diff --git a/tools/pybind11Config.cmake.in b/tools/pybind11Config.cmake.in index 8a7272ff9..58426887a 100644 --- a/tools/pybind11Config.cmake.in +++ b/tools/pybind11Config.cmake.in @@ -28,8 +28,8 @@ # # Python headers, libraries (as needed by platform), and the C++ standard # are attached to the target. Set PythonLibsNew variables to influence -# python detection and PYBIND11_CPP_STANDARD (-std=c++11 or -std=c++14) to -# influence standard setting. :: +# python detection and CMAKE_CXX_STANDARD (11 or 14) to influence standard +# setting. :: # # find_package(pybind11 CONFIG REQUIRED) # message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}") From 5088364b967d3cf57e99d7d352b8a52230788b0c Mon Sep 17 00:00:00 2001 From: David Stone Date: Thu, 23 Apr 2020 12:47:24 -0600 Subject: [PATCH 064/768] Declare `operator==` and `operator!=` member functions const. --- include/pybind11/cast.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index fcfd0a8e3..0edc33686 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -288,8 +288,8 @@ public: // Past-the-end iterator: iterator(size_t end) : curr(end) {} public: - bool operator==(const iterator &other) { return curr.index == other.curr.index; } - bool operator!=(const iterator &other) { return curr.index != other.curr.index; } + bool operator==(const iterator &other) const { return curr.index == other.curr.index; } + bool operator!=(const iterator &other) const { return curr.index != other.curr.index; } iterator &operator++() { if (!inst->simple_layout) curr.vh += 1 + (*types)[curr.index]->holder_size_in_ptrs; From 9ed8b44033e64f2990bf123b5057e92b8142edae Mon Sep 17 00:00:00 2001 From: Orell Garten <10799869+orgarten@users.noreply.github.com> Date: Tue, 21 Apr 2020 15:02:55 +0200 Subject: [PATCH 065/768] Change __init__(self) to __new__(cls) __init__(self) cannot return values. According to https://stackoverflow.com/questions/2491819/how-to-return-a-value-from-init-in-python __new__(cls) should be used, which works. --- docs/advanced/cast/custom.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/advanced/cast/custom.rst b/docs/advanced/cast/custom.rst index e4f99ac5b..f80359431 100644 --- a/docs/advanced/cast/custom.rst +++ b/docs/advanced/cast/custom.rst @@ -23,7 +23,7 @@ The following Python snippet demonstrates the intended usage from the Python sid .. code-block:: python class A: - def __int__(self): + def __new__(cls): return 123 from example import print From 00c462d1490d95cc9fd8ee5c22376909651319bc Mon Sep 17 00:00:00 2001 From: MRocholl Date: Wed, 15 Apr 2020 15:00:03 +0200 Subject: [PATCH 066/768] find library path to libclang.so via glob command in /usr/lib/llvm-* and set it --- tools/mkdoc.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/mkdoc.py b/tools/mkdoc.py index 44164af3d..2b429ae1c 100755 --- a/tools/mkdoc.py +++ b/tools/mkdoc.py @@ -254,6 +254,13 @@ def read_args(args): parameters.append('-isysroot') parameters.append(sysroot_dir) elif platform.system() == 'Linux': + # cython.util.find_library does not find `libclang` for all clang + # versions and distributions. LLVM switched to a monolithical setup + # that includes everything under /usr/lib/llvm{version_number}/ + # We therefore glob for the library and select the highest version + library_path = sorted(glob("/usr/lib/llvm-*/lib/"), reversed=True)[0] + cindex.Config.set_library_path(library_path) + # clang doesn't find its own base includes by default on Linux, # but different distros install them in different paths. # Try to autodetect, preferring the highest numbered version. From 9358e30d2afd580acacf969e58cfc7230cd563a7 Mon Sep 17 00:00:00 2001 From: MRocholl Date: Wed, 15 Apr 2020 15:35:38 +0200 Subject: [PATCH 067/768] change set_path to set_file --- tools/mkdoc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/mkdoc.py b/tools/mkdoc.py index 2b429ae1c..c9ee72685 100755 --- a/tools/mkdoc.py +++ b/tools/mkdoc.py @@ -258,8 +258,8 @@ def read_args(args): # versions and distributions. LLVM switched to a monolithical setup # that includes everything under /usr/lib/llvm{version_number}/ # We therefore glob for the library and select the highest version - library_path = sorted(glob("/usr/lib/llvm-*/lib/"), reversed=True)[0] - cindex.Config.set_library_path(library_path) + library_file = sorted(glob("/usr/lib/llvm-*/lib/libclang.so"), reversed=True)[0] + cindex.Config.set_library_file(library_file) # clang doesn't find its own base includes by default on Linux, # but different distros install them in different paths. From b14aeb7cfae1a412f17ab3cb87350d5cd2ad788f Mon Sep 17 00:00:00 2001 From: MRocholl Date: Wed, 15 Apr 2020 15:37:41 +0200 Subject: [PATCH 068/768] fix typo in sorted function call argument reverse --- tools/mkdoc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/mkdoc.py b/tools/mkdoc.py index c9ee72685..c85e09d4d 100755 --- a/tools/mkdoc.py +++ b/tools/mkdoc.py @@ -258,7 +258,7 @@ def read_args(args): # versions and distributions. LLVM switched to a monolithical setup # that includes everything under /usr/lib/llvm{version_number}/ # We therefore glob for the library and select the highest version - library_file = sorted(glob("/usr/lib/llvm-*/lib/libclang.so"), reversed=True)[0] + library_file = sorted(glob("/usr/lib/llvm-*/lib/libclang.so"), reverse=True)[0] cindex.Config.set_library_file(library_file) # clang doesn't find its own base includes by default on Linux, From 0dfffcf257f01ddc72488a0408d227591e5f7e67 Mon Sep 17 00:00:00 2001 From: Dustin Spicuzza Date: Sun, 5 Apr 2020 02:34:00 -0400 Subject: [PATCH 069/768] Add is_final to disallow inheritance from Python - Not currently supported on PyPy --- docs/advanced/classes.rst | 26 ++++++++++++++++++++++++++ include/pybind11/attr.h | 13 ++++++++++++- include/pybind11/detail/class.h | 4 +++- tests/test_class.cpp | 8 ++++++++ tests/test_class.py | 18 ++++++++++++++++++ 5 files changed, 67 insertions(+), 2 deletions(-) diff --git a/docs/advanced/classes.rst b/docs/advanced/classes.rst index ae5907dee..20760b704 100644 --- a/docs/advanced/classes.rst +++ b/docs/advanced/classes.rst @@ -1042,6 +1042,32 @@ described trampoline: ``.def("foo", static_cast(&Publicist::foo));`` where ``int (A::*)() const`` is the type of ``A::foo``. +Binding final classes +===================== + +Some classes may not be appropriate to inherit from. In C++11, classes can +use the ``final`` specifier to ensure that a class cannot be inherited from. +The ``py::is_final`` attribute can be used to ensure that Python classes +cannot inherit from a specified type. The underlying C++ type does not need +to be declared final. + +.. code-block:: cpp + + class IsFinal final {}; + + py::class_(m, "IsFinal", py::is_final()); + +When you try to inherit from such a class in Python, you will now get this +error: + +.. code-block:: pycon + + >>> class PyFinalChild(IsFinal): + ... pass + TypeError: type 'IsFinal' is not an acceptable base type + +.. note:: This attribute is currently ignored on PyPy + Custom automatic downcasters ============================ diff --git a/include/pybind11/attr.h b/include/pybind11/attr.h index 6962d6fc5..744284a83 100644 --- a/include/pybind11/attr.h +++ b/include/pybind11/attr.h @@ -23,6 +23,9 @@ struct is_method { handle class_; is_method(const handle &c) : class_(c) { } }; /// Annotation for operators struct is_operator { }; +/// Annotation for classes that cannot be subclassed +struct is_final { }; + /// Annotation for parent scope struct scope { handle value; scope(const handle &s) : value(s) { } }; @@ -201,7 +204,7 @@ struct function_record { struct type_record { PYBIND11_NOINLINE type_record() : multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false), - default_holder(true), module_local(false) { } + default_holder(true), module_local(false), is_final(false) { } /// Handle to the parent scope handle scope; @@ -254,6 +257,9 @@ struct type_record { /// Is the class definition local to the module shared object? bool module_local : 1; + /// Is the class inheritable from python classes? + bool is_final : 1; + PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *)) { auto base_info = detail::get_type_info(base, false); if (!base_info) { @@ -416,6 +422,11 @@ struct process_attribute : process_attribute_default static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; } }; +template <> +struct process_attribute : process_attribute_default { + static void init(const is_final &, type_record *r) { r->is_final = true; } +}; + template <> struct process_attribute : process_attribute_default { static void init(const buffer_protocol &, type_record *r) { r->buffer_protocol = true; } diff --git a/include/pybind11/detail/class.h b/include/pybind11/detail/class.h index edfa7de68..a05edeb4c 100644 --- a/include/pybind11/detail/class.h +++ b/include/pybind11/detail/class.h @@ -604,10 +604,12 @@ inline PyObject* make_new_python_type(const type_record &rec) { #endif /* Flags */ - type->tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; + type->tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE; #if PY_MAJOR_VERSION < 3 type->tp_flags |= Py_TPFLAGS_CHECKTYPES; #endif + if (!rec.is_final) + type->tp_flags |= Py_TPFLAGS_BASETYPE; if (rec.dynamic_attr) enable_dynamic_attributes(heap_type); diff --git a/tests/test_class.cpp b/tests/test_class.cpp index 499d0cc51..128bc39e9 100644 --- a/tests/test_class.cpp +++ b/tests/test_class.cpp @@ -367,6 +367,14 @@ TEST_SUBMODULE(class_, m) { .def(py::init<>()) .def("ptr", &Aligned::ptr); #endif + + // test_final + struct IsFinal final {}; + py::class_(m, "IsFinal", py::is_final()); + + // test_non_final_final + struct IsNonFinalFinal {}; + py::class_(m, "IsNonFinalFinal", py::is_final()); } template class BreaksBase { public: virtual ~BreaksBase() = default; }; diff --git a/tests/test_class.py b/tests/test_class.py index ed63ca853..e58fef698 100644 --- a/tests/test_class.py +++ b/tests/test_class.py @@ -279,3 +279,21 @@ def test_aligned(): if hasattr(m, "Aligned"): p = m.Aligned().ptr() assert p % 1024 == 0 + + +# https://bitbucket.org/pypy/pypy/issues/2742 +@pytest.unsupported_on_pypy +def test_final(): + with pytest.raises(TypeError) as exc_info: + class PyFinalChild(m.IsFinal): + pass + assert str(exc_info.value).endswith("is not an acceptable base type") + + +# https://bitbucket.org/pypy/pypy/issues/2742 +@pytest.unsupported_on_pypy +def test_non_final_final(): + with pytest.raises(TypeError) as exc_info: + class PyNonFinalFinalChild(m.IsNonFinalFinal): + pass + assert str(exc_info.value).endswith("is not an acceptable base type") From 03f9e4a8ec10eaab2181da7ec7d629f0dce74c30 Mon Sep 17 00:00:00 2001 From: peter Date: Sun, 22 Mar 2020 12:59:37 +0800 Subject: [PATCH 070/768] Fix compilation with clang-cl --- include/pybind11/numpy.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index ba41a223d..01daf3ac1 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -1218,7 +1218,7 @@ private: #define PYBIND11_MAP_NEXT0(test, next, ...) next PYBIND11_MAP_OUT #define PYBIND11_MAP_NEXT1(test, next) PYBIND11_MAP_NEXT0 (test, next, 0) #define PYBIND11_MAP_NEXT(test, next) PYBIND11_MAP_NEXT1 (PYBIND11_MAP_GET_END test, next) -#ifdef _MSC_VER // MSVC is not as eager to expand macros, hence this workaround +#if defined(_MSC_VER) && !defined(__clang__) // MSVC is not as eager to expand macros, hence this workaround #define PYBIND11_MAP_LIST_NEXT1(test, next) \ PYBIND11_EVAL0 (PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0)) #else @@ -1240,7 +1240,7 @@ private: (::std::vector<::pybind11::detail::field_descriptor> \ {PYBIND11_MAP_LIST (PYBIND11_FIELD_DESCRIPTOR, Type, __VA_ARGS__)}) -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) #define PYBIND11_MAP2_LIST_NEXT1(test, next) \ PYBIND11_EVAL0 (PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0)) #else From be0d804523c01809292f93f0bbf6adbfcf5cd0fa Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Sat, 23 Dec 2017 18:56:07 -0400 Subject: [PATCH 071/768] Support keyword-only arguments This adds support for a `py::args_kw_only()` annotation that can be specified between `py::arg` annotations to indicate that any following arguments are keyword-only. This allows you to write: m.def("f", [](int a, int b) { /* ... */ }, py::arg("a"), py::args_kw_only(), py::arg("b")); and have it work like Python 3's: def f(a, *, b): # ... with respect to how `a` and `b` arguments are accepted (that is, `a` can be positional or by keyword; `b` can only be specified by keyword). --- docs/advanced/functions.rst | 28 ++++++++++++++++++++++ include/pybind11/attr.h | 30 ++++++++++++++++++++--- include/pybind11/cast.h | 5 ++++ include/pybind11/pybind11.h | 25 +++++++++++++------- tests/test_kwargs_and_defaults.cpp | 24 +++++++++++++++++++ tests/test_kwargs_and_defaults.py | 38 ++++++++++++++++++++++++++++++ 6 files changed, 139 insertions(+), 11 deletions(-) diff --git a/docs/advanced/functions.rst b/docs/advanced/functions.rst index 3e1a3ff0e..c7790533b 100644 --- a/docs/advanced/functions.rst +++ b/docs/advanced/functions.rst @@ -362,6 +362,34 @@ like so: py::class_("MyClass") .def("myFunction", py::arg("arg") = (SomeType *) nullptr); +Keyword-only arguments +====================== + +Python 3 introduced keyword-only arguments by specifying an unnamed ``*`` +argument in a function definition: + +.. code-block:: python + + def f(a, *, b): # a can be positional or via keyword; b must be via keyword + pass + + f(a=1, b=2) # good + f(b=2, a=1) # good + f(1, b=2) # good + f(1, 2) # TypeError: f() takes 1 positional argument but 2 were given + +Pybind11 provides a ``py::args_kw_only`` object that allows you to implement +the same behaviour by specifying the object between positional and keyword-only +argument annotations when registering the function: + +.. code-block:: cpp + + m.def("f", [](int a, int b) { /* ... */ }, + py::arg("a"), py::args_kw_only(), py::arg("b")); + +Note that, as in Python, you cannot combine this with a ``py::args`` argument. +This feature does *not* require Python 3 to work. + .. _nonconverting_arguments: Non-converting arguments diff --git a/include/pybind11/attr.h b/include/pybind11/attr.h index 744284a83..70325510d 100644 --- a/include/pybind11/attr.h +++ b/include/pybind11/attr.h @@ -137,7 +137,8 @@ struct argument_record { struct function_record { function_record() : is_constructor(false), is_new_style_constructor(false), is_stateless(false), - is_operator(false), has_args(false), has_kwargs(false), is_method(false) { } + is_operator(false), is_method(false), + has_args(false), has_kwargs(false), has_kw_only_args(false) { } /// Function name char *name = nullptr; /* why no C++ strings? They generate heavier code.. */ @@ -175,18 +176,24 @@ struct function_record { /// True if this is an operator (__add__), etc. bool is_operator : 1; + /// True if this is a method + bool is_method : 1; + /// True if the function has a '*args' argument bool has_args : 1; /// True if the function has a '**kwargs' argument bool has_kwargs : 1; - /// True if this is a method - bool is_method : 1; + /// True once a 'py::args_kw_only' is encountered (any following args are keyword-only) + bool has_kw_only_args : 1; /// Number of arguments (including py::args and/or py::kwargs, if present) std::uint16_t nargs; + /// Number of trailing arguments (counted in `nargs`) that are keyword-only + std::uint16_t nargs_kwonly = 0; + /// Python method object PyMethodDef *def = nullptr; @@ -359,12 +366,20 @@ template <> struct process_attribute : process_attribu static void init(const is_new_style_constructor &, function_record *r) { r->is_new_style_constructor = true; } }; +inline void process_kwonly_arg(const arg &a, function_record *r) { + if (!a.name || strlen(a.name) == 0) + pybind11_fail("arg(): cannot specify an unnamed argument after an args_kw_only() annotation"); + ++r->nargs_kwonly; +} + /// Process a keyword argument attribute (*without* a default value) template <> struct process_attribute : process_attribute_default { static void init(const arg &a, function_record *r) { if (r->is_method && r->args.empty()) r->args.emplace_back("self", nullptr, handle(), true /*convert*/, false /*none not allowed*/); r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none); + + if (r->has_kw_only_args) process_kwonly_arg(a, r); } }; @@ -396,6 +411,15 @@ template <> struct process_attribute : process_attribute_default { #endif } r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none); + + if (r->has_kw_only_args) process_kwonly_arg(a, r); + } +}; + +/// Process a keyword-only-arguments-follow pseudo argument +template <> struct process_attribute : process_attribute_default { + static void init(const args_kw_only &, function_record *r) { + r->has_kw_only_args = true; } }; diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 0edc33686..2ea1c635b 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1887,6 +1887,11 @@ public: #endif }; +/// \ingroup annotations +/// Annotation indicating that all following arguments are keyword-only; the is the equivalent of an +/// unnamed '*' argument (in Python 3) +struct args_kw_only {}; + template arg_v arg::operator=(T &&value) const { return {std::move(*this), std::forward(value)}; } diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index d95d61f7b..ff586033d 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -168,6 +168,14 @@ protected: /* Process any user-provided function attributes */ process_attributes::init(extra..., rec); + { + constexpr bool has_kw_only_args = any_of...>::value, + has_args = any_of...>::value, + has_arg_annotations = any_of...>::value; + static_assert(has_arg_annotations || !has_kw_only_args, "py::args_kw_only requires the use of argument annotations"); + static_assert(!(has_args && has_kw_only_args), "py::args_kw_only cannot be combined with a py::args argument"); + } + /* Generate a readable signature describing the function's arguments and return value types */ static constexpr auto signature = _("(") + cast_in::arg_names + _(") -> ") + cast_out::name; PYBIND11_DESCR_CONSTEXPR auto types = decltype(signature)::types(); @@ -483,15 +491,16 @@ protected: */ const function_record &func = *it; - size_t pos_args = func.nargs; // Number of positional arguments that we need - if (func.has_args) --pos_args; // (but don't count py::args - if (func.has_kwargs) --pos_args; // or py::kwargs) + size_t num_args = func.nargs; // Number of positional arguments that we need + if (func.has_args) --num_args; // (but don't count py::args + if (func.has_kwargs) --num_args; // or py::kwargs) + size_t pos_args = num_args - func.nargs_kwonly; if (!func.has_args && n_args_in > pos_args) - continue; // Too many arguments for this overload + continue; // Too many positional arguments for this overload if (n_args_in < pos_args && func.args.size() < pos_args) - continue; // Not enough arguments given, and not enough defaults to fill in the blanks + continue; // Not enough positional arguments given, and not enough defaults to fill in the blanks function_call call(func, parent); @@ -535,10 +544,10 @@ protected: dict kwargs = reinterpret_borrow(kwargs_in); // 2. Check kwargs and, failing that, defaults that may help complete the list - if (args_copied < pos_args) { + if (args_copied < num_args) { bool copied_kwargs = false; - for (; args_copied < pos_args; ++args_copied) { + for (; args_copied < num_args; ++args_copied) { const auto &arg = func.args[args_copied]; handle value; @@ -564,7 +573,7 @@ protected: break; } - if (args_copied < pos_args) + if (args_copied < num_args) continue; // Not enough arguments, defaults, or kwargs to fill the positional arguments } diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp index 6563fb9ad..6c4971404 100644 --- a/tests/test_kwargs_and_defaults.cpp +++ b/tests/test_kwargs_and_defaults.cpp @@ -94,6 +94,30 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { // m.def("bad_args6", [](py::args, py::args) {}); // m.def("bad_args7", [](py::kwargs, py::kwargs) {}); + // test_keyword_only_args + m.def("kwonly_all", [](int i, int j) { return py::make_tuple(i, j); }, + py::args_kw_only(), py::arg("i"), py::arg("j")); + m.def("kwonly_some", [](int i, int j, int k) { return py::make_tuple(i, j, k); }, + py::arg(), py::args_kw_only(), py::arg("j"), py::arg("k")); + m.def("kwonly_with_defaults", [](int i, int j, int k, int z) { return py::make_tuple(i, j, k, z); }, + py::arg() = 3, "j"_a = 4, py::args_kw_only(), "k"_a = 5, "z"_a); + m.def("kwonly_mixed", [](int i, int j) { return py::make_tuple(i, j); }, + "i"_a, py::args_kw_only(), "j"_a); + m.def("kwonly_plus_more", [](int i, int j, int k, py::kwargs kwargs) { + return py::make_tuple(i, j, k, kwargs); }, + py::arg() /* positional */, py::arg("j") = -1 /* both */, py::args_kw_only(), py::arg("k") /* kw-only */); + + m.def("register_invalid_kwonly", [](py::module m) { + m.def("bad_kwonly", [](int i, int j) { return py::make_tuple(i, j); }, + py::args_kw_only(), py::arg() /* invalid unnamed argument */, "j"_a); + }); + + // These should fail to compile: + // argument annotations are required when using args_kw_only +// m.def("bad_kwonly1", [](int) {}, py::args_kw_only()); + // can't specify both `py::args_kw_only` and a `py::args` argument +// m.def("bad_kwonly2", [](int i, py::args) {}, py::args_kw_only(), "i"_a); + // test_function_signatures (along with most of the above) struct KWClass { void foo(int, float) {} }; py::class_(m, "KWClass") diff --git a/tests/test_kwargs_and_defaults.py b/tests/test_kwargs_and_defaults.py index 27a05a024..fa90140fd 100644 --- a/tests/test_kwargs_and_defaults.py +++ b/tests/test_kwargs_and_defaults.py @@ -107,6 +107,44 @@ def test_mixed_args_and_kwargs(msg): """ # noqa: E501 line too long +def test_keyword_only_args(msg): + assert m.kwonly_all(i=1, j=2) == (1, 2) + assert m.kwonly_all(j=1, i=2) == (2, 1) + + with pytest.raises(TypeError) as excinfo: + assert m.kwonly_all(i=1) == (1,) + assert "incompatible function arguments" in str(excinfo.value) + + with pytest.raises(TypeError) as excinfo: + assert m.kwonly_all(1, 2) == (1, 2) + assert "incompatible function arguments" in str(excinfo.value) + + assert m.kwonly_some(1, k=3, j=2) == (1, 2, 3) + + assert m.kwonly_with_defaults(z=8) == (3, 4, 5, 8) + assert m.kwonly_with_defaults(2, z=8) == (2, 4, 5, 8) + assert m.kwonly_with_defaults(2, j=7, k=8, z=9) == (2, 7, 8, 9) + assert m.kwonly_with_defaults(2, 7, z=9, k=8) == (2, 7, 8, 9) + + assert m.kwonly_mixed(1, j=2) == (1, 2) + assert m.kwonly_mixed(j=2, i=3) == (3, 2) + assert m.kwonly_mixed(i=2, j=3) == (2, 3) + + assert m.kwonly_plus_more(4, 5, k=6, extra=7) == (4, 5, 6, {'extra': 7}) + assert m.kwonly_plus_more(3, k=5, j=4, extra=6) == (3, 4, 5, {'extra': 6}) + assert m.kwonly_plus_more(2, k=3, extra=4) == (2, -1, 3, {'extra': 4}) + + with pytest.raises(TypeError) as excinfo: + assert m.kwonly_mixed(i=1) == (1,) + assert "incompatible function arguments" in str(excinfo.value) + + with pytest.raises(RuntimeError) as excinfo: + m.register_invalid_kwonly(m) + assert msg(excinfo.value) == """ + arg(): cannot specify an unnamed argument after an args_kw_only() annotation + """ + + def test_args_refcount(): """Issue/PR #1216 - py::args elements get double-inc_ref()ed when combined with regular arguments""" From a86ac538f59db7af596ee192f42b9f39ec8039ed Mon Sep 17 00:00:00 2001 From: Sebastian Koslowski Date: Tue, 14 Apr 2020 13:04:25 +0200 Subject: [PATCH 072/768] rename args_kw_only to kwonly --- docs/advanced/functions.rst | 4 ++-- include/pybind11/attr.h | 18 +++++++++--------- include/pybind11/cast.h | 2 +- include/pybind11/pybind11.h | 6 +++--- tests/test_kwargs_and_defaults.cpp | 20 ++++++++++---------- tests/test_kwargs_and_defaults.py | 2 +- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/advanced/functions.rst b/docs/advanced/functions.rst index c7790533b..984b046ef 100644 --- a/docs/advanced/functions.rst +++ b/docs/advanced/functions.rst @@ -378,14 +378,14 @@ argument in a function definition: f(1, b=2) # good f(1, 2) # TypeError: f() takes 1 positional argument but 2 were given -Pybind11 provides a ``py::args_kw_only`` object that allows you to implement +Pybind11 provides a ``py::kwonly`` object that allows you to implement the same behaviour by specifying the object between positional and keyword-only argument annotations when registering the function: .. code-block:: cpp m.def("f", [](int a, int b) { /* ... */ }, - py::arg("a"), py::args_kw_only(), py::arg("b")); + py::arg("a"), py::kwonly(), py::arg("b")); Note that, as in Python, you cannot combine this with a ``py::args`` argument. This feature does *not* require Python 3 to work. diff --git a/include/pybind11/attr.h b/include/pybind11/attr.h index 70325510d..58390239a 100644 --- a/include/pybind11/attr.h +++ b/include/pybind11/attr.h @@ -138,7 +138,7 @@ struct function_record { function_record() : is_constructor(false), is_new_style_constructor(false), is_stateless(false), is_operator(false), is_method(false), - has_args(false), has_kwargs(false), has_kw_only_args(false) { } + has_args(false), has_kwargs(false), has_kwonly_args(false) { } /// Function name char *name = nullptr; /* why no C++ strings? They generate heavier code.. */ @@ -185,8 +185,8 @@ struct function_record { /// True if the function has a '**kwargs' argument bool has_kwargs : 1; - /// True once a 'py::args_kw_only' is encountered (any following args are keyword-only) - bool has_kw_only_args : 1; + /// True once a 'py::kwonly' is encountered (any following args are keyword-only) + bool has_kwonly_args : 1; /// Number of arguments (including py::args and/or py::kwargs, if present) std::uint16_t nargs; @@ -368,7 +368,7 @@ template <> struct process_attribute : process_attribu inline void process_kwonly_arg(const arg &a, function_record *r) { if (!a.name || strlen(a.name) == 0) - pybind11_fail("arg(): cannot specify an unnamed argument after an args_kw_only() annotation"); + pybind11_fail("arg(): cannot specify an unnamed argument after an kwonly() annotation"); ++r->nargs_kwonly; } @@ -379,7 +379,7 @@ template <> struct process_attribute : process_attribute_default { r->args.emplace_back("self", nullptr, handle(), true /*convert*/, false /*none not allowed*/); r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none); - if (r->has_kw_only_args) process_kwonly_arg(a, r); + if (r->has_kwonly_args) process_kwonly_arg(a, r); } }; @@ -412,14 +412,14 @@ template <> struct process_attribute : process_attribute_default { } r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none); - if (r->has_kw_only_args) process_kwonly_arg(a, r); + if (r->has_kwonly_args) process_kwonly_arg(a, r); } }; /// Process a keyword-only-arguments-follow pseudo argument -template <> struct process_attribute : process_attribute_default { - static void init(const args_kw_only &, function_record *r) { - r->has_kw_only_args = true; +template <> struct process_attribute : process_attribute_default { + static void init(const kwonly &, function_record *r) { + r->has_kwonly_args = true; } }; diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 2ea1c635b..91c9ce753 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1890,7 +1890,7 @@ public: /// \ingroup annotations /// Annotation indicating that all following arguments are keyword-only; the is the equivalent of an /// unnamed '*' argument (in Python 3) -struct args_kw_only {}; +struct kwonly {}; template arg_v arg::operator=(T &&value) const { return {std::move(*this), std::forward(value)}; } diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index ff586033d..722a19a1a 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -169,11 +169,11 @@ protected: process_attributes::init(extra..., rec); { - constexpr bool has_kw_only_args = any_of...>::value, + constexpr bool has_kwonly_args = any_of...>::value, has_args = any_of...>::value, has_arg_annotations = any_of...>::value; - static_assert(has_arg_annotations || !has_kw_only_args, "py::args_kw_only requires the use of argument annotations"); - static_assert(!(has_args && has_kw_only_args), "py::args_kw_only cannot be combined with a py::args argument"); + static_assert(has_arg_annotations || !has_kwonly_args, "py::kwonly requires the use of argument annotations"); + static_assert(!(has_args && has_kwonly_args), "py::kwonly cannot be combined with a py::args argument"); } /* Generate a readable signature describing the function's arguments and return value types */ diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp index 6c4971404..8f095fe4a 100644 --- a/tests/test_kwargs_and_defaults.cpp +++ b/tests/test_kwargs_and_defaults.cpp @@ -96,27 +96,27 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { // test_keyword_only_args m.def("kwonly_all", [](int i, int j) { return py::make_tuple(i, j); }, - py::args_kw_only(), py::arg("i"), py::arg("j")); + py::kwonly(), py::arg("i"), py::arg("j")); m.def("kwonly_some", [](int i, int j, int k) { return py::make_tuple(i, j, k); }, - py::arg(), py::args_kw_only(), py::arg("j"), py::arg("k")); + py::arg(), py::kwonly(), py::arg("j"), py::arg("k")); m.def("kwonly_with_defaults", [](int i, int j, int k, int z) { return py::make_tuple(i, j, k, z); }, - py::arg() = 3, "j"_a = 4, py::args_kw_only(), "k"_a = 5, "z"_a); + py::arg() = 3, "j"_a = 4, py::kwonly(), "k"_a = 5, "z"_a); m.def("kwonly_mixed", [](int i, int j) { return py::make_tuple(i, j); }, - "i"_a, py::args_kw_only(), "j"_a); + "i"_a, py::kwonly(), "j"_a); m.def("kwonly_plus_more", [](int i, int j, int k, py::kwargs kwargs) { return py::make_tuple(i, j, k, kwargs); }, - py::arg() /* positional */, py::arg("j") = -1 /* both */, py::args_kw_only(), py::arg("k") /* kw-only */); + py::arg() /* positional */, py::arg("j") = -1 /* both */, py::kwonly(), py::arg("k") /* kw-only */); m.def("register_invalid_kwonly", [](py::module m) { m.def("bad_kwonly", [](int i, int j) { return py::make_tuple(i, j); }, - py::args_kw_only(), py::arg() /* invalid unnamed argument */, "j"_a); + py::kwonly(), py::arg() /* invalid unnamed argument */, "j"_a); }); // These should fail to compile: - // argument annotations are required when using args_kw_only -// m.def("bad_kwonly1", [](int) {}, py::args_kw_only()); - // can't specify both `py::args_kw_only` and a `py::args` argument -// m.def("bad_kwonly2", [](int i, py::args) {}, py::args_kw_only(), "i"_a); + // argument annotations are required when using kwonly +// m.def("bad_kwonly1", [](int) {}, py::kwonly()); + // can't specify both `py::kwonly` and a `py::args` argument +// m.def("bad_kwonly2", [](int i, py::args) {}, py::kwonly(), "i"_a); // test_function_signatures (along with most of the above) struct KWClass { void foo(int, float) {} }; diff --git a/tests/test_kwargs_and_defaults.py b/tests/test_kwargs_and_defaults.py index fa90140fd..bad6636cb 100644 --- a/tests/test_kwargs_and_defaults.py +++ b/tests/test_kwargs_and_defaults.py @@ -141,7 +141,7 @@ def test_keyword_only_args(msg): with pytest.raises(RuntimeError) as excinfo: m.register_invalid_kwonly(m) assert msg(excinfo.value) == """ - arg(): cannot specify an unnamed argument after an args_kw_only() annotation + arg(): cannot specify an unnamed argument after an kwonly() annotation """ From 805c5862b61204cb2e43911c794d78326e947cb7 Mon Sep 17 00:00:00 2001 From: Yannick Jadoul Date: Sat, 25 Jan 2020 23:38:01 +0100 Subject: [PATCH 073/768] Adding method names to cpp_function constructor calls in enum_base --- include/pybind11/pybind11.h | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 722a19a1a..dee2423de 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1427,7 +1427,7 @@ struct enum_base { return pybind11::str("{}.{}").format(type_name, kv.first); } return pybind11::str("{}.???").format(type_name); - }, is_method(m_base) + }, name("__repr__"), is_method(m_base) ); m_base.attr("name") = property(cpp_function( @@ -1438,7 +1438,7 @@ struct enum_base { return pybind11::str(kv.first); } return "???"; - }, is_method(m_base) + }, name("name"), is_method(m_base) )); m_base.attr("__doc__") = static_property(cpp_function( @@ -1456,7 +1456,7 @@ struct enum_base { docstring += " : " + (std::string) pybind11::str(comment); } return docstring; - } + }, name("__doc__") ), none(), none(), ""); m_base.attr("__members__") = static_property(cpp_function( @@ -1465,7 +1465,7 @@ struct enum_base { for (const auto &kv : entries) m[kv.first] = kv.second[int_(0)]; return m; - }), none(), none(), "" + }, name("__members__")), none(), none(), "" ); #define PYBIND11_ENUM_OP_STRICT(op, expr, strict_behavior) \ @@ -1475,7 +1475,7 @@ struct enum_base { strict_behavior; \ return expr; \ }, \ - is_method(m_base)) + name(op), is_method(m_base)) #define PYBIND11_ENUM_OP_CONV(op, expr) \ m_base.attr(op) = cpp_function( \ @@ -1483,7 +1483,7 @@ struct enum_base { int_ a(a_), b(b_); \ return expr; \ }, \ - is_method(m_base)) + name(op), is_method(m_base)) #define PYBIND11_ENUM_OP_CONV_LHS(op, expr) \ m_base.attr(op) = cpp_function( \ @@ -1491,7 +1491,7 @@ struct enum_base { int_ a(a_); \ return expr; \ }, \ - is_method(m_base)) + name(op), is_method(m_base)) if (is_convertible) { PYBIND11_ENUM_OP_CONV_LHS("__eq__", !b.is_none() && a.equal(b)); @@ -1509,7 +1509,7 @@ struct enum_base { PYBIND11_ENUM_OP_CONV("__xor__", a ^ b); PYBIND11_ENUM_OP_CONV("__rxor__", a ^ b); m_base.attr("__invert__") = cpp_function( - [](object arg) { return ~(int_(arg)); }, is_method(m_base)); + [](object arg) { return ~(int_(arg)); }, name("__invert__"), is_method(m_base)); } } else { PYBIND11_ENUM_OP_STRICT("__eq__", int_(a).equal(int_(b)), return false); @@ -1529,11 +1529,11 @@ struct enum_base { #undef PYBIND11_ENUM_OP_CONV #undef PYBIND11_ENUM_OP_STRICT - object getstate = cpp_function( - [](object arg) { return int_(arg); }, is_method(m_base)); + m_base.attr("__getstate__") = cpp_function( + [](object arg) { return int_(arg); }, name("__getstate__"), is_method(m_base)); - m_base.attr("__getstate__") = getstate; - m_base.attr("__hash__") = getstate; + m_base.attr("__hash__") = cpp_function( + [](object arg) { return int_(arg); }, name("__hash__"), is_method(m_base)); } PYBIND11_NOINLINE void value(char const* name_, object value, const char *doc = nullptr) { @@ -1586,10 +1586,12 @@ public: def("__index__", [](Type value) { return (Scalar) value; }); #endif - cpp_function setstate( - [](Type &value, Scalar arg) { value = static_cast(arg); }, - is_method(*this)); - attr("__setstate__") = setstate; + attr("__setstate__") = cpp_function( + [](detail::value_and_holder &v_h, Scalar arg) { + detail::initimpl::setstate(v_h, static_cast(arg), + Py_TYPE(v_h.inst) != v_h.type->type); }, + detail::is_new_style_constructor(), + pybind11::name("__setstate__"), is_method(*this)); } /// Export enumeration entries into the parent scope From 02c83dba0f6efeef536f0bb8c1aac99f603c96b0 Mon Sep 17 00:00:00 2001 From: Nicholas Musolino Date: Sun, 26 Jan 2020 11:49:32 -0500 Subject: [PATCH 074/768] Propagate exceptions in sequence::size() (#2076) --- include/pybind11/pytypes.h | 7 ++++++- tests/test_sequences_and_iterators.cpp | 3 +++ tests/test_sequences_and_iterators.py | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 4003d6918..63cbf2e56 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -1242,7 +1242,12 @@ private: class sequence : public object { public: PYBIND11_OBJECT_DEFAULT(sequence, object, PySequence_Check) - size_t size() const { return (size_t) PySequence_Size(m_ptr); } + size_t size() const { + ssize_t result = PySequence_Size(m_ptr); + if (result == -1) + throw error_already_set(); + return (size_t) result; + } bool empty() const { return size() == 0; } detail::sequence_accessor operator[](size_t index) const { return {*this, index}; } detail::item_accessor operator[](handle h) const { return object::operator[](h); } diff --git a/tests/test_sequences_and_iterators.cpp b/tests/test_sequences_and_iterators.cpp index 87ccf99d6..05f999bb3 100644 --- a/tests/test_sequences_and_iterators.cpp +++ b/tests/test_sequences_and_iterators.cpp @@ -319,6 +319,9 @@ TEST_SUBMODULE(sequences_and_iterators, m) { return l; }); + // test_sequence_length: check that Python sequences can be converted to py::sequence. + m.def("sequence_length", [](py::sequence seq) { return seq.size(); }); + // Make sure that py::iterator works with std algorithms m.def("count_none", [](py::object o) { return std::count_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); }); diff --git a/tests/test_sequences_and_iterators.py b/tests/test_sequences_and_iterators.py index 6bd160640..d839dbef6 100644 --- a/tests/test_sequences_and_iterators.py +++ b/tests/test_sequences_and_iterators.py @@ -100,6 +100,25 @@ def test_sequence(): assert cstats.move_assignments == 0 +def test_sequence_length(): + """#2076: Exception raised by len(arg) should be propagated """ + class BadLen(RuntimeError): + pass + + class SequenceLike(): + def __getitem__(self, i): + return None + + def __len__(self): + raise BadLen() + + with pytest.raises(BadLen): + m.sequence_length(SequenceLike()) + + assert m.sequence_length([1, 2, 3]) == 3 + assert m.sequence_length("hello") == 5 + + def test_map_iterator(): sm = m.StringMap({'hi': 'bye', 'black': 'white'}) assert sm['hi'] == 'bye' From 2c4cd8419dd81f0563373150c5c1474bfc308352 Mon Sep 17 00:00:00 2001 From: Dustin Spicuzza Date: Sun, 24 Nov 2019 02:36:48 -0500 Subject: [PATCH 075/768] Add AutoWIG to list of binding generators (#1990) * Add AutoWIG to list of binding generators --- docs/compiling.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/compiling.rst b/docs/compiling.rst index ea8d1ec16..bfb1cd805 100644 --- a/docs/compiling.rst +++ b/docs/compiling.rst @@ -283,3 +283,11 @@ code by introspecting existing C++ codebases using LLVM/Clang. See the [binder]_ documentation for details. .. [binder] http://cppbinder.readthedocs.io/en/latest/about.html + +[AutoWIG]_ is a Python library that wraps automatically compiled libraries into +high-level languages. It parses C++ code using LLVM/Clang technologies and +generates the wrappers using the Mako templating engine. The approach is automatic, +extensible, and applies to very complex C++ libraries, composed of thousands of +classes or incorporating modern meta-programming constructs. + +.. [AutoWIG] https://github.com/StatisKit/AutoWIG From a54eab92d265337996b8e4b4149d9176c2d428a6 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Sun, 26 Apr 2020 22:53:50 +0200 Subject: [PATCH 076/768] Revert "Change __init__(self) to __new__(cls)" This reverts commit 9ed8b44033e64f2990bf123b5057e92b8142edae. --- docs/advanced/cast/custom.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/advanced/cast/custom.rst b/docs/advanced/cast/custom.rst index f80359431..e4f99ac5b 100644 --- a/docs/advanced/cast/custom.rst +++ b/docs/advanced/cast/custom.rst @@ -23,7 +23,7 @@ The following Python snippet demonstrates the intended usage from the Python sid .. code-block:: python class A: - def __new__(cls): + def __int__(self): return 123 from example import print From a38e5331d7b98f99ac4f7284ef3359b327d99241 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Sun, 31 May 2020 00:29:30 -0400 Subject: [PATCH 077/768] Fix CI, prepare test on Python 3.9 beta (#2233) * Test on Python 3.9 beta * Pin Sphinx * Newer version of PyPy --- .travis.yml | 58 ++++++++++++++++++++++++++++----------- tests/test_stl_binders.py | 1 + 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index d81cd8c7b..f9a906541 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,8 @@ matrix: - $PY_CMD -m pip install --user --upgrade pip wheel setuptools install: # breathe 4.14 doesn't work with bit fields. See https://github.com/michaeljones/breathe/issues/462 - - $PY_CMD -m pip install --user --upgrade sphinx sphinx_rtd_theme breathe==4.13.1 flake8 pep8-naming pytest + # Latest breathe + Sphinx causes warnings and errors out + - $PY_CMD -m pip install --user --upgrade "sphinx<3" sphinx_rtd_theme breathe==4.13.1 flake8 pep8-naming pytest - curl -fsSL https://sourceforge.net/projects/doxygen/files/rel-1.8.15/doxygen-1.8.15.linux.bin.tar.gz/download | tar xz - export PATH="$PWD/doxygen-1.8.15/bin:$PATH" script: @@ -109,7 +110,7 @@ matrix: - os: linux dist: xenial env: PYTHON=3.8 CPP=17 GCC=7 - name: Python 3.8, c++17, gcc 7 (w/o numpy/scipy) # TODO: update build name when the numpy/scipy wheels become available + name: Python 3.8, c++17, gcc 7 addons: apt: sources: @@ -119,12 +120,21 @@ matrix: - g++-7 - python3.8-dev - python3.8-venv - # Currently there is no numpy/scipy wheels available for python3.8 - # TODO: remove next before_install, install and script clause when the wheels become available - before_install: - - pyenv global $(pyenv whence 2to3) # activate all python versions - - PY_CMD=python3 - - $PY_CMD -m pip install --user --upgrade pip wheel setuptools + - os: linux + dist: xenial + env: PYTHON=3.9 CPP=17 GCC=7 + name: Python 3.9 beta, c++17, gcc 7 (w/o numpy/scipy) # TODO: update build name when the numpy/scipy wheels become available + addons: + apt: + sources: + - deadsnakes + - ubuntu-toolchain-r-test + packages: + - g++-7 + - python3.9-dev + - python3.9-venv + # Currently there are no numpy/scipy wheels available for python3.9 + # TODO: remove next install and script clause when the wheels become available install: - $PY_CMD -m pip install --user --upgrade pytest script: @@ -143,14 +153,25 @@ matrix: # Test a PyPy 2.7 build - os: linux dist: trusty - env: PYPY=5.8 PYTHON=2.7 CPP=11 GCC=4.8 - name: PyPy 5.8, Python 2.7, c++11, gcc 4.8 + env: PYPY=7.3.1 PYTHON=2.7 CPP=11 GCC=4.8 + name: PyPy 7.3, Python 2.7, c++11, gcc 4.8 addons: apt: packages: - libblas-dev - liblapack-dev - gfortran + - os: linux + dist: xenial + env: PYPY=7.3.1 PYTHON=3.6 CPP=11 GCC=5 + name: PyPy 7.3, Python 3.6, c++11, gcc 5 + addons: + apt: + packages: + - libblas-dev + - liblapack-dev + - gfortran + - g++-5 # Build in 32-bit mode and tests against the CMake-installed version - os: linux dist: trusty @@ -170,6 +191,10 @@ matrix: cmake ../pybind11-tests ${CMAKE_EXTRA_ARGS} -DPYBIND11_WERROR=ON make pytest -j 2" set +ex + allow_failures: + - name: PyPy 7.3, Python 2.7, c++11, gcc 4.8 + - name: PyPy 7.3, Python 3.6, c++11, gcc 5 + - name: Python 3.9 beta, c++17, gcc 7 (w/o numpy/scipy) cache: directories: - $HOME/.local/bin @@ -211,9 +236,9 @@ before_install: SCRIPT_RUN_PREFIX="docker exec --tty $containerid" $SCRIPT_RUN_PREFIX sh -c 'for s in 0 15; do sleep $s; apt-get update && apt-get -qy dist-upgrade && break; done' else - if [ "$PYPY" = "5.8" ]; then - curl -fSL https://bitbucket.org/pypy/pypy/downloads/pypy2-v5.8.0-linux64.tar.bz2 | tar xj - PY_CMD=$(echo `pwd`/pypy2-v5.8.0-linux64/bin/pypy) + if [ -n "$PYPY" ]; then + curl -fSL https://bitbucket.org/pypy/pypy/downloads/pypy$PYTHON-v$PYPY-linux64.tar.bz2 | tar xj + PY_CMD=$(echo `pwd`/pypy$PYTHON-v$PYPY-linux64/bin/pypy$PY) CMAKE_EXTRA_ARGS+=" -DPYTHON_EXECUTABLE:FILEPATH=$PY_CMD" else PY_CMD=python$PYTHON @@ -255,11 +280,12 @@ install: export NPY_NUM_BUILD_JOBS=2 echo "Installing pytest, numpy, scipy..." local PIP_CMD="" - if [ -n $PYPY ]; then + if [ -n "$PYPY" ]; then # For expediency, install only versions that are available on the extra index. travis_wait 30 \ - $PY_CMD -m pip install --user --upgrade --extra-index-url https://imaginary.ca/trusty-pypi \ - pytest numpy==1.15.4 scipy==1.2.0 + $PY_CMD -m pip install --user --upgrade --extra-index-url https://antocuni.github.io/pypy-wheels/manylinux2010 \ + numpy scipy + $PY_CMD -m pip install --user --upgrade pytest else $PY_CMD -m pip install --user --upgrade pytest numpy scipy fi diff --git a/tests/test_stl_binders.py b/tests/test_stl_binders.py index c7b7e8535..c1264c01f 100644 --- a/tests/test_stl_binders.py +++ b/tests/test_stl_binders.py @@ -67,6 +67,7 @@ def test_vector_int(): v_int2.clear() assert len(v_int2) == 0 + # related to the PyPy's buffer protocol. @pytest.unsupported_on_pypy def test_vector_buffer(): From a3118130c6cf6307bf21fdb7ce9c00a71aec1360 Mon Sep 17 00:00:00 2001 From: "Andrew J. Hesford" <48421688+ahesford@users.noreply.github.com> Date: Sun, 31 May 2020 00:59:50 -0400 Subject: [PATCH 078/768] pytypes.h: fix docs generation (#2220) --- include/pybind11/pytypes.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 63cbf2e56..6cf7fe173 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -980,6 +980,9 @@ public: return std::string(buffer, (size_t) length); } }; +// 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 +/// @} pytypes inline bytes::bytes(const pybind11::str &s) { object temp = s; @@ -1009,6 +1012,8 @@ inline str::str(const bytes& b) { m_ptr = obj.release().ptr(); } +/// \addtogroup pytypes +/// @{ class none : public object { public: PYBIND11_OBJECT(none, object, detail::PyNone_Check) From 2c30e0a11867f09ff21292f435fd99e3ab973de9 Mon Sep 17 00:00:00 2001 From: Eric Cousineau Date: Sun, 31 May 2020 01:00:55 -0400 Subject: [PATCH 079/768] cmake: Expose `PYBIND11_TEST_OVERRIDE` (#2218) Primarily for the ccmake curses GUI --- tests/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 765c47adb..58993d159 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,6 +8,7 @@ cmake_minimum_required(VERSION 2.8.12) option(PYBIND11_WERROR "Report all warnings as errors" OFF) +set(PYBIND11_TEST_OVERRIDE "" CACHE STRING "Tests from ;-separated list of *.cpp files will be built instead of all tests") if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) # We're being loaded directly, i.e. not via add_subdirectory, so make this From 5309573005eddbdcebaffa4f1ef88178d24497e9 Mon Sep 17 00:00:00 2001 From: Eric Cousineau Date: Mon, 18 May 2020 15:33:23 -0400 Subject: [PATCH 080/768] operators: Move hash check to before mutations, tweak whitespace --- tests/test_operator_overloading.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/tests/test_operator_overloading.py b/tests/test_operator_overloading.py index bd36ac2a5..f283f5b3a 100644 --- a/tests/test_operator_overloading.py +++ b/tests/test_operator_overloading.py @@ -24,6 +24,8 @@ def test_operator_overloading(): assert str(v1 * v2) == "[3.000000, -2.000000]" assert str(v2 / v1) == "[3.000000, -0.500000]" + assert hash(v1) == 4 + v1 += 2 * v2 assert str(v1) == "[7.000000, 0.000000]" v1 -= v2 @@ -37,22 +39,30 @@ def test_operator_overloading(): v2 /= v1 assert str(v2) == "[2.000000, 8.000000]" - assert hash(v1) == 4 - cstats = ConstructorStats.get(m.Vector2) assert cstats.alive() == 2 del v1 assert cstats.alive() == 1 del v2 assert cstats.alive() == 0 - assert cstats.values() == ['[1.000000, 2.000000]', '[3.000000, -1.000000]', - '[-3.000000, 1.000000]', '[4.000000, 1.000000]', - '[-2.000000, 3.000000]', '[-7.000000, -6.000000]', - '[9.000000, 10.000000]', '[8.000000, 16.000000]', - '[0.125000, 0.250000]', '[7.000000, 6.000000]', - '[9.000000, 10.000000]', '[8.000000, 16.000000]', - '[8.000000, 4.000000]', '[3.000000, -2.000000]', - '[3.000000, -0.500000]', '[6.000000, -2.000000]'] + assert cstats.values() == [ + '[1.000000, 2.000000]', + '[3.000000, -1.000000]', + '[-3.000000, 1.000000]', + '[4.000000, 1.000000]', + '[-2.000000, 3.000000]', + '[-7.000000, -6.000000]', + '[9.000000, 10.000000]', + '[8.000000, 16.000000]', + '[0.125000, 0.250000]', + '[7.000000, 6.000000]', + '[9.000000, 10.000000]', + '[8.000000, 16.000000]', + '[8.000000, 4.000000]', + '[3.000000, -2.000000]', + '[3.000000, -0.500000]', + '[6.000000, -2.000000]', + ] assert cstats.default_constructions == 0 assert cstats.copy_constructions == 0 assert cstats.move_constructions >= 10 From 4e3d9fea74ed50a042d98f68fa35a3133482289b Mon Sep 17 00:00:00 2001 From: Eric Cousineau Date: Fri, 22 May 2020 00:43:01 -0400 Subject: [PATCH 081/768] operators: Explicitly expose `py::hash(py::self)` Add warnings about extending STL --- include/pybind11/operators.h | 5 +++++ tests/test_operator_overloading.cpp | 25 ++++++++++++++++++++++++- tests/test_operator_overloading.py | 14 ++++++++++++-- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/include/pybind11/operators.h b/include/pybind11/operators.h index b3dd62c3b..293d5abd2 100644 --- a/include/pybind11/operators.h +++ b/include/pybind11/operators.h @@ -147,6 +147,9 @@ PYBIND11_INPLACE_OPERATOR(ixor, operator^=, l ^= r) PYBIND11_INPLACE_OPERATOR(ior, operator|=, l |= r) PYBIND11_UNARY_OPERATOR(neg, operator-, -l) PYBIND11_UNARY_OPERATOR(pos, operator+, +l) +// WARNING: This usage of `abs` should only be done for existing STL overloads. +// Adding overloads directly in to the `std::` namespace is advised against: +// https://en.cppreference.com/w/cpp/language/extending_std PYBIND11_UNARY_OPERATOR(abs, abs, std::abs(l)) PYBIND11_UNARY_OPERATOR(hash, hash, std::hash()(l)) PYBIND11_UNARY_OPERATOR(invert, operator~, (~l)) @@ -160,6 +163,8 @@ PYBIND11_UNARY_OPERATOR(float, float_, (double) l) NAMESPACE_END(detail) using detail::self; +// Add named operators so that they are accessible via `py::`. +using detail::hash; NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/tests/test_operator_overloading.cpp b/tests/test_operator_overloading.cpp index 7b111704b..52fcd3383 100644 --- a/tests/test_operator_overloading.cpp +++ b/tests/test_operator_overloading.cpp @@ -43,6 +43,13 @@ public: friend Vector2 operator-(float f, const Vector2 &v) { return Vector2(f - v.x, f - v.y); } friend Vector2 operator*(float f, const Vector2 &v) { return Vector2(f * v.x, f * v.y); } friend Vector2 operator/(float f, const Vector2 &v) { return Vector2(f / v.x, f / v.y); } + + bool operator==(const Vector2 &v) const { + return x == v.x && y == v.y; + } + bool operator!=(const Vector2 &v) const { + return x != v.x || y != v.y; + } private: float x, y; }; @@ -55,6 +62,11 @@ int operator+(const C2 &, const C2 &) { return 22; } int operator+(const C2 &, const C1 &) { return 21; } int operator+(const C1 &, const C2 &) { return 12; } +// Note: Specializing explicit within `namespace std { ... }` is done due to a +// bug in GCC<7. If you are supporting compilers later than this, consider +// specializing `using template<> struct std::hash<...>` in the global +// namespace instead, per this recommendation: +// https://en.cppreference.com/w/cpp/language/extending_std#Adding_template_specializations namespace std { template<> struct hash { @@ -63,6 +75,11 @@ namespace std { }; } +// Not a good abs function, but easy to test. +std::string abs(const Vector2&) { + return "abs(Vector2)"; +} + // MSVC warns about unknown pragmas, and warnings are errors. #ifndef _MSC_VER #pragma GCC diagnostic push @@ -107,7 +124,13 @@ TEST_SUBMODULE(operators, m) { .def(float() / py::self) .def(-py::self) .def("__str__", &Vector2::toString) - .def(hash(py::self)) + .def("__repr__", &Vector2::toString) + .def(py::self == py::self) + .def(py::self != py::self) + .def(py::hash(py::self)) + // N.B. See warning about usage of `py::detail::abs(py::self)` in + // `operators.h`. + .def("__abs__", [](const Vector2& v) { return abs(v); }) ; m.attr("Vector") = m.attr("Vector2"); diff --git a/tests/test_operator_overloading.py b/tests/test_operator_overloading.py index f283f5b3a..1cee29889 100644 --- a/tests/test_operator_overloading.py +++ b/tests/test_operator_overloading.py @@ -6,6 +6,9 @@ from pybind11_tests import ConstructorStats def test_operator_overloading(): v1 = m.Vector2(1, 2) v2 = m.Vector(3, -1) + v3 = m.Vector2(1, 2) # Same value as v1, but different instance. + assert v1 is not v3 + assert str(v1) == "[1.000000, 2.000000]" assert str(v2) == "[3.000000, -1.000000]" @@ -24,7 +27,11 @@ def test_operator_overloading(): assert str(v1 * v2) == "[3.000000, -2.000000]" assert str(v2 / v1) == "[3.000000, -0.500000]" + assert v1 == v3 + assert v1 != v2 assert hash(v1) == 4 + # TODO(eric.cousineau): Make this work. + # assert abs(v1) == "abs(Vector2)" v1 += 2 * v2 assert str(v1) == "[7.000000, 0.000000]" @@ -40,14 +47,17 @@ def test_operator_overloading(): assert str(v2) == "[2.000000, 8.000000]" cstats = ConstructorStats.get(m.Vector2) - assert cstats.alive() == 2 + assert cstats.alive() == 3 del v1 - assert cstats.alive() == 1 + assert cstats.alive() == 2 del v2 + assert cstats.alive() == 1 + del v3 assert cstats.alive() == 0 assert cstats.values() == [ '[1.000000, 2.000000]', '[3.000000, -1.000000]', + '[1.000000, 2.000000]', '[-3.000000, 1.000000]', '[4.000000, 1.000000]', '[-2.000000, 3.000000]', From 1817d2116a3b2b9f5239b25b87657a324695fb5a Mon Sep 17 00:00:00 2001 From: Andrey Dorozhkin Date: Tue, 2 Jun 2020 16:43:07 +0300 Subject: [PATCH 082/768] Disable defining (v)snprintf as macro in modern Visual Studio --- include/pybind11/detail/common.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index dd6267936..fb7c22f60 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -96,6 +96,12 @@ #define PYBIND11_VERSION_MINOR 5 #define PYBIND11_VERSION_PATCH dev1 +/* Don't let Python.h #define (v)snprintf as macro because they are implemented + properly in Visual Studio since 2015. */ +#if defined(_MSC_VER) && _MSC_VER >= 1900 +# define HAVE_SNPRINTF 1 +#endif + /// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode #if defined(_MSC_VER) # if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 4) From eeb1044818af5b70761deae602c49eba439164dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6ppe?= Date: Wed, 3 Jun 2020 13:51:40 +0100 Subject: [PATCH 083/768] [common.h] Mark entry point as "unused". This change defines a new, portable macro PYBIND11_MAYBE_UNUSED to mark declarations as unused, and annotates the PYBIND11_MODULE entry point with this attribute. The purpose of this annotation is to facilitate dead code detection, which might otherwise consider the module entry point function dead, since it isn't otherwise used. (It is only used via FFI.) --- include/pybind11/detail/common.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index fb7c22f60..d466925dd 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -92,6 +92,14 @@ # define PYBIND11_DEPRECATED(reason) __attribute__((deprecated(reason))) #endif +#if defined(PYBIND11_CPP17) +# define PYBIND11_MAYBE_UNUSED [[maybe_unused]] +#elif defined(_MSC_VER) && !defined(__clang__) +# define PYBIND11_MAYBE_UNUSED +#else +# define PYBIND11_MAYBE_UNUSED __attribute__ ((__unused__)) +#endif + #define PYBIND11_VERSION_MAJOR 2 #define PYBIND11_VERSION_MINOR 5 #define PYBIND11_VERSION_PATCH dev1 @@ -285,6 +293,10 @@ extern "C" { should not be in quotes. The second macro argument defines a variable of type `py::module` which can be used to initialize the module. + The entry point is marked as "maybe unused" to aid dead-code detection analysis: + since the entry point is typically only looked up at runtime and not referenced + during translation, it would otherwise appear as unused ("dead") code. + .. code-block:: cpp PYBIND11_MODULE(example, m) { @@ -297,6 +309,7 @@ extern "C" { } \endrst */ #define PYBIND11_MODULE(name, variable) \ + PYBIND11_MAYBE_UNUSED \ static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &); \ PYBIND11_PLUGIN_IMPL(name) { \ PYBIND11_CHECK_PYTHON_VERSION \ From c776e9ef937e3286c96f801ce2c4221f245e1bff Mon Sep 17 00:00:00 2001 From: Simeon Ehrig Date: Wed, 3 Jun 2020 12:12:51 +0200 Subject: [PATCH 084/768] Fix compiler error with MSVC 17 and CUDA 10.2 --- include/pybind11/cast.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 91c9ce753..2b382ddfd 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1498,7 +1498,9 @@ public: } explicit operator type*() { return this->value; } - explicit operator type&() { return *(this->value); } + // static_cast works around compiler error with MSVC 17 and CUDA 10.2 + // see issue #2180 + explicit operator type&() { return *(static_cast(this->value)); } explicit operator holder_type*() { return std::addressof(holder); } // Workaround for Intel compiler bug From 1e14930dfcee467da6a28b44f0f276451935970b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6ppe?= Date: Wed, 3 Jun 2020 13:51:40 +0100 Subject: [PATCH 085/768] [common.h] Mark another entry point as "unused". For rationale, see #2241, eeb1044818af5b70761deae602c49eba439164dc; there is a second entry point function defined by the PYBIND11_MODULE macro that also needs to be annotated as unused. --- include/pybind11/detail/common.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index d466925dd..f4840daef 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -185,9 +185,10 @@ #define PYBIND11_STR_TYPE ::pybind11::str #define PYBIND11_BOOL_ATTR "__bool__" #define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_bool) -// Providing a separate declaration to make Clang's -Wmissing-prototypes happy +// Providing a separate declaration to make Clang's -Wmissing-prototypes happy. +// See comment for PYBIND11_MODULE below for why this is marked "maybe unused". #define PYBIND11_PLUGIN_IMPL(name) \ - extern "C" PYBIND11_EXPORT PyObject *PyInit_##name(); \ + extern "C" PYBIND11_MAYBE_UNUSED PYBIND11_EXPORT PyObject *PyInit_##name(); \ extern "C" PYBIND11_EXPORT PyObject *PyInit_##name() #else @@ -211,13 +212,14 @@ #define PYBIND11_STR_TYPE ::pybind11::bytes #define PYBIND11_BOOL_ATTR "__nonzero__" #define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_nonzero) -// Providing a separate PyInit decl to make Clang's -Wmissing-prototypes happy +// Providing a separate PyInit decl to make Clang's -Wmissing-prototypes happy. +// See comment for PYBIND11_MODULE below for why this is marked "maybe unused". #define PYBIND11_PLUGIN_IMPL(name) \ - static PyObject *pybind11_init_wrapper(); \ - extern "C" PYBIND11_EXPORT void init##name(); \ - extern "C" PYBIND11_EXPORT void init##name() { \ - (void)pybind11_init_wrapper(); \ - } \ + static PyObject *pybind11_init_wrapper(); \ + extern "C" PYBIND11_MAYBE_UNUSED PYBIND11_EXPORT void init##name(); \ + extern "C" PYBIND11_EXPORT void init##name() { \ + (void)pybind11_init_wrapper(); \ + } \ PyObject *pybind11_init_wrapper() #endif From b524008967daf913deccffaf4e06285e2c4f5923 Mon Sep 17 00:00:00 2001 From: Matthijs van der Burgh Date: Wed, 10 Jun 2020 13:30:41 +0200 Subject: [PATCH 086/768] Deepcopy documentation (#2242) * (docs) convert note to real note * (docs) Add information about (deep)copy --- docs/advanced/classes.rst | 50 +++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/docs/advanced/classes.rst b/docs/advanced/classes.rst index 20760b704..70393b55e 100644 --- a/docs/advanced/classes.rst +++ b/docs/advanced/classes.rst @@ -768,13 +768,17 @@ An instance can now be pickled as follows: p.setExtra(15) data = pickle.dumps(p, 2) -Note that only the cPickle module is supported on Python 2.7. The second -argument to ``dumps`` is also crucial: it selects the pickle protocol version -2, since the older version 1 is not supported. Newer versions are also fine—for -instance, specify ``-1`` to always use the latest available version. Beware: -failure to follow these instructions will cause important pybind11 memory -allocation routines to be skipped during unpickling, which will likely lead to -memory corruption and/or segmentation faults. + +.. note:: + Note that only the cPickle module is supported on Python 2.7. + + The second argument to ``dumps`` is also crucial: it selects the pickle + protocol version 2, since the older version 1 is not supported. Newer + versions are also fine—for instance, specify ``-1`` to always use the + latest available version. Beware: failure to follow these instructions + will cause important pybind11 memory allocation routines to be skipped + during unpickling, which will likely lead to memory corruption and/or + segmentation faults. .. seealso:: @@ -784,6 +788,38 @@ memory corruption and/or segmentation faults. .. [#f3] http://docs.python.org/3/library/pickle.html#pickling-class-instances +Deepcopy support +================ + +Python normally uses references in assignments. Sometimes a real copy is needed +to prevent changing all copies. The ``copy`` module [#f5]_ provides these +capabilities. + +On Python 3, a class with pickle support is automatically also (deep)copy +compatible. However, performance can be improved by adding custom +``__copy__`` and ``__deepcopy__`` methods. With Python 2.7, these custom methods +are mandatory for (deep)copy compatibility, because pybind11 only supports +cPickle. + +For simple classes (deep)copy can be enabled by using the copy constructor, +which should look as follows: + +.. code-block:: cpp + + py::class_(m, "Copyable") + .def("__copy__", [](const Copyable &self) { + return Copyable(self); + }) + .def("__deepcopy__", [](const Copyable &self, py::dict) { + return Copyable(self); + }, "memo"_a); + +.. note:: + + Dynamic attributes will not be copied in this example. + +.. [#f5] https://docs.python.org/3/library/copy.html + Multiple Inheritance ==================== From 63df87fa490d49244b76249854559ec8db22f119 Mon Sep 17 00:00:00 2001 From: Clemens Sielaff Date: Wed, 10 Jun 2020 04:35:10 -0700 Subject: [PATCH 087/768] Add lvalue ref-qualified cpp_function constructors (#2213) * added overload for l-value ref-qualified methods * Added test. Before, the code would have failed to build. --- include/pybind11/pybind11.h | 22 ++++++++++++++++++++-- tests/test_methods_and_attributes.cpp | 15 +++++++++++++++ tests/test_methods_and_attributes.py | 11 +++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index dee2423de..ac13616d2 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -72,20 +72,38 @@ public: (detail::function_signature_t *) nullptr, extra...); } - /// Construct a cpp_function from a class method (non-const) + /// Construct a cpp_function from a class method (non-const, no ref-qualifier) template cpp_function(Return (Class::*f)(Arg...), const Extra&... extra) { initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(args...); }, (Return (*) (Class *, Arg...)) nullptr, extra...); } - /// Construct a cpp_function from a class method (const) + /// Construct a cpp_function from a class method (non-const, lvalue ref-qualifier) + /// A copy of the overload for non-const functions without explicit ref-qualifier + /// but with an added `&`. + template + cpp_function(Return (Class::*f)(Arg...)&, const Extra&... extra) { + initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(args...); }, + (Return (*) (Class *, Arg...)) nullptr, extra...); + } + + /// Construct a cpp_function from a class method (const, no ref-qualifier) template cpp_function(Return (Class::*f)(Arg...) const, const Extra&... extra) { initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(args...); }, (Return (*)(const Class *, Arg ...)) nullptr, extra...); } + /// Construct a cpp_function from a class method (const, lvalue ref-qualifier) + /// A copy of the overload for const functions without explicit ref-qualifier + /// but with an added `&`. + template + cpp_function(Return (Class::*f)(Arg...) const&, const Extra&... extra) { + initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(args...); }, + (Return (*)(const Class *, Arg ...)) nullptr, extra...); + } + /// Return the function name object name() const { return attr("__name__"); } diff --git a/tests/test_methods_and_attributes.cpp b/tests/test_methods_and_attributes.cpp index c7b82f13d..133762094 100644 --- a/tests/test_methods_and_attributes.cpp +++ b/tests/test_methods_and_attributes.cpp @@ -207,6 +207,14 @@ public: double sum() const { return rw_value + ro_value; } }; +// Test explicit lvalue ref-qualification +struct RefQualified { + int value = 0; + + void refQualified(int other) & { value += other; } + int constRefQualified(int other) const & { return value + other; } +}; + TEST_SUBMODULE(methods_and_attributes, m) { // test_methods_and_attributes py::class_ emna(m, "ExampleMandA"); @@ -457,4 +465,11 @@ TEST_SUBMODULE(methods_and_attributes, m) { m.def("custom_caster_destroy_const", []() -> const DestructionTester * { return new DestructionTester(); }, py::return_value_policy::take_ownership); // Likewise (const doesn't inhibit destruction) m.def("destruction_tester_cstats", &ConstructorStats::get, py::return_value_policy::reference); + + // test_methods_and_attributes + py::class_(m, "RefQualified") + .def(py::init<>()) + .def_readonly("value", &RefQualified::value) + .def("refQualified", &RefQualified::refQualified) + .def("constRefQualified", &RefQualified::constRefQualified); } diff --git a/tests/test_methods_and_attributes.py b/tests/test_methods_and_attributes.py index f1c862be8..5a10fbfa4 100644 --- a/tests/test_methods_and_attributes.py +++ b/tests/test_methods_and_attributes.py @@ -510,3 +510,14 @@ def test_custom_caster_destruction(): # Make sure we still only have the original object (from ..._no_destroy()) alive: assert cstats.alive() == 1 + + +def test_ref_qualified(): + """Tests that explicit lvalue ref-qualified methods can be called just like their + non ref-qualified counterparts.""" + + r = m.RefQualified() + assert r.value == 0 + r.refQualified(17) + assert r.value == 17 + assert r.constRefQualified(23) == 40 From 22b2504080d37e035bbf3df88edb7abffb317ce5 Mon Sep 17 00:00:00 2001 From: Sergei Izmailov Date: Thu, 14 May 2020 15:34:48 +0300 Subject: [PATCH 088/768] Render full numpy numeric names (e.g. numpy.int32) --- include/pybind11/numpy.h | 6 +++--- tests/test_eigen.py | 34 +++++++++++++++++++--------------- tests/test_numpy_array.py | 18 +++++++++--------- tests/test_numpy_vectorize.py | 10 +++++----- 4 files changed, 36 insertions(+), 32 deletions(-) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index 01daf3ac1..f26d7aa67 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -1007,14 +1007,14 @@ struct npy_format_descriptor_name; template struct npy_format_descriptor_name::value>> { static constexpr auto name = _::value>( - _("bool"), _::value>("int", "uint") + _() + _("bool"), _::value>("numpy.int", "numpy.uint") + _() ); }; template struct npy_format_descriptor_name::value>> { static constexpr auto name = _::value || std::is_same::value>( - _("float") + _(), _("longdouble") + _("numpy.float") + _(), _("numpy.longdouble") ); }; @@ -1022,7 +1022,7 @@ template struct npy_format_descriptor_name::value>> { static constexpr auto name = _::value || std::is_same::value>( - _("complex") + _(), _("longcomplex") + _("numpy.complex") + _(), _("numpy.longcomplex") ); }; diff --git a/tests/test_eigen.py b/tests/test_eigen.py index 55d935173..d836398a0 100644 --- a/tests/test_eigen.py +++ b/tests/test_eigen.py @@ -79,15 +79,17 @@ def test_mutator_descriptors(): m.fixed_mutator_a(zc) with pytest.raises(TypeError) as excinfo: m.fixed_mutator_r(zc) - assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable, flags.c_contiguous]) -> None' + assert ('(arg0: numpy.ndarray[numpy.float32[5, 6],' + ' flags.writeable, flags.c_contiguous]) -> None' in str(excinfo.value)) with pytest.raises(TypeError) as excinfo: m.fixed_mutator_c(zr) - assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable, flags.f_contiguous]) -> None' + assert ('(arg0: numpy.ndarray[numpy.float32[5, 6],' + ' flags.writeable, flags.f_contiguous]) -> None' in str(excinfo.value)) with pytest.raises(TypeError) as excinfo: m.fixed_mutator_a(np.array([[1, 2], [3, 4]], dtype='float32')) - assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable]) -> None' + assert ('(arg0: numpy.ndarray[numpy.float32[5, 6], flags.writeable]) -> None' in str(excinfo.value)) zr.flags.writeable = False with pytest.raises(TypeError): @@ -179,7 +181,7 @@ def test_negative_stride_from_python(msg): m.double_threer(second_row) assert msg(excinfo.value) == """ double_threer(): incompatible function arguments. The following argument types are supported: - 1. (arg0: numpy.ndarray[float32[1, 3], flags.writeable]) -> None + 1. (arg0: numpy.ndarray[numpy.float32[1, 3], flags.writeable]) -> None Invoked with: """ + repr(np.array([ 5., 4., 3.], dtype='float32')) # noqa: E501 line too long @@ -187,7 +189,7 @@ def test_negative_stride_from_python(msg): m.double_threec(second_col) assert msg(excinfo.value) == """ double_threec(): incompatible function arguments. The following argument types are supported: - 1. (arg0: numpy.ndarray[float32[3, 1], flags.writeable]) -> None + 1. (arg0: numpy.ndarray[numpy.float32[3, 1], flags.writeable]) -> None Invoked with: """ + repr(np.array([ 7., 4., 1.], dtype='float32')) # noqa: E501 line too long @@ -607,17 +609,19 @@ def test_special_matrix_objects(): def test_dense_signature(doc): assert doc(m.double_col) == """ - double_col(arg0: numpy.ndarray[float32[m, 1]]) -> numpy.ndarray[float32[m, 1]] + double_col(arg0: numpy.ndarray[numpy.float32[m, 1]]) -> numpy.ndarray[numpy.float32[m, 1]] """ assert doc(m.double_row) == """ - double_row(arg0: numpy.ndarray[float32[1, n]]) -> numpy.ndarray[float32[1, n]] - """ - assert doc(m.double_complex) == """ - double_complex(arg0: numpy.ndarray[complex64[m, 1]]) -> numpy.ndarray[complex64[m, 1]] - """ - assert doc(m.double_mat_rm) == """ - double_mat_rm(arg0: numpy.ndarray[float32[m, n]]) -> numpy.ndarray[float32[m, n]] + double_row(arg0: numpy.ndarray[numpy.float32[1, n]]) -> numpy.ndarray[numpy.float32[1, n]] """ + assert doc(m.double_complex) == (""" + double_complex(arg0: numpy.ndarray[numpy.complex64[m, 1]])""" + """ -> numpy.ndarray[numpy.complex64[m, 1]] + """) + assert doc(m.double_mat_rm) == (""" + double_mat_rm(arg0: numpy.ndarray[numpy.float32[m, n]])""" + """ -> numpy.ndarray[numpy.float32[m, n]] + """) def test_named_arguments(): @@ -654,10 +658,10 @@ def test_sparse(): @pytest.requires_eigen_and_scipy def test_sparse_signature(doc): assert doc(m.sparse_copy_r) == """ - sparse_copy_r(arg0: scipy.sparse.csr_matrix[float32]) -> scipy.sparse.csr_matrix[float32] + sparse_copy_r(arg0: scipy.sparse.csr_matrix[numpy.float32]) -> scipy.sparse.csr_matrix[numpy.float32] """ # noqa: E501 line too long assert doc(m.sparse_copy_c) == """ - sparse_copy_c(arg0: scipy.sparse.csc_matrix[float32]) -> scipy.sparse.csc_matrix[float32] + sparse_copy_c(arg0: scipy.sparse.csc_matrix[numpy.float32]) -> scipy.sparse.csc_matrix[numpy.float32] """ # noqa: E501 line too long diff --git a/tests/test_numpy_array.py b/tests/test_numpy_array.py index d0a6324df..55571964d 100644 --- a/tests/test_numpy_array.py +++ b/tests/test_numpy_array.py @@ -286,13 +286,13 @@ def test_overload_resolution(msg): m.overloaded("not an array") assert msg(excinfo.value) == """ overloaded(): incompatible function arguments. The following argument types are supported: - 1. (arg0: numpy.ndarray[float64]) -> str - 2. (arg0: numpy.ndarray[float32]) -> str - 3. (arg0: numpy.ndarray[int32]) -> str - 4. (arg0: numpy.ndarray[uint16]) -> str - 5. (arg0: numpy.ndarray[int64]) -> str - 6. (arg0: numpy.ndarray[complex128]) -> str - 7. (arg0: numpy.ndarray[complex64]) -> str + 1. (arg0: numpy.ndarray[numpy.float64]) -> str + 2. (arg0: numpy.ndarray[numpy.float32]) -> str + 3. (arg0: numpy.ndarray[numpy.int32]) -> str + 4. (arg0: numpy.ndarray[numpy.uint16]) -> str + 5. (arg0: numpy.ndarray[numpy.int64]) -> str + 6. (arg0: numpy.ndarray[numpy.complex128]) -> str + 7. (arg0: numpy.ndarray[numpy.complex64]) -> str Invoked with: 'not an array' """ @@ -307,8 +307,8 @@ def test_overload_resolution(msg): assert m.overloaded3(np.array([1], dtype='intc')) == 'int' expected_exc = """ overloaded3(): incompatible function arguments. The following argument types are supported: - 1. (arg0: numpy.ndarray[int32]) -> str - 2. (arg0: numpy.ndarray[float64]) -> str + 1. (arg0: numpy.ndarray[numpy.int32]) -> str + 2. (arg0: numpy.ndarray[numpy.float64]) -> str Invoked with: """ diff --git a/tests/test_numpy_vectorize.py b/tests/test_numpy_vectorize.py index 0e9c88397..c078ee7cf 100644 --- a/tests/test_numpy_vectorize.py +++ b/tests/test_numpy_vectorize.py @@ -109,7 +109,7 @@ def test_type_selection(): def test_docs(doc): assert doc(m.vectorized_func) == """ - vectorized_func(arg0: numpy.ndarray[int32], arg1: numpy.ndarray[float32], arg2: numpy.ndarray[float64]) -> object + vectorized_func(arg0: numpy.ndarray[numpy.int32], arg1: numpy.ndarray[numpy.float32], arg2: numpy.ndarray[numpy.float64]) -> object """ # noqa: E501 line too long @@ -160,12 +160,12 @@ def test_passthrough_arguments(doc): assert doc(m.vec_passthrough) == ( "vec_passthrough(" + ", ".join([ "arg0: float", - "arg1: numpy.ndarray[float64]", - "arg2: numpy.ndarray[float64]", - "arg3: numpy.ndarray[int32]", + "arg1: numpy.ndarray[numpy.float64]", + "arg2: numpy.ndarray[numpy.float64]", + "arg3: numpy.ndarray[numpy.int32]", "arg4: int", "arg5: m.numpy_vectorize.NonPODClass", - "arg6: numpy.ndarray[float64]"]) + ") -> object") + "arg6: numpy.ndarray[numpy.float64]"]) + ") -> object") b = np.array([[10, 20, 30]], dtype='float64') c = np.array([100, 200]) # NOT a vectorized argument From 57070fb0a084e40ceab8a9f80b9e4436a48b9e53 Mon Sep 17 00:00:00 2001 From: Sergei Izmailov Date: Sat, 16 May 2020 17:28:29 +0300 Subject: [PATCH 089/768] Render py::iterator/py::iterable as Iterator/Iterable in docstrings --- include/pybind11/cast.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 2b382ddfd..5384ecafb 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1606,6 +1606,8 @@ template struct is_holder_type struct handle_type_name { static constexpr auto name = _(); }; template <> struct handle_type_name { static constexpr auto name = _(PYBIND11_BYTES_NAME); }; +template <> struct handle_type_name { static constexpr auto name = _("Iterable"); }; +template <> struct handle_type_name { static constexpr auto name = _("Iterator"); }; template <> struct handle_type_name { static constexpr auto name = _("*args"); }; template <> struct handle_type_name { static constexpr auto name = _("**kwargs"); }; From 90d99b56a00a00cf23568435ae5f44ea0c8c3bf1 Mon Sep 17 00:00:00 2001 From: Sergei Izmailov Date: Wed, 20 May 2020 12:42:07 +0300 Subject: [PATCH 090/768] Render pybind11::array as numpy.ndarray in docstrings --- include/pybind11/numpy.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index f26d7aa67..49a1e4f5e 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -40,6 +40,9 @@ NAMESPACE_BEGIN(PYBIND11_NAMESPACE) class array; // Forward declaration NAMESPACE_BEGIN(detail) + +template <> struct handle_type_name { static constexpr auto name = _("numpy.ndarray"); }; + template struct npy_format_descriptor; struct PyArrayDescr_Proxy { From 4f1531c454ada656884c6f69b56050ac9fd18b2a Mon Sep 17 00:00:00 2001 From: Sergei Izmailov Date: Fri, 15 May 2020 00:11:39 +0300 Subject: [PATCH 091/768] Render `py::int_` as `int` in docstrings --- include/pybind11/cast.h | 1 + tests/test_pytypes.cpp | 2 ++ tests/test_pytypes.py | 2 ++ 3 files changed, 5 insertions(+) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 5384ecafb..be4f66b06 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1606,6 +1606,7 @@ template struct is_holder_type struct handle_type_name { static constexpr auto name = _(); }; template <> struct handle_type_name { static constexpr auto name = _(PYBIND11_BYTES_NAME); }; +template <> struct handle_type_name { static constexpr auto name = _("int"); }; template <> struct handle_type_name { static constexpr auto name = _("Iterable"); }; template <> struct handle_type_name { static constexpr auto name = _("Iterator"); }; template <> struct handle_type_name { static constexpr auto name = _("*args"); }; diff --git a/tests/test_pytypes.cpp b/tests/test_pytypes.cpp index 244e1db0d..da9fcaea3 100644 --- a/tests/test_pytypes.cpp +++ b/tests/test_pytypes.cpp @@ -11,6 +11,8 @@ TEST_SUBMODULE(pytypes, m) { + // test_int + m.def("get_int", []{return py::int_(0);}); // test_list m.def("get_list", []() { py::list list; diff --git a/tests/test_pytypes.py b/tests/test_pytypes.py index 0e8d6c33a..89ec28583 100644 --- a/tests/test_pytypes.py +++ b/tests/test_pytypes.py @@ -5,6 +5,8 @@ import sys from pybind11_tests import pytypes as m from pybind11_tests import debug_enabled +def test_int(doc): + assert doc(m.get_int) == "get_int() -> int" def test_list(capture, doc): with capture: From ab323e04f3157cfe57c49d6f95fd232190d7032c Mon Sep 17 00:00:00 2001 From: Sergei Izmailov Date: Fri, 5 Jun 2020 21:29:16 +0300 Subject: [PATCH 092/768] Test py::iterable/py::iterator representation in docstrings --- tests/test_pytypes.cpp | 4 ++++ tests/test_pytypes.py | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/tests/test_pytypes.cpp b/tests/test_pytypes.cpp index da9fcaea3..e70ffae9e 100644 --- a/tests/test_pytypes.cpp +++ b/tests/test_pytypes.cpp @@ -13,6 +13,10 @@ TEST_SUBMODULE(pytypes, m) { // test_int m.def("get_int", []{return py::int_(0);}); + // test_iterator + m.def("get_iterator", []{return py::iterator();}); + // test_iterable + m.def("get_iterable", []{return py::iterable();}); // test_list m.def("get_list", []() { py::list list; diff --git a/tests/test_pytypes.py b/tests/test_pytypes.py index 89ec28583..d6223b9ba 100644 --- a/tests/test_pytypes.py +++ b/tests/test_pytypes.py @@ -5,9 +5,19 @@ import sys from pybind11_tests import pytypes as m from pybind11_tests import debug_enabled + def test_int(doc): assert doc(m.get_int) == "get_int() -> int" + +def test_iterator(doc): + assert doc(m.get_iterator) == "get_iterator() -> Iterator" + + +def test_iterable(doc): + assert doc(m.get_iterable) == "get_iterable() -> Iterable" + + def test_list(capture, doc): with capture: lst = m.get_list() From e107fc2a054fe3c71bbd8c4ed2539fdb80e9f1b5 Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Sun, 26 Apr 2020 14:56:10 +0000 Subject: [PATCH 093/768] Fix setuptools record of headers --- setup.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/setup.py b/setup.py index 473ea1ee0..668b56a5b 100644 --- a/setup.py +++ b/setup.py @@ -67,6 +67,13 @@ class BuildPy(build_py): self.mkpath(os.path.dirname(target)) self.copy_file(header, target, preserve_mode=False) + def get_outputs(self, include_bytecode=1): + outputs = build_py.get_outputs(self, include_bytecode=include_bytecode) + for header in package_data: + target = os.path.join(self.build_lib, 'pybind11', header) + outputs.append(target) + return outputs + setup( name='pybind11', From d96c34516d276f4c33d25df23d5934af1c5b2406 Mon Sep 17 00:00:00 2001 From: methylDragon Date: Tue, 16 Jun 2020 03:34:45 +0800 Subject: [PATCH 094/768] Fix docs typo --- include/pybind11/pybind11.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index ac13616d2..7a6e56302 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -2152,8 +2152,8 @@ template function get_overload(const T *this_ptr, const char *name) { PYBIND11_OVERLOAD_NAME( std::string, // Return type (ret_type) Animal, // Parent class (cname) - toString, // Name of function in C++ (name) - "__str__", // Name of method in Python (fn) + "__str__", // Name of method in Python (name) + toString, // Name of function in C++ (fn) ); } \endrst */ From 8c0cd94465fbc1dbc34217e5a614edc784f0913e Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Thu, 18 Jun 2020 12:14:59 +0200 Subject: [PATCH 095/768] ignore another type of visual studio project file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 979fd4431..244bbcaa7 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ cmake_install.cmake *.sdf *.opensdf *.vcxproj +*.vcxproj.user *.filters example.dir Win32 From 8e85fadff28988f036182cc9345dae124ce7cd17 Mon Sep 17 00:00:00 2001 From: Ashley Whetter Date: Sat, 27 Jun 2020 18:33:20 -0700 Subject: [PATCH 096/768] Render `py::none` as `None` in docstrings Closes #2270 --- include/pybind11/cast.h | 1 + tests/test_pytypes.cpp | 5 +++++ tests/test_pytypes.py | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index be4f66b06..28283da8f 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1609,6 +1609,7 @@ template <> struct handle_type_name { static constexpr auto name = _(PYBI template <> struct handle_type_name { static constexpr auto name = _("int"); }; template <> struct handle_type_name { static constexpr auto name = _("Iterable"); }; template <> struct handle_type_name { static constexpr auto name = _("Iterator"); }; +template <> struct handle_type_name { static constexpr auto name = _("None"); }; template <> struct handle_type_name { static constexpr auto name = _("*args"); }; template <> struct handle_type_name { static constexpr auto name = _("**kwargs"); }; diff --git a/tests/test_pytypes.cpp b/tests/test_pytypes.cpp index e70ffae9e..f0d86d872 100644 --- a/tests/test_pytypes.cpp +++ b/tests/test_pytypes.cpp @@ -32,6 +32,11 @@ TEST_SUBMODULE(pytypes, m) { for (auto item : list) py::print("list item {}: {}"_s.format(index++, item)); }); + // test_none + m.def("get_none", []{return py::none();}); + m.def("print_none", [](py::none none) { + py::print("none: {}"_s.format(none)); + }); // test_set m.def("get_set", []() { diff --git a/tests/test_pytypes.py b/tests/test_pytypes.py index d6223b9ba..79bee8775 100644 --- a/tests/test_pytypes.py +++ b/tests/test_pytypes.py @@ -37,6 +37,11 @@ def test_list(capture, doc): assert doc(m.print_list) == "print_list(arg0: list) -> None" +def test_none(capture, doc): + assert doc(m.get_none) == "get_none() -> None" + assert doc(m.print_none) == "print_none(arg0: None) -> None" + + def test_set(capture, doc): s = m.get_set() assert s == {"key1", "key2", "key3"} From a3daf87d45eb5a26c12ec44b7878f81e1dc8b8d5 Mon Sep 17 00:00:00 2001 From: fatvlady Date: Sat, 14 Mar 2020 15:15:12 +0200 Subject: [PATCH 097/768] Add failing optional test --- tests/test_stl.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ tests/test_stl.py | 10 ++++++++++ 2 files changed, 50 insertions(+) diff --git a/tests/test_stl.cpp b/tests/test_stl.cpp index 207c9fb2b..4c5ed853a 100644 --- a/tests/test_stl.cpp +++ b/tests/test_stl.cpp @@ -50,6 +50,17 @@ namespace std { } +template