From a80b22374ae9398962fe9746f84edc7e7982f9f7 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 27 Oct 2021 15:15:11 -0700 Subject: [PATCH 01/37] chore: get back to work after 2.8.1 [skip ci] --- include/pybind11/detail/common.h | 6 +++--- pybind11/_version.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 713de94b0..862451fd1 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -10,12 +10,12 @@ #pragma once #define PYBIND11_VERSION_MAJOR 2 -#define PYBIND11_VERSION_MINOR 8 -#define PYBIND11_VERSION_PATCH 1 +#define PYBIND11_VERSION_MINOR 9 +#define PYBIND11_VERSION_PATCH 0.dev1 // Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html // Additional convention: 0xD = dev -#define PYBIND11_VERSION_HEX 0x02080100 +#define PYBIND11_VERSION_HEX 0x020900D1 #define PYBIND11_NAMESPACE_BEGIN(name) namespace name { #define PYBIND11_NAMESPACE_END(name) } diff --git a/pybind11/_version.py b/pybind11/_version.py index 7cc100286..ce894a774 100644 --- a/pybind11/_version.py +++ b/pybind11/_version.py @@ -8,5 +8,5 @@ def _to_int(s): return s -__version__ = "2.8.1" +__version__ = "2.9.0.dev1" version_info = tuple(_to_int(s) for s in __version__.split(".")) From e7c9753f1d35061d137ac3ce561e94a7407e5583 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Fri, 29 Oct 2021 00:16:55 -0300 Subject: [PATCH 02/37] feat: allow kw-only args after a py::args (#3402) * Simply has_kw_only_args handling This simplifies tracking the number of kw-only args by instead tracking the number of positional arguments (which is really what we care about everywhere this is used). * Allow keyword-only arguments to follow py::args This removes the constraint that py::args has to be last (or second-last, with py::kwargs) and instead makes py::args imply py::kw_only for any remaining arguments, allowing you to bind a function that works the same way as a Python function such as: def f(a, *args, b): return a * b + sum(args) f(10, 1, 2, 3, b=20) # == 206 With this change, you can bind such a function using: m.def("f", [](int a, py::args args, int b) { /* ... */ }, "a"_a, "b"_a); Or, to be more explicit about the keyword-only arguments: m.def("g", [](int a, py::args args, int b) { /* ... */ }, "a"_a, py::kw_only{}, "b"_a); (The only difference between the two is that the latter will fail at binding time if the `kw_only{}` doesn't match the `py::args` position). This doesn't affect backwards compatibility at all because, currently, you can't have a py::args anywhere except the end/2nd-last. * Take args/kwargs by const lvalue ref Co-authored-by: Henry Schreiner Co-authored-by: Henry Schreiner --- docs/advanced/functions.rst | 16 +++++- include/pybind11/attr.h | 28 +++++----- include/pybind11/cast.h | 20 ++++--- include/pybind11/pybind11.h | 57 +++++++++++++------ tests/test_kwargs_and_defaults.cpp | 17 ++++++ tests/test_kwargs_and_defaults.py | 90 +++++++++++++++++++++++++++++- 6 files changed, 186 insertions(+), 42 deletions(-) diff --git a/docs/advanced/functions.rst b/docs/advanced/functions.rst index abd1084ab..ea9f35223 100644 --- a/docs/advanced/functions.rst +++ b/docs/advanced/functions.rst @@ -306,8 +306,9 @@ The class ``py::args`` derives from ``py::tuple`` and ``py::kwargs`` derives from ``py::dict``. You may also use just one or the other, and may combine these with other -arguments as long as the ``py::args`` and ``py::kwargs`` arguments are the last -arguments accepted by the function. +arguments. Note, however, that ``py::kwargs`` must always be the last argument +of the function, and ``py::args`` implies that any further arguments are +keyword-only (see :ref:`keyword_only_arguments`). Please refer to the other examples for details on how to iterate over these, and on how to cast their entries into C++ objects. A demonstration is also @@ -366,6 +367,8 @@ like so: py::class_("MyClass") .def("myFunction", py::arg("arg") = static_cast(nullptr)); +.. _keyword_only_arguments: + Keyword-only arguments ====================== @@ -397,6 +400,15 @@ feature does *not* require Python 3 to work. .. versionadded:: 2.6 +As of pybind11 2.9, a ``py::args`` argument implies that any following arguments +are keyword-only, as if ``py::kw_only()`` had been specified in the same +relative location of the argument list as the ``py::args`` argument. The +``py::kw_only()`` may be included to be explicit about this, but is not +required. (Prior to 2.9 ``py::args`` may only occur at the end of the argument +list, or immediately before a ``py::kwargs`` argument at the end). + +.. versionadded:: 2.9 + Positional-only arguments ========================= diff --git a/include/pybind11/attr.h b/include/pybind11/attr.h index 0dedbc08d..b95c84904 100644 --- a/include/pybind11/attr.h +++ b/include/pybind11/attr.h @@ -174,7 +174,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), prepend(false) { } + has_kwargs(false), prepend(false) { } /// Function name char *name = nullptr; /* why no C++ strings? They generate heavier code.. */ @@ -221,17 +221,15 @@ struct function_record { /// True if the function has a '**kwargs' argument bool has_kwargs : 1; - /// True once a 'py::kw_only' is encountered (any following args are keyword-only) - bool has_kw_only_args : 1; - /// True if this function is to be inserted at the beginning of the overload resolution chain bool prepend : 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_kw_only = 0; + /// Number of leading positional arguments, which are terminated by a py::args or py::kwargs + /// argument or by a py::kw_only annotation. + std::uint16_t nargs_pos = 0; /// Number of leading arguments (counted in `nargs`) that are positional-only std::uint16_t nargs_pos_only = 0; @@ -411,10 +409,9 @@ 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_kw_only_arg(const arg &a, function_record *r) { - if (!a.name || a.name[0] == '\0') - pybind11_fail("arg(): cannot specify an unnamed argument after an kw_only() annotation"); - ++r->nargs_kw_only; +inline void check_kw_only_arg(const arg &a, function_record *r) { + if (r->args.size() > r->nargs_pos && (!a.name || a.name[0] == '\0')) + pybind11_fail("arg(): cannot specify an unnamed argument after a kw_only() annotation or args() argument"); } /// Process a keyword argument attribute (*without* a default value) @@ -424,7 +421,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_kw_only_arg(a, r); + check_kw_only_arg(a, r); } }; @@ -457,14 +454,16 @@ 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_kw_only_arg(a, r); + check_kw_only_arg(a, r); } }; /// Process a keyword-only-arguments-follow pseudo argument template <> struct process_attribute : process_attribute_default { static void init(const kw_only &, function_record *r) { - r->has_kw_only_args = true; + if (r->has_args && r->nargs_pos != static_cast(r->args.size())) + pybind11_fail("Mismatched args() and kw_only(): they must occur at the same relative argument location (or omit kw_only() entirely)"); + r->nargs_pos = static_cast(r->args.size()); } }; @@ -472,6 +471,9 @@ template <> struct process_attribute : process_attribute_default struct process_attribute : process_attribute_default { static void init(const pos_only &, function_record *r) { r->nargs_pos_only = static_cast(r->args.size()); + if (r->nargs_pos_only > r->nargs_pos) + pybind11_fail("pos_only(): cannot follow a py::args() argument"); + // It also can't follow a kw_only, but a static_assert in pybind11.h checks that } }; diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 20fbb3258..4b39827c2 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1130,6 +1130,9 @@ constexpr arg operator"" _a(const char *name, size_t) { return arg(name); } PYBIND11_NAMESPACE_BEGIN(detail) +template using is_kw_only = std::is_same, kw_only>; +template using is_pos_only = std::is_same, pos_only>; + // forward declaration (definition in attr.h) struct function_record; @@ -1165,17 +1168,18 @@ class argument_loader { template using argument_is_args = std::is_same, args>; template using argument_is_kwargs = std::is_same, kwargs>; - // Get args/kwargs argument positions relative to the end of the argument list: - static constexpr auto args_pos = constexpr_first() - (int) sizeof...(Args), - kwargs_pos = constexpr_first() - (int) sizeof...(Args); + // Get kwargs argument position, or -1 if not present: + static constexpr auto kwargs_pos = constexpr_last(); - static constexpr bool args_kwargs_are_last = kwargs_pos >= - 1 && args_pos >= kwargs_pos - 1; - - static_assert(args_kwargs_are_last, "py::args/py::kwargs are only permitted as the last argument(s) of a function"); + static_assert(kwargs_pos == -1 || kwargs_pos == (int) sizeof...(Args) - 1, "py::kwargs is only permitted as the last argument of a function"); public: - static constexpr bool has_kwargs = kwargs_pos < 0; - static constexpr bool has_args = args_pos < 0; + static constexpr bool has_kwargs = kwargs_pos != -1; + + // py::args argument position; -1 if not present. + static constexpr int args_pos = constexpr_last(); + + static_assert(args_pos == -1 || args_pos == constexpr_first(), "py::args cannot be specified more than once"); static constexpr auto arg_names = concat(type_descr(make_caster::name)...); diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index bfc1c368c..124ea37e5 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -203,7 +203,7 @@ protected: conditional_t::value, void_type, Return> >; - static_assert(expected_num_args(sizeof...(Args), cast_in::has_args, cast_in::has_kwargs), + static_assert(expected_num_args(sizeof...(Args), cast_in::args_pos >= 0, cast_in::has_kwargs), "The number of argument annotations does not match the number of function arguments"); /* Dispatch code which converts function arguments and performs the actual function call */ @@ -238,17 +238,27 @@ protected: return result; }; + rec->nargs_pos = cast_in::args_pos >= 0 + ? static_cast(cast_in::args_pos) + : sizeof...(Args) - cast_in::has_kwargs; // Will get reduced more if we have a kw_only + rec->has_args = cast_in::args_pos >= 0; + rec->has_kwargs = cast_in::has_kwargs; + /* Process any user-provided function attributes */ process_attributes::init(extra..., rec); { constexpr bool has_kw_only_args = any_of...>::value, has_pos_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::kw_only requires the use of argument annotations"); static_assert(has_arg_annotations || !has_pos_only_args, "py::pos_only requires the use of argument annotations (for docstrings and aligning the annotations to the argument)"); - static_assert(!(has_args && has_kw_only_args), "py::kw_only cannot be combined with a py::args argument"); + + static_assert(constexpr_sum(is_kw_only::value...) <= 1, "py::kw_only may be specified only once"); + static_assert(constexpr_sum(is_pos_only::value...) <= 1, "py::pos_only may be specified only once"); + constexpr auto kw_only_pos = constexpr_first(); + constexpr auto pos_only_pos = constexpr_first(); + static_assert(!(has_kw_only_args && has_pos_only_args) || pos_only_pos < kw_only_pos, "py::pos_only must come before py::kw_only"); } /* Generate a readable signature describing the function's arguments and return value types */ @@ -259,9 +269,6 @@ protected: // Pass on the ownership over the `unique_rec` to `initialize_generic`. `rec` stays valid. initialize_generic(std::move(unique_rec), signature.text, types.data(), sizeof...(Args)); - if (cast_in::has_args) rec->has_args = true; - if (cast_in::has_kwargs) rec->has_kwargs = true; - /* Stash some additional information used by an important optimization in 'functional.h' */ using FunctionType = Return (*)(Args...); constexpr bool is_function_ptr = @@ -340,16 +347,18 @@ protected: /* Generate a proper function signature */ std::string signature; size_t type_index = 0, arg_index = 0; + bool is_starred = false; for (auto *pc = text; *pc != '\0'; ++pc) { const auto c = *pc; if (c == '{') { // Write arg name for everything except *args and **kwargs. - if (*(pc + 1) == '*') + is_starred = *(pc + 1) == '*'; + if (is_starred) continue; // Separator for keyword-only arguments, placed before the kw - // arguments start - if (rec->nargs_kw_only > 0 && arg_index + rec->nargs_kw_only == args) + // arguments start (unless we are already putting an *args) + if (!rec->has_args && arg_index == rec->nargs_pos) signature += "*, "; if (arg_index < rec->args.size() && rec->args[arg_index].name) { signature += rec->args[arg_index].name; @@ -361,7 +370,7 @@ protected: signature += ": "; } else if (c == '}') { // Write default value if available. - if (arg_index < rec->args.size() && rec->args[arg_index].descr) { + if (!is_starred && arg_index < rec->args.size() && rec->args[arg_index].descr) { signature += " = "; signature += rec->args[arg_index].descr; } @@ -369,7 +378,8 @@ protected: // argument, rather than before like * if (rec->nargs_pos_only > 0 && (arg_index + 1) == rec->nargs_pos_only) signature += ", /"; - arg_index++; + if (!is_starred) + arg_index++; } else if (c == '%') { const std::type_info *t = types[type_index++]; if (!t) @@ -395,7 +405,7 @@ protected: } } - if (arg_index != args || types[type_index] != nullptr) + if (arg_index != args - rec->has_args - rec->has_kwargs || types[type_index] != nullptr) pybind11_fail("Internal error while parsing type signature (2)"); #if PY_MAJOR_VERSION < 3 @@ -631,7 +641,7 @@ protected: named positional arguments weren't *also* specified via kwarg. 2. If we weren't given enough, try to make up the omitted ones by checking whether they were provided by a kwarg matching the `py::arg("name")` name. If - so, use it (and remove it from kwargs; if not, see if the function binding + so, use it (and remove it from kwargs); if not, see if the function binding provided a default that we can use. 3. Ensure that either all keyword arguments were "consumed", or that the function takes a kwargs argument to accept unconsumed kwargs. @@ -649,7 +659,7 @@ protected: 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_kw_only; + size_t pos_args = func.nargs_pos; if (!func.has_args && n_args_in > pos_args) continue; // Too many positional arguments for this overload @@ -695,6 +705,10 @@ protected: if (bad_arg) continue; // Maybe it was meant for another overload (issue #688) + // Keep track of how many position args we copied out in case we need to come back + // to copy the rest into a py::args argument. + size_t positional_args_copied = args_copied; + // We'll need to copy this if we steal some kwargs for defaults dict kwargs = reinterpret_borrow(kwargs_in); @@ -747,6 +761,10 @@ protected: } if (value) { + // If we're at the py::args index then first insert a stub for it to be replaced later + if (func.has_args && call.args.size() == func.nargs_pos) + call.args.push_back(none()); + call.args.push_back(value); call.args_convert.push_back(arg_rec.convert); } @@ -769,16 +787,19 @@ protected: // We didn't copy out any position arguments from the args_in tuple, so we // can reuse it directly without copying: extra_args = reinterpret_borrow(args_in); - } else if (args_copied >= n_args_in) { + } else if (positional_args_copied >= n_args_in) { extra_args = tuple(0); } else { - size_t args_size = n_args_in - args_copied; + size_t args_size = n_args_in - positional_args_copied; extra_args = tuple(args_size); for (size_t i = 0; i < args_size; ++i) { - extra_args[i] = PyTuple_GET_ITEM(args_in, args_copied + i); + extra_args[i] = PyTuple_GET_ITEM(args_in, positional_args_copied + i); } } - call.args.push_back(extra_args); + if (call.args.size() <= func.nargs_pos) + call.args.push_back(extra_args); + else + call.args[func.nargs_pos] = extra_args; call.args_convert.push_back(false); call.args_ref = std::move(extra_args); } diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp index 63332d32e..312596dab 100644 --- a/tests/test_kwargs_and_defaults.cpp +++ b/tests/test_kwargs_and_defaults.cpp @@ -56,6 +56,23 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { m.def("mixed_plus_args_kwargs_defaults", mixed_plus_both, py::arg("i") = 1, py::arg("j") = 3.14159); + m.def("args_kwonly", + [](int i, double j, const py::args &args, int z) { return py::make_tuple(i, j, args, z); }, + "i"_a, "j"_a, "z"_a); + m.def("args_kwonly_kwargs", + [](int i, double j, const py::args &args, int z, const py::kwargs &kwargs) { + return py::make_tuple(i, j, args, z, kwargs); }, + "i"_a, "j"_a, py::kw_only{}, "z"_a); + m.def("args_kwonly_kwargs_defaults", + [](int i, double j, const py::args &args, int z, const py::kwargs &kwargs) { + return py::make_tuple(i, j, args, z, kwargs); }, + "i"_a = 1, "j"_a = 3.14159, "z"_a = 42); + m.def("args_kwonly_full_monty", + [](int h, int i, double j, const py::args &args, int z, const py::kwargs &kwargs) { + return py::make_tuple(h, i, j, args, z, kwargs); }, + py::arg() = 1, py::arg() = 2, py::pos_only{}, "j"_a = 3.14159, "z"_a = 42); + + // test_args_refcount // PyPy needs a garbage collection to get the reference count values to match CPython's behaviour #ifdef PYPY_VERSION diff --git a/tests/test_kwargs_and_defaults.py b/tests/test_kwargs_and_defaults.py index ddc387eeb..68903bde1 100644 --- a/tests/test_kwargs_and_defaults.py +++ b/tests/test_kwargs_and_defaults.py @@ -141,6 +141,53 @@ def test_mixed_args_and_kwargs(msg): """ # noqa: E501 line too long ) + # Arguments after a py::args are automatically keyword-only (pybind 2.9+) + assert m.args_kwonly(2, 2.5, z=22) == (2, 2.5, (), 22) + assert m.args_kwonly(2, 2.5, "a", "b", "c", z=22) == (2, 2.5, ("a", "b", "c"), 22) + assert m.args_kwonly(z=22, i=4, j=16) == (4, 16, (), 22) + + with pytest.raises(TypeError) as excinfo: + assert m.args_kwonly(2, 2.5, 22) # missing z= keyword + assert ( + msg(excinfo.value) + == """ + args_kwonly(): incompatible function arguments. The following argument types are supported: + 1. (i: int, j: float, *args, z: int) -> tuple + + Invoked with: 2, 2.5, 22 + """ + ) + + assert m.args_kwonly_kwargs(i=1, k=4, j=10, z=-1, y=9) == ( + 1, + 10, + (), + -1, + {"k": 4, "y": 9}, + ) + assert m.args_kwonly_kwargs(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, z=11, y=12) == ( + 1, + 2, + (3, 4, 5, 6, 7, 8, 9, 10), + 11, + {"y": 12}, + ) + assert ( + m.args_kwonly_kwargs.__doc__ + == "args_kwonly_kwargs(i: int, j: float, *args, z: int, **kwargs) -> tuple\n" + ) + + assert ( + m.args_kwonly_kwargs_defaults.__doc__ + == "args_kwonly_kwargs_defaults(i: int = 1, j: float = 3.14159, *args, z: int = 42, **kwargs) -> tuple\n" # noqa: E501 line too long + ) + assert m.args_kwonly_kwargs_defaults() == (1, 3.14159, (), 42, {}) + assert m.args_kwonly_kwargs_defaults(2) == (2, 3.14159, (), 42, {}) + assert m.args_kwonly_kwargs_defaults(z=-99) == (1, 3.14159, (), -99, {}) + assert m.args_kwonly_kwargs_defaults(5, 6, 7, 8) == (5, 6, (7, 8), 42, {}) + assert m.args_kwonly_kwargs_defaults(5, 6, 7, m=8) == (5, 6, (7,), 42, {"m": 8}) + assert m.args_kwonly_kwargs_defaults(5, 6, 7, m=8, z=9) == (5, 6, (7,), 9, {"m": 8}) + def test_keyword_only_args(msg): assert m.kw_only_all(i=1, j=2) == (1, 2) @@ -178,7 +225,7 @@ def test_keyword_only_args(msg): assert ( msg(excinfo.value) == """ - arg(): cannot specify an unnamed argument after an kw_only() annotation + arg(): cannot specify an unnamed argument after a kw_only() annotation or args() argument """ ) @@ -222,6 +269,47 @@ def test_positional_only_args(msg): m.pos_only_def_mix(1, j=4) assert "incompatible function arguments" in str(excinfo.value) + # Mix it with args and kwargs: + assert ( + m.args_kwonly_full_monty.__doc__ + == "args_kwonly_full_monty(arg0: int = 1, arg1: int = 2, /, j: float = 3.14159, *args, z: int = 42, **kwargs) -> tuple\n" # noqa: E501 line too long + ) + assert m.args_kwonly_full_monty() == (1, 2, 3.14159, (), 42, {}) + assert m.args_kwonly_full_monty(8) == (8, 2, 3.14159, (), 42, {}) + assert m.args_kwonly_full_monty(8, 9) == (8, 9, 3.14159, (), 42, {}) + assert m.args_kwonly_full_monty(8, 9, 10) == (8, 9, 10.0, (), 42, {}) + assert m.args_kwonly_full_monty(3, 4, 5, 6, 7, m=8, z=9) == ( + 3, + 4, + 5.0, + ( + 6, + 7, + ), + 9, + {"m": 8}, + ) + assert m.args_kwonly_full_monty(3, 4, 5, 6, 7, m=8, z=9) == ( + 3, + 4, + 5.0, + ( + 6, + 7, + ), + 9, + {"m": 8}, + ) + assert m.args_kwonly_full_monty(5, j=7, m=8, z=9) == (5, 2, 7.0, (), 9, {"m": 8}) + assert m.args_kwonly_full_monty(i=5, j=7, m=8, z=9) == ( + 1, + 2, + 7.0, + (), + 9, + {"i": 5, "m": 8}, + ) + def test_signatures(): assert "kw_only_all(*, i: int, j: int) -> tuple\n" == m.kw_only_all.__doc__ From dd2d12721c924486e6f5313cb815441a7d3dd256 Mon Sep 17 00:00:00 2001 From: "Chad B. Hovey" <1473854+hovey@users.noreply.github.com> Date: Mon, 1 Nov 2021 10:01:27 -0600 Subject: [PATCH 03/37] Correct "which" versus "that" error. (#3430) --- docs/basics.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/basics.rst b/docs/basics.rst index 0b1d85cfd..e0479b298 100644 --- a/docs/basics.rst +++ b/docs/basics.rst @@ -109,7 +109,7 @@ a file named :file:`example.cpp` with the following contents: PYBIND11_MODULE(example, m) { m.doc() = "pybind11 example plugin"; // optional module docstring - m.def("add", &add, "A function which adds two numbers"); + m.def("add", &add, "A function that adds two numbers"); } .. [#f1] In practice, implementation and binding code will generally be located From 6de30d317277c26a72ed1929e09f225b74f23b7a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 17:22:12 -0400 Subject: [PATCH 04/37] [pre-commit.ci] pre-commit autoupdate (#3432) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/psf/black: 21.9b0 → 21.10b0](https://github.com/psf/black/compare/21.9b0...21.10b0) * Update blacken-docs too Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Aaron Gokaslan --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b3e517905..706194646 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -44,7 +44,7 @@ repos: # Black, the code formatter, natively supports pre-commit - repo: https://github.com/psf/black - rev: 21.9b0 # Keep in sync with blacken-docs + rev: 21.10b0 # Keep in sync with blacken-docs hooks: - id: black @@ -53,7 +53,7 @@ repos: hooks: - id: blacken-docs additional_dependencies: - - black==21.9b0 # keep in sync with black hook + - black==21.10b0 # keep in sync with black hook # Changes tabs to spaces - repo: https://github.com/Lucas-C/pre-commit-hooks From a61e354e4279d296df8ab712a66ef4564d4ec04c Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 5 Nov 2021 22:48:27 -0400 Subject: [PATCH 05/37] docs: touch up manual release suggestion (#3422) --- docs/release.rst | 9 ++++----- noxfile.py | 2 ++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/release.rst b/docs/release.rst index b5de60f4e..e761cdf7a 100644 --- a/docs/release.rst +++ b/docs/release.rst @@ -22,6 +22,9 @@ the version just below. To release a new version of pybind11: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +If you don't have nox, you should either use ``pipx run nox`` instead, or use +``pipx install nox`` or ``brew install nox`` (Unix). + - Update the version number - Update ``PYBIND11_VERSION_MAJOR`` etc. in ``include/pybind11/detail/common.h``. PATCH should be a simple integer. @@ -51,14 +54,12 @@ To release a new version of pybind11: notifications to users watching releases, and also uploads PyPI packages). (Note: if you do not use an existing tag, this creates a new lightweight tag for you, so you could skip the above step.) - - GUI method: Under `releases `_ click "Draft a new release" on the far right, fill in the tag name (if you didn't tag above, it will be made here), fill in a release name like "Version X.Y.Z", and copy-and-paste the markdown-formatted (!) changelog into the description (usually ``cat docs/changelog.rst | pandoc -f rst -t gfm``). Check "pre-release" if this is a beta/RC. - - CLI method: with ``gh`` installed, run ``gh release create vX.Y.Z -t "Version X.Y.Z"`` If this is a pre-release, add ``-p``. @@ -90,9 +91,7 @@ If you need to manually upload releases, you can download the releases from the .. code-block:: bash - python3 -m pip install build - python3 -m build - PYBIND11_SDIST_GLOBAL=1 python3 -m build + nox -s build twine upload dist/* This makes SDists and wheels, and the final line uploads them. diff --git a/noxfile.py b/noxfile.py index 757a53843..53d87dbcb 100644 --- a/noxfile.py +++ b/noxfile.py @@ -85,5 +85,7 @@ def build(session: nox.Session) -> None: """ session.install("build") + session.log("Building normal files") session.run("python", "-m", "build") + session.log("Building pybind11-global files (PYBIND11_GLOBAL_SDIST=1)") session.run("python", "-m", "build", env={"PYBIND11_GLOBAL_SDIST": "1"}) From 01f938e79938fd5b9bb6df2daeff95a625f6211f Mon Sep 17 00:00:00 2001 From: Boris Rasin Date: Mon, 8 Nov 2021 01:35:25 +0200 Subject: [PATCH 06/37] fix: add missing std::forward calls (#3443) * fix: add missing std::forward calls Two of the four cpp_function overloads are missing std::forward calls, which seems like a simple oversight. * add test for https://github.com/pybind/pybind11/pull/3443 * add py tests * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix test Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- include/pybind11/pybind11.h | 4 ++-- tests/test_methods_and_attributes.cpp | 15 +++++++++++++++ tests/test_methods_and_attributes.py | 8 ++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 124ea37e5..b8b7c7a02 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -115,7 +115,7 @@ public: template // NOLINTNEXTLINE(google-explicit-constructor) cpp_function(Return (Class::*f)(Arg...)&, const Extra&... extra) { - initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(args...); }, + initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(std::forward(args)...); }, (Return (*) (Class *, Arg...)) nullptr, extra...); } @@ -133,7 +133,7 @@ public: template // NOLINTNEXTLINE(google-explicit-constructor) cpp_function(Return (Class::*f)(Arg...) const&, const Extra&... extra) { - initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(args...); }, + initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(std::forward(args)...); }, (Return (*)(const Class *, Arg ...)) nullptr, extra...); } diff --git a/tests/test_methods_and_attributes.cpp b/tests/test_methods_and_attributes.cpp index 2d303a44e..9e55452de 100644 --- a/tests/test_methods_and_attributes.cpp +++ b/tests/test_methods_and_attributes.cpp @@ -159,6 +159,14 @@ struct RefQualified { int constRefQualified(int other) const & { return value + other; } }; +// Test rvalue ref param +struct RValueRefParam { + std::size_t func1(std::string&& s) { return s.size(); } + std::size_t func2(std::string&& s) const { return s.size(); } + std::size_t func3(std::string&& s) & { return s.size(); } + std::size_t func4(std::string&& s) const & { return s.size(); } +}; + TEST_SUBMODULE(methods_and_attributes, m) { // test_methods_and_attributes py::class_ emna(m, "ExampleMandA"); @@ -409,4 +417,11 @@ TEST_SUBMODULE(methods_and_attributes, m) { .def_readonly("value", &RefQualified::value) .def("refQualified", &RefQualified::refQualified) .def("constRefQualified", &RefQualified::constRefQualified); + + py::class_(m, "RValueRefParam") + .def(py::init<>()) + .def("func1", &RValueRefParam::func1) + .def("func2", &RValueRefParam::func2) + .def("func3", &RValueRefParam::func3) + .def("func4", &RValueRefParam::func4); } diff --git a/tests/test_methods_and_attributes.py b/tests/test_methods_and_attributes.py index 866b3cea1..fa026f9ed 100644 --- a/tests/test_methods_and_attributes.py +++ b/tests/test_methods_and_attributes.py @@ -515,3 +515,11 @@ def test_overload_ordering(): assert "2. (arg0: {}) -> int".format(uni_name) in str(err.value) assert "3. (arg0: {}) -> int".format(uni_name) in str(err.value) assert "4. (arg0: int) -> int" in str(err.value) + + +def test_rvalue_ref_param(): + r = m.RValueRefParam() + assert r.func1("123") == 3 + assert r.func2("1234") == 4 + assert r.func3("12345") == 5 + assert r.func4("123456") == 6 From b322018e1571b42513de77d9ad9fde1d030c8cc6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 8 Nov 2021 15:56:20 -0500 Subject: [PATCH 07/37] [pre-commit.ci] pre-commit autoupdate (#3449) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/isort: 5.9.3 → 5.10.0](https://github.com/PyCQA/isort/compare/5.9.3...5.10.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 706194646..6f0bb39b1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,7 +38,7 @@ repos: - id: pyupgrade - repo: https://github.com/PyCQA/isort - rev: 5.9.3 + rev: 5.10.0 hooks: - id: isort From b11ff912a6b68edcd67770308ba4703e3a740e7b Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Mon, 8 Nov 2021 22:27:32 +0100 Subject: [PATCH 08/37] fix(setup =_helpers): don't add -g0 CFLAGS sets -g (#3436) On Unix, setuptools prepends $CFLAGS and $CPPFLAGS to the compiler flags (they always come before extra_compile_args and anything else; see distutils.sysconfig.customize_compiler). In practice, the environment variables are useful e.g. to quickly generate a debug build (e.g. by setting CFLAGS=-g), but Pybind11Extension currently unconditionally overwrites this with -g0. Instead, check the environment variables and only insert -g0 if not overridden by them. --- pybind11/setup_helpers.py | 8 +++++++- tests/extra_setuptools/test_setuphelper.py | 14 +++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/pybind11/setup_helpers.py b/pybind11/setup_helpers.py index 4ff1a0cb3..d6d84f672 100644 --- a/pybind11/setup_helpers.py +++ b/pybind11/setup_helpers.py @@ -42,6 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import contextlib import os import platform +import shlex import shutil import sys import sysconfig @@ -143,7 +144,12 @@ class Pybind11Extension(_Extension): if WIN: cflags += ["/EHsc", "/bigobj"] else: - cflags += ["-fvisibility=hidden", "-g0"] + cflags += ["-fvisibility=hidden"] + env_cflags = os.environ.get("CFLAGS", "") + env_cppflags = os.environ.get("CPPFLAGS", "") + c_cpp_flags = shlex.split(env_cflags) + shlex.split(env_cppflags) + if not any(opt.startswith("-g") for opt in c_cpp_flags): + cflags += ["-g0"] if MACOS: cflags += ["-stdlib=libc++"] ldflags += ["-stdlib=libc++"] diff --git a/tests/extra_setuptools/test_setuphelper.py b/tests/extra_setuptools/test_setuphelper.py index c24f50af8..788f368b1 100644 --- a/tests/extra_setuptools/test_setuphelper.py +++ b/tests/extra_setuptools/test_setuphelper.py @@ -8,6 +8,7 @@ import pytest DIR = os.path.abspath(os.path.dirname(__file__)) MAIN_DIR = os.path.dirname(os.path.dirname(DIR)) +WIN = sys.platform.startswith("win32") or sys.platform.startswith("cygwin") @pytest.mark.parametrize("parallel", [False, True]) @@ -71,13 +72,20 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std): encoding="ascii", ) - subprocess.check_call( + out = subprocess.check_output( [sys.executable, "setup.py", "build_ext", "--inplace"], - stdout=sys.stdout, - stderr=sys.stderr, ) + if not WIN: + assert b"-g0" in out + out = subprocess.check_output( + [sys.executable, "setup.py", "build_ext", "--inplace", "--force"], + env=dict(os.environ, CFLAGS="-g"), + ) + if not WIN: + assert b"-g0" not in out # Debug helper printout, normally hidden + print(out) for item in tmpdir.listdir(): print(item.basename) From aebd21b53c6be5a817a50491327371393aa9d8de Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Wed, 10 Nov 2021 12:13:10 -0500 Subject: [PATCH 09/37] docs: rework CI a bit, more modern skipping (#3424) * docs: rework CI a bit, more modern skipping * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 9 +++------ docs/Doxyfile | 3 +-- docs/requirements.txt | 13 +++++-------- include/pybind11/pytypes.h | 8 ++++---- noxfile.py | 10 ++++++---- 5 files changed, 19 insertions(+), 24 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3694f1636..2888c420b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -704,14 +704,11 @@ jobs: - name: Install Doxygen run: sudo apt-get install -y doxygen librsvg2-bin # Changed to rsvg-convert in 20.04 - - name: Install docs & setup requirements - run: python3 -m pip install -r docs/requirements.txt - - name: Build docs - run: python3 -m sphinx -W -b html docs docs/.build + run: pipx run nox -s docs - name: Make SDist - run: python3 setup.py sdist + run: pipx run nox -s build -- --sdist - run: git status --ignored @@ -723,7 +720,7 @@ jobs: - name: Compare Dists (headers only) working-directory: include run: | - python3 -m pip install --user -U ../dist/* + python3 -m pip install --user -U ../dist/*.tar.gz installed=$(python3 -c "import pybind11; print(pybind11.get_include() + '/pybind11')") diff -rq $installed ./pybind11 diff --git a/docs/Doxyfile b/docs/Doxyfile index c8562952e..62c267556 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -18,6 +18,5 @@ ALIASES += "endrst=\endverbatim" QUIET = YES WARNINGS = YES WARN_IF_UNDOCUMENTED = NO -PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS \ - PY_MAJOR_VERSION=3 \ +PREDEFINED = PY_MAJOR_VERSION=3 \ PYBIND11_NOINLINE diff --git a/docs/requirements.txt b/docs/requirements.txt index 8f293b5d3..b2801b1f0 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,8 +1,5 @@ -breathe==4.26.1 -# docutils 0.17 breaks HTML tags & RTD theme -# https://github.com/sphinx-doc/sphinx/issues/9001 -docutils==0.16 -sphinx==3.3.1 -sphinx_rtd_theme==0.5.0 -sphinxcontrib-moderncmakedomain==3.17 -sphinxcontrib-svg2pdfconverter==1.1.0 +breathe==4.31.0 +sphinx==3.5.4 +sphinx_rtd_theme==1.0.0 +sphinxcontrib-moderncmakedomain==3.19 +sphinxcontrib-svg2pdfconverter==1.1.1 diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index f54d5fad6..a08fd8ceb 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -287,10 +287,10 @@ protected: struct borrowed_t { }; struct stolen_t { }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS // Issue in breathe 4.26.1 + /// @cond BROKEN template friend T reinterpret_borrow(handle); template friend T reinterpret_steal(handle); -#endif + /// @endcond public: // Only accessible from derived classes and the reinterpret_* functions @@ -1717,7 +1717,7 @@ public: #endif }; -#ifndef DOXYGEN_SHOULD_SKIP_THIS +/// @cond DUPLICATE inline memoryview memoryview::from_buffer( void *ptr, ssize_t itemsize, const char* format, detail::any_container shape, @@ -1745,7 +1745,7 @@ inline memoryview memoryview::from_buffer( throw error_already_set(); return memoryview(object(obj, stolen_t{})); } -#endif // DOXYGEN_SHOULD_SKIP_THIS +/// @endcond /// @} pytypes /// \addtogroup python_builtins diff --git a/noxfile.py b/noxfile.py index 53d87dbcb..4adffac2e 100644 --- a/noxfile.py +++ b/noxfile.py @@ -57,10 +57,10 @@ def docs(session: nox.Session) -> None: session.chdir("docs") if "pdf" in session.posargs: - session.run("sphinx-build", "-M", "latexpdf", ".", "_build") + session.run("sphinx-build", "-b", "latexpdf", ".", "_build") return - session.run("sphinx-build", "-M", "html", ".", "_build") + session.run("sphinx-build", "-b", "html", ".", "_build") if "serve" in session.posargs: session.log("Launching docs at http://localhost:8000/ - use Ctrl-C to quit") @@ -86,6 +86,8 @@ def build(session: nox.Session) -> None: session.install("build") session.log("Building normal files") - session.run("python", "-m", "build") + session.run("python", "-m", "build", *session.posargs) session.log("Building pybind11-global files (PYBIND11_GLOBAL_SDIST=1)") - session.run("python", "-m", "build", env={"PYBIND11_GLOBAL_SDIST": "1"}) + session.run( + "python", "-m", "build", *session.posargs, env={"PYBIND11_GLOBAL_SDIST": "1"} + ) From e450eb62c21c8518c1988c3b17bc5793ea347756 Mon Sep 17 00:00:00 2001 From: Guillaume Jacquenot Date: Fri, 12 Nov 2021 16:53:43 +0100 Subject: [PATCH 10/37] Removed duplicated word in docs/advanced/cast/eigen.rst (#3458) --- docs/advanced/cast/eigen.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/advanced/cast/eigen.rst b/docs/advanced/cast/eigen.rst index 80f101343..a5c11a3f1 100644 --- a/docs/advanced/cast/eigen.rst +++ b/docs/advanced/cast/eigen.rst @@ -52,7 +52,7 @@ can be mapped *and* if the numpy array is writeable (that is the passed variable will be transparently carried out directly on the ``numpy.ndarray``. -This means you can can write code such as the following and have it work as +This means you can write code such as the following and have it work as expected: .. code-block:: cpp From 270b11d50229e67e2d8d63e96464f9bcd12b527c Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Sat, 13 Nov 2021 21:32:58 -0500 Subject: [PATCH 11/37] Revert "style: drop pycln" (#3466) * Revert "style: drop pycln (#3397)" This reverts commit 606f81a966e56d1ec0f17b0c032e8d6679430d67. * Update .pre-commit-config.yaml --- .pre-commit-config.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6f0bb39b1..91047b328 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -61,6 +61,12 @@ repos: hooks: - id: remove-tabs +# Autoremoves unused imports +- repo: https://github.com/hadialqattan/pycln + rev: v1.1.0 + hooks: + - id: pycln + - repo: https://github.com/pre-commit/pygrep-hooks rev: v1.9.0 hooks: From afdc09deda50d82eba6cc2e48228df7d909650be Mon Sep 17 00:00:00 2001 From: Trigve Date: Mon, 15 Nov 2021 19:36:41 +0100 Subject: [PATCH 12/37] [master] Wrong caching of overrides (#3465) * override: Fix wrong caching of the overrides There was a problem when the python type, which was stored in override cache for C++ functions, was destroyed and the record wasn't removed from the override cache. Therefor, dangling pointer was stored there. Then when the memory was reused and new type was allocated at the given address and the method with the same name (as previously stored in the cache) was actually overridden in python, it would wrongly find it in the override cache for C++ functions and therefor override from python wouldn't be called. The fix is to erase the type from the override cache when the type is destroyed. * test: Pass by const ref instead of by value (clang-tidy) * test: Rename classes and move to different files Rename the classes and files so they're no too generic. Also, better place to test the stuff is in test_virtual_functions.cpp/.py as we're basically testing the virtual functions/trampolines. * Add TODO for erasure code * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- include/pybind11/pybind11.h | 10 ++++++ tests/test_embed/CMakeLists.txt | 2 +- tests/test_embed/test_interpreter.cpp | 49 +++++++++++++++++++++++++++ tests/test_embed/test_trampoline.py | 18 ++++++++++ tests/test_virtual_functions.cpp | 25 ++++++++++++++ tests/test_virtual_functions.py | 19 +++++++++++ 6 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 tests/test_embed/test_trampoline.py diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index b8b7c7a02..c2b88688a 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1979,6 +1979,16 @@ inline std::pair all_t // gets destroyed: weakref((PyObject *) type, cpp_function([type](handle wr) { get_internals().registered_types_py.erase(type); + + // TODO consolidate the erasure code in pybind11_meta_dealloc() in class.h + auto &cache = get_internals().inactive_override_cache; + for (auto it = cache.begin(), last = cache.end(); it != last; ) { + if (it->first == reinterpret_cast(type)) + it = cache.erase(it); + else + ++it; + } + wr.dec_ref(); })).release(); } diff --git a/tests/test_embed/CMakeLists.txt b/tests/test_embed/CMakeLists.txt index 3b89d6e58..edb8961a7 100644 --- a/tests/test_embed/CMakeLists.txt +++ b/tests/test_embed/CMakeLists.txt @@ -25,7 +25,7 @@ pybind11_enable_warnings(test_embed) target_link_libraries(test_embed PRIVATE pybind11::embed Catch2::Catch2 Threads::Threads) if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) - file(COPY test_interpreter.py DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(COPY test_interpreter.py test_trampoline.py DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") endif() add_custom_target( diff --git a/tests/test_embed/test_interpreter.cpp b/tests/test_embed/test_interpreter.cpp index 20bcade0a..508975eb3 100644 --- a/tests/test_embed/test_interpreter.cpp +++ b/tests/test_embed/test_interpreter.cpp @@ -37,6 +37,22 @@ class PyWidget final : public Widget { std::string argv0() const override { PYBIND11_OVERRIDE_PURE(std::string, Widget, argv0); } }; +class test_override_cache_helper { + +public: + virtual int func() { return 0; } + + test_override_cache_helper() = default; + virtual ~test_override_cache_helper() = default; + // Non-copyable + test_override_cache_helper &operator=(test_override_cache_helper const &Right) = delete; + test_override_cache_helper(test_override_cache_helper const &Copy) = delete; +}; + +class test_override_cache_helper_trampoline : public test_override_cache_helper { + int func() override { PYBIND11_OVERRIDE(int, test_override_cache_helper, func); } +}; + PYBIND11_EMBEDDED_MODULE(widget_module, m) { py::class_(m, "Widget") .def(py::init()) @@ -45,6 +61,12 @@ PYBIND11_EMBEDDED_MODULE(widget_module, m) { m.def("add", [](int i, int j) { return i + j; }); } +PYBIND11_EMBEDDED_MODULE(trampoline_module, m) { + py::class_>(m, "test_override_cache_helper") + .def(py::init_alias<>()) + .def("func", &test_override_cache_helper::func); +} + PYBIND11_EMBEDDED_MODULE(throw_exception, ) { throw std::runtime_error("C++ Error"); } @@ -73,6 +95,33 @@ TEST_CASE("Pass classes and data between modules defined in C++ and Python") { REQUIRE(cpp_widget.the_answer() == 42); } +TEST_CASE("Override cache") { + auto module_ = py::module_::import("test_trampoline"); + REQUIRE(py::hasattr(module_, "func")); + REQUIRE(py::hasattr(module_, "func2")); + + auto locals = py::dict(**module_.attr("__dict__")); + + int i = 0; + for (; i < 1500; ++i) { + std::shared_ptr p_obj; + std::shared_ptr p_obj2; + + py::object loc_inst = locals["func"](); + p_obj = py::cast>(loc_inst); + + int ret = p_obj->func(); + + REQUIRE(ret == 42); + + loc_inst = locals["func2"](); + + p_obj2 = py::cast>(loc_inst); + + p_obj2->func(); + } +} + TEST_CASE("Import error handling") { REQUIRE_NOTHROW(py::module_::import("widget_module")); REQUIRE_THROWS_WITH(py::module_::import("throw_exception"), diff --git a/tests/test_embed/test_trampoline.py b/tests/test_embed/test_trampoline.py new file mode 100644 index 000000000..87c8fa44c --- /dev/null +++ b/tests/test_embed/test_trampoline.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +import trampoline_module + + +def func(): + class Test(trampoline_module.test_override_cache_helper): + def func(self): + return 42 + + return Test() + + +def func2(): + class Test(trampoline_module.test_override_cache_helper): + pass + + return Test() diff --git a/tests/test_virtual_functions.cpp b/tests/test_virtual_functions.cpp index 6e06db9fc..f1a513180 100644 --- a/tests/test_virtual_functions.cpp +++ b/tests/test_virtual_functions.cpp @@ -214,6 +214,25 @@ static void test_gil_from_thread() { t.join(); } +class test_override_cache_helper { + +public: + virtual int func() { return 0; } + + test_override_cache_helper() = default; + virtual ~test_override_cache_helper() = default; + // Non-copyable + test_override_cache_helper &operator=(test_override_cache_helper const &Right) = delete; + test_override_cache_helper(test_override_cache_helper const &Copy) = delete; +}; + +class test_override_cache_helper_trampoline : public test_override_cache_helper { + int func() override { PYBIND11_OVERRIDE(int, test_override_cache_helper, func); } +}; + +inline int test_override_cache(std::shared_ptr const &instance) { return instance->func(); } + + // Forward declaration (so that we can put the main tests here; the inherited virtual approaches are // rather long). @@ -378,6 +397,12 @@ TEST_SUBMODULE(virtual_functions, m) { // .def("str_ref", &OverrideTest::str_ref) .def("A_value", &OverrideTest::A_value) .def("A_ref", &OverrideTest::A_ref); + + py::class_>(m, "test_override_cache_helper") + .def(py::init_alias<>()) + .def("func", &test_override_cache_helper::func); + + m.def("test_override_cache", test_override_cache); } diff --git a/tests/test_virtual_functions.py b/tests/test_virtual_functions.py index 0b550992f..4f25cac4a 100644 --- a/tests/test_virtual_functions.py +++ b/tests/test_virtual_functions.py @@ -439,3 +439,22 @@ def test_issue_1454(): # Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7) m.test_gil() m.test_gil_from_thread() + + +def test_python_override(): + def func(): + class Test(m.test_override_cache_helper): + def func(self): + return 42 + + return Test() + + def func2(): + class Test(m.test_override_cache_helper): + pass + + return Test() + + for _ in range(1500): + assert m.test_override_cache(func()) == 42 + assert m.test_override_cache(func2()) == 0 From 9422d98fcc46cee9193178fdc9323e3d8d384f16 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 15 Nov 2021 22:48:39 -0500 Subject: [PATCH 13/37] [pre-commit.ci] pre-commit autoupdate (#3473) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/isort: 5.10.0 → 5.10.1](https://github.com/PyCQA/isort/compare/5.10.0...5.10.1) - [github.com/shellcheck-py/shellcheck-py: v0.7.2.1 → v0.8.0.1](https://github.com/shellcheck-py/shellcheck-py/compare/v0.7.2.1...v0.8.0.1) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 91047b328..357e2a84b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,7 +38,7 @@ repos: - id: pyupgrade - repo: https://github.com/PyCQA/isort - rev: 5.10.0 + rev: 5.10.1 hooks: - id: isort @@ -128,7 +128,7 @@ repos: args: ["-L", "nd,ot,thist"] - repo: https://github.com/shellcheck-py/shellcheck-py - rev: v0.7.2.1 + rev: v0.8.0.1 hooks: - id: shellcheck From d2b21316031783fa306ae86e4e379e3db2640a5e Mon Sep 17 00:00:00 2001 From: Sergiu Deitsch Date: Tue, 16 Nov 2021 16:03:41 +0100 Subject: [PATCH 14/37] cmake: report version type in the version string (#3472) --- tools/pybind11Config.cmake.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/pybind11Config.cmake.in b/tools/pybind11Config.cmake.in index 8f8701be7..262020d14 100644 --- a/tools/pybind11Config.cmake.in +++ b/tools/pybind11Config.cmake.in @@ -13,7 +13,7 @@ This module sets the following variables in your project: ``pybind11_VERSION`` pybind11 version in format Major.Minor.Release ``pybind11_VERSION_TYPE`` - pybind11 version type (dev, release) + pybind11 version type (``dev*`` or empty for a release) ``pybind11_INCLUDE_DIRS`` Directories where pybind11 and python headers are located. ``pybind11_INCLUDE_DIR`` @@ -228,6 +228,6 @@ include("${CMAKE_CURRENT_LIST_DIR}/pybind11Common.cmake") if(NOT pybind11_FIND_QUIETLY) message( STATUS - "Found pybind11: ${pybind11_INCLUDE_DIR} (found version \"${pybind11_VERSION}\" ${pybind11_VERSION_TYPE})" + "Found pybind11: ${pybind11_INCLUDE_DIR} (found version \"${pybind11_VERSION}${pybind11_VERSION_TYPE}\")" ) endif() From 1eb59963c78644f3e3a9b3fc6186df9b211093fc Mon Sep 17 00:00:00 2001 From: Guillaume Jacquenot Date: Tue, 16 Nov 2021 23:32:01 +0100 Subject: [PATCH 15/37] Removed duplicated word in docs/advanced/exceptions.rst (#3476) --- docs/advanced/exceptions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/advanced/exceptions.rst b/docs/advanced/exceptions.rst index 40f67d7b8..7cd8447b9 100644 --- a/docs/advanced/exceptions.rst +++ b/docs/advanced/exceptions.rst @@ -64,7 +64,7 @@ at its exception handler. +--------------------------------------+--------------------------------------+ Exception translation is not bidirectional. That is, *catching* the C++ -exceptions defined above above will not trap exceptions that originate from +exceptions defined above will not trap exceptions that originate from Python. For that, catch :class:`pybind11::error_already_set`. See :ref:`below ` for further details. From 72282f75a10a5ec9d34d4ab4305546bfbd8d586d Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Wed, 17 Nov 2021 09:44:19 -0500 Subject: [PATCH 16/37] ci: support development releases of Python (#3419) * ci: support development releases of Python * fix: better PyPy support * fix: patch over a few more pypy issues * Try to patch * Properly follow pep667 * Fix typo * Whoops, 667 not in yet * For testing * More testing * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Try to backport * Try to simplify fix * Nail down the fix * Try pypy workaround * Typo * one last typo * Replacing 0x03110000 with 0x030B0000 * Add TODO. Drop PyPy * Fix typo * Revert catch upgrade * fix: minor cleanup, try pypy again Co-authored-by: Aaron Gokaslan Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Ralf W. Grosse-Kunstleve --- .github/workflows/ci.yml | 11 ++-- .github/workflows/upstream.yml | 112 +++++++++++++++++++++++++++++++++ include/pybind11/cast.h | 3 +- include/pybind11/eval.h | 4 +- include/pybind11/pybind11.h | 7 ++- tests/requirements.txt | 2 +- tests/test_buffers.py | 4 ++ tests/test_builtin_casters.py | 7 ++- tests/test_exceptions.py | 4 +- 9 files changed, 137 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/upstream.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2888c420b..dcc61ecd7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,16 +30,14 @@ jobs: - '3.6' - '3.9' - '3.10' - # - '3.11-dev' - - 'pypy-3.7-v7.3.5' - # - 'pypy-3.8' + - 'pypy-3.7-v7.3.7' + - 'pypy-3.8-v7.3.7' # Items in here will either be added to the build matrix (if not # present), or add new keys to an existing matrix element if all the # existing keys match. # - # We support three optional keys: args (both build), args1 (first - # build), and args2 (second build). + # We support an optional keys: args, for cmake args include: # Just add a key - runs-on: ubuntu-latest @@ -122,7 +120,7 @@ jobs: run: git clean -fdx # Second build - C++17 mode and in a build directory - - name: Configure ${{ matrix.args2 }} + - name: Configure C++17 run: > cmake -S . -B build2 -DPYBIND11_WERROR=ON @@ -130,7 +128,6 @@ jobs: -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=17 ${{ matrix.args }} - ${{ matrix.args2 }} - name: Build run: cmake --build build2 -j 2 diff --git a/.github/workflows/upstream.yml b/.github/workflows/upstream.yml new file mode 100644 index 000000000..654947425 --- /dev/null +++ b/.github/workflows/upstream.yml @@ -0,0 +1,112 @@ + +name: Upstream + +on: + workflow_dispatch: + pull_request: + +concurrency: + group: upstream-${{ github.ref }} + cancel-in-progress: true + +env: + PIP_ONLY_BINARY: numpy + +jobs: + standard: + name: "🐍 3.11 dev • ubuntu-latest • x64" + runs-on: ubuntu-latest + if: "contains(github.event.pull_request.labels.*.name, 'python dev')" + + steps: + - uses: actions/checkout@v2 + + - name: Setup Python 3.11 + uses: actions/setup-python@v2 + with: + python-version: "3.11-dev" + + - name: Setup Boost (Linux) + if: runner.os == 'Linux' + run: sudo apt-get install libboost-dev + + - name: Update CMake + uses: jwlawson/actions-setup-cmake@v1.11 + + - name: Prepare env + run: | + python -m pip install -r tests/requirements.txt + + - name: Setup annotations on Linux + if: runner.os == 'Linux' + run: python -m pip install pytest-github-actions-annotate-failures + + # First build - C++11 mode and inplace + - name: Configure C++11 + run: > + cmake -S . -B . + -DPYBIND11_WERROR=ON + -DDOWNLOAD_CATCH=ON + -DDOWNLOAD_EIGEN=ON + -DCMAKE_CXX_STANDARD=11 + + - name: Build C++11 + run: cmake --build . -j 2 + + - name: Python tests C++11 + run: cmake --build . --target pytest -j 2 + + - name: C++11 tests + run: cmake --build . --target cpptest -j 2 + + - name: Interface test C++11 + run: cmake --build . --target test_cmake_build + + - name: Clean directory + run: git clean -fdx + + # Second build - C++17 mode and in a build directory + - name: Configure C++17 + run: > + cmake -S . -B build2 + -DPYBIND11_WERROR=ON + -DDOWNLOAD_CATCH=ON + -DDOWNLOAD_EIGEN=ON + -DCMAKE_CXX_STANDARD=17 + ${{ matrix.args }} + ${{ matrix.args2 }} + + - name: Build + run: cmake --build build2 -j 2 + + - name: Python tests + run: cmake --build build2 --target pytest + + - name: C++ tests + run: cmake --build build2 --target cpptest + + # Third build - C++17 mode with unstable ABI + - name: Configure (unstable ABI) + run: > + cmake -S . -B build3 + -DPYBIND11_WERROR=ON + -DDOWNLOAD_CATCH=ON + -DDOWNLOAD_EIGEN=ON + -DCMAKE_CXX_STANDARD=17 + -DPYBIND11_INTERNALS_VERSION=10000000 + "-DPYBIND11_TEST_OVERRIDE=test_call_policies.cpp;test_gil_scoped.cpp;test_thread.cpp" + ${{ matrix.args }} + + - name: Build (unstable ABI) + run: cmake --build build3 -j 2 + + - name: Python tests (unstable ABI) + run: cmake --build build3 --target pytest + + - name: Interface test + run: cmake --build build2 --target test_cmake_build + + # This makes sure the setup_helpers module can build packages using + # setuptools + - name: Setuptools helpers test + run: pytest tests/extra_setuptools diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 4b39827c2..097d41bda 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -150,7 +150,8 @@ public: return false; } else { handle src_or_index = src; -#if PY_VERSION_HEX < 0x03080000 + // PyPy: 7.3.7's 3.8 does not implement PyLong_*'s __index__ calls. +#if PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION) object index; if (!PYBIND11_LONG_CHECK(src.ptr())) { // So: index_check(src.ptr()) index = reinterpret_steal(PyNumber_Index(src.ptr())); diff --git a/include/pybind11/eval.h b/include/pybind11/eval.h index 6cc672e2d..4248551e9 100644 --- a/include/pybind11/eval.h +++ b/include/pybind11/eval.h @@ -19,11 +19,11 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(detail) inline void ensure_builtins_in_globals(object &global) { - #if PY_VERSION_HEX < 0x03080000 + #if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x03080000 // Running exec and eval on Python 2 and 3 adds `builtins` module under // `__builtins__` key to globals if not yet present. // Python 3.8 made PyRun_String behave similarly. Let's also do that for - // older versions, for consistency. + // older versions, for consistency. This was missing from PyPy3.8 7.3.7. if (!global.contains("__builtins__")) global["__builtins__"] = module_::import(PYBIND11_BUILTINS_MODULE); #else diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index c2b88688a..cfe03f6db 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -2365,8 +2365,9 @@ inline function get_type_override(const void *this_ptr, const type_info *this_ty /* Don't call dispatch code if invoked from overridden function. Unfortunately this doesn't work on PyPy. */ -#if !defined(PYPY_VERSION) - +#if !defined(PYPY_VERSION) && PY_VERSION_HEX < 0x030B0000 + // TODO: Remove PyPy workaround for Python 3.11. + // Current API fails on 3.11 since co_varnames can be null. #if PY_VERSION_HEX >= 0x03090000 PyFrameObject *frame = PyThreadState_GetFrame(PyThreadState_Get()); if (frame != nullptr) { @@ -2374,7 +2375,7 @@ inline function get_type_override(const void *this_ptr, const type_info *this_ty // f_code is guaranteed to not be NULL if ((std::string) str(f_code->co_name) == name && f_code->co_argcount > 0) { PyObject* locals = PyEval_GetLocals(); - if (locals != nullptr) { + if (locals != nullptr && f_code->co_varnames != nullptr) { PyObject *self_caller = dict_getitem( locals, PyTuple_GET_ITEM(f_code->co_varnames, 0) ); diff --git a/tests/requirements.txt b/tests/requirements.txt index 8d2742a71..98ca46d28 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -2,7 +2,7 @@ numpy==1.16.6; python_version<"3.6" and sys_platform!="win32" and platform_pytho numpy==1.19.0; platform_python_implementation=="PyPy" and sys_platform=="linux" and python_version=="3.6" numpy==1.20.0; platform_python_implementation=="PyPy" and sys_platform=="linux" and python_version=="3.7" numpy==1.19.3; platform_python_implementation!="PyPy" and python_version=="3.6" -numpy==1.21.3; platform_python_implementation!="PyPy" and python_version>="3.7" +numpy==1.21.3; platform_python_implementation!="PyPy" and python_version>="3.7" and python_version<"3.11" py @ git+https://github.com/pytest-dev/py; python_version>="3.11" pytest==4.6.9; python_version<"3.5" pytest==6.1.2; python_version=="3.5" diff --git a/tests/test_buffers.py b/tests/test_buffers.py index adf7cadff..0877dc0e4 100644 --- a/tests/test_buffers.py +++ b/tests/test_buffers.py @@ -36,6 +36,10 @@ def test_from_python(): # https://foss.heptapod.net/pypy/pypy/-/issues/2444 +# TODO: fix on recent PyPy +@pytest.mark.xfail( + env.PYPY, reason="PyPy 7.3.7 doesn't clear this anymore", stict=False +) def test_to_python(): mat = m.Matrix(5, 4) assert memoryview(mat).shape == (5, 4) diff --git a/tests/test_builtin_casters.py b/tests/test_builtin_casters.py index 2a061c193..9c5e17a68 100644 --- a/tests/test_builtin_casters.py +++ b/tests/test_builtin_casters.py @@ -299,7 +299,8 @@ def test_int_convert(): assert noconvert(7) == 7 cant_convert(3.14159) # TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar) - if (3, 8) <= env.PY < (3, 10): + # TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7) + if (3, 8) <= env.PY < (3, 10) and env.CPYTHON: with env.deprecated_call(): assert convert(Int()) == 42 else: @@ -334,7 +335,9 @@ def test_numpy_int_convert(): # The implicit conversion from np.float32 is undesirable but currently accepted. # TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar) - if (3, 8) <= env.PY < (3, 10): + # TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7) + # https://github.com/pybind/pybind11/issues/3408 + if (3, 8) <= env.PY < (3, 10) and env.CPYTHON: with env.deprecated_call(): assert convert(np.float32(3.14159)) == 3 else: diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 3821eadaa..56201a81c 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -3,7 +3,7 @@ import sys import pytest -import env # noqa: F401 +import env import pybind11_cross_module_tests as cm from pybind11_tests import exceptions as m @@ -97,6 +97,8 @@ def ignore_pytest_unraisable_warning(f): return f +# TODO: find out why this fails on PyPy, https://foss.heptapod.net/pypy/pypy/-/issues/3583 +@pytest.mark.xfail(env.PYPY, reason="Failure on PyPy 3.8 (7.3.7)", strict=False) @ignore_pytest_unraisable_warning def test_python_alreadyset_in_destructor(monkeypatch, capsys): hooked = False From ff51fcb773ef7e3cfd6c96d044caf549024d3250 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Thu, 18 Nov 2021 08:42:08 -0500 Subject: [PATCH 17/37] docs: fix broken link (again) --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 7ce57b03a..45c4af5a6 100644 --- a/README.rst +++ b/README.rst @@ -106,7 +106,7 @@ goodies: - Binaries are generally smaller by a factor of at least 2 compared to equivalent bindings generated by Boost.Python. A recent pybind11 conversion of PyRosetta, an enormous Boost.Python binding project, - `reported `_ + `reported `_ a binary size reduction of **5.4x** and compile time reduction by **5.8x**. From 15f8d7c12ed5fd78bd3aa8d993e76a334089fa55 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Thu, 18 Nov 2021 10:01:24 -0500 Subject: [PATCH 18/37] fix(build): cleaner CMake printouts & IDE folders (#3479) --- CMakeLists.txt | 14 ++++++++------ tests/CMakeLists.txt | 8 ++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e81869c3..3787982cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,11 @@ else() cmake_policy(VERSION 3.22) endif() +# Avoid infinite recursion if tests include this as a subdirectory +if(DEFINED PYBIND11_MASTER_PROJECT) + return() +endif() + # Extract project version from source file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/include/pybind11/detail/common.h" pybind11_version_defines REGEX "#define PYBIND11_VERSION_(MAJOR|MINOR|PATCH) ") @@ -45,13 +50,8 @@ if(NOT pybind11_FIND_QUIETLY) message(STATUS "pybind11 v${pybind11_VERSION} ${pybind11_VERSION_TYPE}") endif() -# Avoid infinite recursion if tests include this as a subdirectory -if(DEFINED PYBIND11_MASTER_PROJECT) - set(PYBIND11_TEST OFF) -endif() - # Check if pybind11 is being used directly or via add_subdirectory -if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR AND NOT DEFINED PYBIND11_MASTER_PROJECT) +if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) ### Warn if not an out-of-source builds if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) set(lines @@ -80,6 +80,8 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR AND NOT DEFINED PYBIND11_MASTER_ endif() set(pybind11_system "") + + set_property(GLOBAL PROPERTY USE_FOLDERS ON) else() set(PYBIND11_MASTER_PROJECT OFF) set(pybind11_system SYSTEM) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6dc67a11a..8b19b1967 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -429,6 +429,14 @@ foreach(target ${test_targets}) endif() endforeach() +# Provide nice organisation in IDEs +if(NOT CMAKE_VERSION VERSION_LESS 3.8) + source_group( + TREE "${CMAKE_CURRENT_SOURCE_DIR}/../include" + PREFIX "Header Files" + FILES ${PYBIND11_HEADERS}) +endif() + # Make sure pytest is found or produce a warning pybind11_find_import(pytest VERSION 3.1) From 56322dafc9d4d248c46bd1755568df01fbea4994 Mon Sep 17 00:00:00 2001 From: ngc92 <7938269+ngc92@users.noreply.github.com> Date: Thu, 18 Nov 2021 21:06:04 +0200 Subject: [PATCH 19/37] fixed include for filesystem::path (#3482) --- docs/advanced/cast/overview.rst | 180 ++++++++++++++++---------------- 1 file changed, 90 insertions(+), 90 deletions(-) diff --git a/docs/advanced/cast/overview.rst b/docs/advanced/cast/overview.rst index 6341fce6d..6a834a3e5 100644 --- a/docs/advanced/cast/overview.rst +++ b/docs/advanced/cast/overview.rst @@ -75,96 +75,96 @@ The following basic data types are supported out of the box (some may require an additional extension header to be included). To pass other data structures as arguments and return values, refer to the section on binding :ref:`classes`. -+------------------------------------+---------------------------+-------------------------------+ -| Data type | Description | Header file | -+====================================+===========================+===============================+ -| ``int8_t``, ``uint8_t`` | 8-bit integers | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``int16_t``, ``uint16_t`` | 16-bit integers | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``int32_t``, ``uint32_t`` | 32-bit integers | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``int64_t``, ``uint64_t`` | 64-bit integers | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``ssize_t``, ``size_t`` | Platform-dependent size | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``float``, ``double`` | Floating point types | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``bool`` | Two-state Boolean type | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``char`` | Character literal | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``char16_t`` | UTF-16 character literal | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``char32_t`` | UTF-32 character literal | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``wchar_t`` | Wide character literal | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``const char *`` | UTF-8 string literal | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``const char16_t *`` | UTF-16 string literal | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``const char32_t *`` | UTF-32 string literal | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``const wchar_t *`` | Wide string literal | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::string`` | STL dynamic UTF-8 string | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::u16string`` | STL dynamic UTF-16 string | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::u32string`` | STL dynamic UTF-32 string | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::wstring`` | STL dynamic wide string | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::string_view``, | STL C++17 string views | :file:`pybind11/pybind11.h` | -| ``std::u16string_view``, etc. | | | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::pair`` | Pair of two custom types | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::tuple<...>`` | Arbitrary tuple of types | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::reference_wrapper<...>`` | Reference type wrapper | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::complex`` | Complex numbers | :file:`pybind11/complex.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::array`` | STL static array | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::vector`` | STL dynamic array | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::deque`` | STL double-ended queue | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::valarray`` | STL value array | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::list`` | STL linked list | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::map`` | STL ordered map | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::unordered_map`` | STL unordered map | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::set`` | STL ordered set | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::unordered_set`` | STL unordered set | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::optional`` | STL optional type (C++17) | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::experimental::optional`` | STL optional type (exp.) | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::variant<...>`` | Type-safe union (C++17) | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::filesystem::path`` | STL path (C++17) [#]_ | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::function<...>`` | STL polymorphic function | :file:`pybind11/functional.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::chrono::duration<...>`` | STL time duration | :file:`pybind11/chrono.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::chrono::time_point<...>`` | STL date/time | :file:`pybind11/chrono.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``Eigen::Matrix<...>`` | Eigen: dense matrix | :file:`pybind11/eigen.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``Eigen::Map<...>`` | Eigen: mapped memory | :file:`pybind11/eigen.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``Eigen::SparseMatrix<...>`` | Eigen: sparse matrix | :file:`pybind11/eigen.h` | -+------------------------------------+---------------------------+-------------------------------+ ++------------------------------------+---------------------------+-----------------------------------+ +| Data type | Description | Header file | ++====================================+===========================+===================================+ +| ``int8_t``, ``uint8_t`` | 8-bit integers | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``int16_t``, ``uint16_t`` | 16-bit integers | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``int32_t``, ``uint32_t`` | 32-bit integers | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``int64_t``, ``uint64_t`` | 64-bit integers | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``ssize_t``, ``size_t`` | Platform-dependent size | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``float``, ``double`` | Floating point types | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``bool`` | Two-state Boolean type | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``char`` | Character literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``char16_t`` | UTF-16 character literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``char32_t`` | UTF-32 character literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``wchar_t`` | Wide character literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``const char *`` | UTF-8 string literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``const char16_t *`` | UTF-16 string literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``const char32_t *`` | UTF-32 string literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``const wchar_t *`` | Wide string literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::string`` | STL dynamic UTF-8 string | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::u16string`` | STL dynamic UTF-16 string | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::u32string`` | STL dynamic UTF-32 string | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::wstring`` | STL dynamic wide string | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::string_view``, | STL C++17 string views | :file:`pybind11/pybind11.h` | +| ``std::u16string_view``, etc. | | | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::pair`` | Pair of two custom types | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::tuple<...>`` | Arbitrary tuple of types | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::reference_wrapper<...>`` | Reference type wrapper | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::complex`` | Complex numbers | :file:`pybind11/complex.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::array`` | STL static array | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::vector`` | STL dynamic array | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::deque`` | STL double-ended queue | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::valarray`` | STL value array | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::list`` | STL linked list | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::map`` | STL ordered map | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::unordered_map`` | STL unordered map | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::set`` | STL ordered set | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::unordered_set`` | STL unordered set | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::optional`` | STL optional type (C++17) | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::experimental::optional`` | STL optional type (exp.) | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::variant<...>`` | Type-safe union (C++17) | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::filesystem::path`` | STL path (C++17) [#]_ | :file:`pybind11/stl/filesystem.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::function<...>`` | STL polymorphic function | :file:`pybind11/functional.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::chrono::duration<...>`` | STL time duration | :file:`pybind11/chrono.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::chrono::time_point<...>`` | STL date/time | :file:`pybind11/chrono.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``Eigen::Matrix<...>`` | Eigen: dense matrix | :file:`pybind11/eigen.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``Eigen::Map<...>`` | Eigen: mapped memory | :file:`pybind11/eigen.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``Eigen::SparseMatrix<...>`` | Eigen: sparse matrix | :file:`pybind11/eigen.h` | ++------------------------------------+---------------------------+-----------------------------------+ .. [#] ``std::filesystem::path`` is converted to ``pathlib.Path`` and ``os.PathLike`` is converted to ``std::filesystem::path``, but this requires From 673b4be3d7809198cd6a13a476fef270e430977d Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Sat, 20 Nov 2021 20:01:57 -0400 Subject: [PATCH 20/37] Fix py::kw_only when used before the first arg of a method (#3488) * Fix py::kw_only when used before the first arg of a method The implicit space for the `self` argument isn't added until we hit the first argument, but this wasn't being done for kw_only or pos_only, and so a kw_only before the first argument would break. This fixes it by properly checking whether we need to add the self arg. (The pos_only issue here was extremely mild -- you didn't get the `/` in the docstring, but AFAICT it has no other effect since there are no meaningful arguments before it anyway). * Style changes - rename check_have_self_arg -> append_self_arg_if_needed - move the argument name inline comments before the args instead of after --- include/pybind11/attr.h | 12 +++++++++--- tests/test_kwargs_and_defaults.cpp | 17 +++++++++++++++++ tests/test_kwargs_and_defaults.py | 21 +++++++++++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/include/pybind11/attr.h b/include/pybind11/attr.h index b95c84904..f1b66fb80 100644 --- a/include/pybind11/attr.h +++ b/include/pybind11/attr.h @@ -414,11 +414,15 @@ inline void check_kw_only_arg(const arg &a, function_record *r) { pybind11_fail("arg(): cannot specify an unnamed argument after a kw_only() annotation or args() argument"); } +inline void append_self_arg_if_needed(function_record *r) { + if (r->is_method && r->args.empty()) + r->args.emplace_back("self", nullptr, handle(), /*convert=*/ true, /*none=*/ false); +} + /// 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*/); + append_self_arg_if_needed(r); r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none); check_kw_only_arg(a, r); @@ -429,7 +433,7 @@ template <> struct process_attribute : process_attribute_default { template <> struct process_attribute : process_attribute_default { static void init(const arg_v &a, function_record *r) { if (r->is_method && r->args.empty()) - r->args.emplace_back("self", nullptr /*descr*/, handle() /*parent*/, true /*convert*/, false /*none not allowed*/); + r->args.emplace_back("self", /*descr=*/ nullptr, /*parent=*/ handle(), /*convert=*/ true, /*none=*/ false); if (!a.value) { #if !defined(NDEBUG) @@ -461,6 +465,7 @@ template <> struct process_attribute : process_attribute_default { /// Process a keyword-only-arguments-follow pseudo argument template <> struct process_attribute : process_attribute_default { static void init(const kw_only &, function_record *r) { + append_self_arg_if_needed(r); if (r->has_args && r->nargs_pos != static_cast(r->args.size())) pybind11_fail("Mismatched args() and kw_only(): they must occur at the same relative argument location (or omit kw_only() entirely)"); r->nargs_pos = static_cast(r->args.size()); @@ -470,6 +475,7 @@ template <> struct process_attribute : process_attribute_default struct process_attribute : process_attribute_default { static void init(const pos_only &, function_record *r) { + append_self_arg_if_needed(r); r->nargs_pos_only = static_cast(r->args.size()); if (r->nargs_pos_only > r->nargs_pos) pybind11_fail("pos_only(): cannot follow a py::args() argument"); diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp index 312596dab..34ad2a864 100644 --- a/tests/test_kwargs_and_defaults.cpp +++ b/tests/test_kwargs_and_defaults.cpp @@ -167,4 +167,21 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { "class_default_argument", [](py::object a) { return py::repr(std::move(a)); }, "a"_a = py::module_::import("decimal").attr("Decimal")); + + // Initial implementation of kw_only was broken when used on a method/constructor before any + // other arguments + // https://github.com/pybind/pybind11/pull/3402#issuecomment-963341987 + + struct first_arg_kw_only {}; + py::class_(m, "first_arg_kw_only") + .def(py::init([](int) { return first_arg_kw_only(); }), + py::kw_only(), // This being before any args was broken + py::arg("i") = 0) + .def("method", [](first_arg_kw_only&, int, int) {}, + py::kw_only(), // and likewise here + py::arg("i") = 1, py::arg("j") = 2) + // Closely related: pos_only marker didn't show up properly when it was before any other + // arguments (although that is fairly useless in practice). + .def("pos_only", [](first_arg_kw_only&, int, int) {}, + py::pos_only{}, py::arg("i"), py::arg("j")); } diff --git a/tests/test_kwargs_and_defaults.py b/tests/test_kwargs_and_defaults.py index 68903bde1..d61cf2aa5 100644 --- a/tests/test_kwargs_and_defaults.py +++ b/tests/test_kwargs_and_defaults.py @@ -229,6 +229,19 @@ def test_keyword_only_args(msg): """ ) + # https://github.com/pybind/pybind11/pull/3402#issuecomment-963341987 + x = m.first_arg_kw_only(i=1) + x.method() + x.method(i=1, j=2) + assert ( + m.first_arg_kw_only.__init__.__doc__ + == "__init__(self: pybind11_tests.kwargs_and_defaults.first_arg_kw_only, *, i: int = 0) -> None\n" # noqa: E501 line too long + ) + assert ( + m.first_arg_kw_only.method.__doc__ + == "method(self: pybind11_tests.kwargs_and_defaults.first_arg_kw_only, *, i: int = 1, j: int = 2) -> None\n" # noqa: E501 line too long + ) + def test_positional_only_args(msg): assert m.pos_only_all(1, 2) == (1, 2) @@ -310,6 +323,14 @@ def test_positional_only_args(msg): {"i": 5, "m": 8}, ) + # pos_only at the beginning of the argument list was "broken" in how it was displayed (though + # this is fairly useless in practice). Related to: + # https://github.com/pybind/pybind11/pull/3402#issuecomment-963341987 + assert ( + m.first_arg_kw_only.pos_only.__doc__ + == "pos_only(self: pybind11_tests.kwargs_and_defaults.first_arg_kw_only, /, i: int, j: int) -> None\n" # noqa: E501 line too long + ) + def test_signatures(): assert "kw_only_all(*, i: int, j: int) -> tuple\n" == m.kw_only_all.__doc__ From 9281faf429970ec43881ee15f9cdf1ee398807ef Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 22 Nov 2021 01:33:03 -0800 Subject: [PATCH 21/37] Fixing `stict` vs `strict` typo. (#3493) --- tests/test_buffers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_buffers.py b/tests/test_buffers.py index 0877dc0e4..0d5bf16c3 100644 --- a/tests/test_buffers.py +++ b/tests/test_buffers.py @@ -38,7 +38,7 @@ def test_from_python(): # https://foss.heptapod.net/pypy/pypy/-/issues/2444 # TODO: fix on recent PyPy @pytest.mark.xfail( - env.PYPY, reason="PyPy 7.3.7 doesn't clear this anymore", stict=False + env.PYPY, reason="PyPy 7.3.7 doesn't clear this anymore", strict=False ) def test_to_python(): mat = m.Matrix(5, 4) From 5d067e870ab828083cf8b9eec5ff73fade4b3e8b Mon Sep 17 00:00:00 2001 From: Lishen1 Date: Mon, 22 Nov 2021 23:27:00 +0300 Subject: [PATCH 22/37] fix: remove redundant copy operation to fix warning (#3486) * fix compiler warning: deprecated implicit copy constructor * take care of the bug http://eigen.tuxfamily.org/bz/show_bug.cgi?id=747 * add parenthesis for better reading * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update include/pybind11/eigen.h Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Henry Schreiner --- include/pybind11/eigen.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/include/pybind11/eigen.h b/include/pybind11/eigen.h index 97b1d96b0..e43e484c6 100644 --- a/include/pybind11/eigen.h +++ b/include/pybind11/eigen.h @@ -80,14 +80,12 @@ template struct EigenConformable { // Matrix type: EigenConformable(EigenIndex r, EigenIndex c, EigenIndex rstride, EigenIndex cstride) : - conformable{true}, rows{r}, cols{c} { - // TODO: when Eigen bug #747 is fixed, remove the tests for non-negativity. http://eigen.tuxfamily.org/bz/show_bug.cgi?id=747 - if (rstride < 0 || cstride < 0) { - negativestrides = true; - } else { - stride = {EigenRowMajor ? rstride : cstride /* outer stride */, - EigenRowMajor ? cstride : rstride /* inner stride */ }; - } + conformable{true}, rows{r}, cols{c}, + //TODO: when Eigen bug #747 is fixed, remove the tests for non-negativity. http://eigen.tuxfamily.org/bz/show_bug.cgi?id=747 + stride{EigenRowMajor ? (rstride > 0 ? rstride : 0) : (cstride > 0 ? cstride : 0) /* outer stride */, + EigenRowMajor ? (cstride > 0 ? cstride : 0) : (rstride > 0 ? rstride : 0) /* inner stride */ }, + negativestrides{rstride < 0 || cstride < 0} { + } // Vector type: EigenConformable(EigenIndex r, EigenIndex c, EigenIndex stride) From fe65693c720ca1e859f9734355bf271a1342cbf7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 22 Nov 2021 16:25:35 -0500 Subject: [PATCH 23/37] [pre-commit.ci] pre-commit autoupdate (#3500) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/asottile/pyupgrade: v2.29.0 → v2.29.1](https://github.com/asottile/pyupgrade/compare/v2.29.0...v2.29.1) - [github.com/psf/black: 21.10b0 → 21.11b1](https://github.com/psf/black/compare/21.10b0...21.11b1) - [github.com/asottile/blacken-docs: v1.11.0 → v1.12.0](https://github.com/asottile/blacken-docs/compare/v1.11.0...v1.12.0) * Keep blacken-docs and black in sync. Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Aaron Gokaslan --- .pre-commit-config.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 357e2a84b..601031243 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -33,7 +33,7 @@ repos: exclude: ^noxfile.py$ - repo: https://github.com/asottile/pyupgrade - rev: v2.29.0 + rev: v2.29.1 hooks: - id: pyupgrade @@ -44,16 +44,16 @@ repos: # Black, the code formatter, natively supports pre-commit - repo: https://github.com/psf/black - rev: 21.10b0 # Keep in sync with blacken-docs + rev: 21.11b1 # Keep in sync with blacken-docs hooks: - id: black - repo: https://github.com/asottile/blacken-docs - rev: v1.11.0 + rev: v1.12.0 hooks: - id: blacken-docs additional_dependencies: - - black==21.10b0 # keep in sync with black hook + - black==21.11b1 # keep in sync with black hook # Changes tabs to spaces - repo: https://github.com/Lucas-C/pre-commit-hooks From 70a58c577eaf067748c2ec31bfd0b0a614cffba6 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Mon, 22 Nov 2021 17:01:35 -0800 Subject: [PATCH 24/37] Replace usage of deprecated Eigen class MappedSparseMatrix. (#3499) * Replace usage of deprecated Eigen class Eigen::MappedSparseMatrix has been deprecated since Eigen 3.3 from 2016. Use the equivalent modern syntax Eigen::Map>. * Update eigen.h * Update eigen.h --- include/pybind11/eigen.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/include/pybind11/eigen.h b/include/pybind11/eigen.h index e43e484c6..965d66e8a 100644 --- a/include/pybind11/eigen.h +++ b/include/pybind11/eigen.h @@ -50,8 +50,12 @@ PYBIND11_NAMESPACE_BEGIN(detail) #if EIGEN_VERSION_AT_LEAST(3,3,0) using EigenIndex = Eigen::Index; +template +using EigenMapSparseMatrix = Eigen::Map>; #else using EigenIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE; +template +using EigenMapSparseMatrix = Eigen::MappedSparseMatrix; #endif // Matches Eigen::Map, Eigen::Ref, blocks, etc: @@ -571,9 +575,9 @@ struct type_caster::value>> { if (!values || !innerIndices || !outerIndices) return false; - value = Eigen::MappedSparseMatrix( + value = EigenMapSparseMatrix( shape[0].cast(), shape[1].cast(), nnz, outerIndices.mutable_data(), innerIndices.mutable_data(), values.mutable_data()); From cd176ceeff94ec184abde945ef0867ebe9fb3664 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Thu, 2 Dec 2021 16:41:47 -0500 Subject: [PATCH 25/37] chore: update changelog with recent PRs (#3524) --- docs/changelog.rst | 70 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index bb5457eec..dff8ec808 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -10,6 +10,76 @@ Starting with version 1.8.0, pybind11 releases use a `semantic versioning IN DEVELOPMENT -------------- +New Features: + +* Allow ``py::args`` to be followed by other arguments; the remaining arguments + are implicitly keyword-only, as if a ``py::kw_only{}`` annotation had been + used. + `#3402 `_ + +* Add C++ Exception type to throw and catch ``AttributeError``. Useful for + defining custom ``__setattr__`` and ``__getattr__`` methods. + `#3387 `_ + +Bug fixes: + +* Fix a regression in 2.8.0 that caused undefined behavior (typically + segfaults) in ``make_key_iterator``/``make_value_iterator`` if dereferencing + the iterator returned a temporary value instead of a reference. + `#3348 `_ + +* Fix a rare warning about extra copy in an Eigen constructor. + `#3486 `_ + +* Fix caching of the C++ overrides. + `#3465 `_ + +* Add missing ``std::forward`` calls to some ``cpp_function`` overloads. + `#3443 `_ + +* Support PyPy 7.3.7 and the PyPy3.8 beta. Test python-3.11 on PRs with the ``python dev`` label. + `#3419 `_ + +* Fix 2.8.0 regression with MSVC 2017 + C++17 mode + Python 3. + `#3407 `_ + +* Modernize usage of ``PyCodeObject`` on Python 3.9 (toward supporting Python + 3.11a1) + `#3368 `_ + +* A long-standing bug in eigen.h was fixed (originally PR #3343). The bug was + unmasked by newly added ``static_assert``'s in the Eigen 3.4.0 release. + `#3352 `_ + +* Replace usage of deprecated ``Eigen::MappedSparseMatrix`` with + ``Eigen::Map>`` for Eigen 3.3+. + `#3499 `_ + +* Fixed the potential for dangling references when using properties with + ``std::optional`` types. + `#3376 `_ + +Build system improvements: + +* Nicer CMake printout and IDE organisation for pybind11's own tests. + `#3479 `_ + +* CMake: report version type as part of the version string to avoid a spurious + space in the package status message. + `#3472 `_ + +* Support multiple raw inclusion of CMake helper files (Conan.io does this for + multi-config generators). + `#3420 `_ + +* Fix harmless warning on CMake 3.22. + `#3368 `_ + +* Flags starting with ``-g`` in ``$CFLAGS`` and ``$CPPFLAGS`` are no longer + overridden by ``.Pybind11Extension``. + `#3436 `_ + + v2.8.1 (Oct 27, 2021) --------------------- From b4939fcbfb9a90f02bea6bb70383eac418c8b3be Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Fri, 3 Dec 2021 13:20:32 -0400 Subject: [PATCH 26/37] Expand std::string_view support to str, bytes, memoryview (#3521) * Expand string_view support to str, bytes, memoryview 1. Allows constructing a str or bytes implicitly from a string_view; this is essentially a small shortcut allowing a caller to write `py::bytes{sv}` rather than `py::bytes{sv.data(), sv.size()}`. 2. Allows implicit conversion *to* string_view from py::bytes -- this saves a fair bit more as currently there is no simple way to get such a view of the bytes without copying it (or resorting to Python API calls). (This is not done for `str` because when the str contains unicode we have to allocate to a temporary and so there might not be some string data we can properly view without owning.) 3. Allows `memoryview::from_memory` to accept a string_view. As with the other from_memory calls, it's entirely your responsibility to keep it alive. This also required moving the string_view availability detection into detail/common.h because this PR needs it in pytypes.h, which is higher up the include chain than cast.h where it was being detected currently. * Move string_view include to pytypes.h * CI-testing a fix for the "ambiguous conversion" issue. This change is known to fix the `tensorflow::tstring` issue reported under https://github.com/pybind/pybind11/pull/3521#issuecomment-985100965 TODO: Minimal reproducer for the `tensorflow::tstring` issue. * Make clang-tidy happy (hopefully). * Adding minimal reproducer for the `tensorflow::tstring` issue. Error without the enable_if trick: ``` /usr/local/google/home/rwgk/forked/pybind11/tests/test_builtin_casters.cpp:169:16: error: ambiguous conversion for functional-style cast from 'TypeWithBothOperatorStringAndStringView' to 'py::bytes' return py::bytes(TypeWithBothOperatorStringAndStringView()); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../pytypes.h:1174:5: note: candidate constructor bytes(const std::string &s) : bytes(s.data(), s.size()) { } ^ /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/detail/../pytypes.h:1191:5: note: candidate constructor bytes(std::string_view s) : bytes(s.data(), s.size()) { } ^ ``` * Adding missing NOLINTNEXTLINE * Also apply ambiguous conversion workaround to str() Co-authored-by: Ralf W. Grosse-Kunstleve --- include/pybind11/cast.h | 17 ------------ include/pybind11/detail/common.h | 15 +++++++++++ include/pybind11/pytypes.h | 45 ++++++++++++++++++++++++++++++++ tests/test_builtin_casters.cpp | 24 +++++++++++++++++ tests/test_builtin_casters.py | 11 ++++++++ 5 files changed, 95 insertions(+), 17 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 097d41bda..01dc5df73 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -27,23 +27,6 @@ #include #include -#if defined(PYBIND11_CPP17) -# if defined(__has_include) -# if __has_include() -# define PYBIND11_HAS_STRING_VIEW -# endif -# elif defined(_MSC_VER) -# define PYBIND11_HAS_STRING_VIEW -# endif -#endif -#ifdef PYBIND11_HAS_STRING_VIEW -#include -#endif - -#if defined(__cpp_lib_char8_t) && __cpp_lib_char8_t >= 201811L -# define PYBIND11_HAS_U8STRING -#endif - PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(detail) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 862451fd1..eb5fb0868 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -183,6 +183,21 @@ # define PYBIND11_HAS_VARIANT 1 #endif +#if defined(PYBIND11_CPP17) +# if defined(__has_include) +# if __has_include() +# define PYBIND11_HAS_STRING_VIEW +# endif +# elif defined(_MSC_VER) +# define PYBIND11_HAS_STRING_VIEW +# endif +#endif + +#if defined(__cpp_lib_char8_t) && __cpp_lib_char8_t >= 201811L +# define PYBIND11_HAS_U8STRING +#endif + + #include #include #include diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index a08fd8ceb..f803a05ca 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -18,6 +18,10 @@ # include #endif +#ifdef PYBIND11_HAS_STRING_VIEW +# include +#endif + PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) /* A few forward declarations */ @@ -1085,6 +1089,20 @@ public: // NOLINTNEXTLINE(google-explicit-constructor) str(const std::string &s) : str(s.data(), s.size()) { } +#ifdef PYBIND11_HAS_STRING_VIEW + // enable_if is needed to avoid "ambiguous conversion" errors (see PR #3521). + template ::value, int> = 0> + // NOLINTNEXTLINE(google-explicit-constructor) + str(T s) : str(s.data(), s.size()) { } + +# ifdef PYBIND11_HAS_U8STRING + // reinterpret_cast here is safe (C++20 guarantees char8_t has the same size/alignment as char) + // NOLINTNEXTLINE(google-explicit-constructor) + str(std::u8string_view s) : str(reinterpret_cast(s.data()), s.size()) { } +# endif + +#endif + explicit str(const bytes &b); /** \rst @@ -1167,6 +1185,26 @@ public: pybind11_fail("Unable to extract bytes contents!"); return std::string(buffer, (size_t) length); } + +#ifdef PYBIND11_HAS_STRING_VIEW + // enable_if is needed to avoid "ambiguous conversion" errors (see PR #3521). + template ::value, int> = 0> + // NOLINTNEXTLINE(google-explicit-constructor) + bytes(T s) : bytes(s.data(), s.size()) { } + + // Obtain a string view that views the current `bytes` buffer value. Note that this is only + // valid so long as the `bytes` instance remains alive and so generally should not outlive the + // lifetime of the `bytes` instance. + // NOLINTNEXTLINE(google-explicit-constructor) + operator std::string_view() const { + char *buffer = nullptr; + ssize_t length = 0; + if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length)) + pybind11_fail("Unable to extract bytes contents!"); + return {buffer, static_cast(length)}; + } +#endif + }; // Note: breathe >= 4.17.0 will fail to build docs if the below two constructors // are included in the doxygen group; close here and reopen after as a workaround @@ -1714,6 +1752,13 @@ public: static memoryview from_memory(const void *mem, ssize_t size) { return memoryview::from_memory(const_cast(mem), size, true); } + +#ifdef PYBIND11_HAS_STRING_VIEW + static memoryview from_memory(std::string_view mem) { + return from_memory(const_cast(mem.data()), static_cast(mem.size()), true); + } +#endif + #endif }; diff --git a/tests/test_builtin_casters.cpp b/tests/test_builtin_casters.cpp index 71c778e8e..fe629e7c3 100644 --- a/tests/test_builtin_casters.cpp +++ b/tests/test_builtin_casters.cpp @@ -140,11 +140,35 @@ TEST_SUBMODULE(builtin_casters, m) { 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"); }); + // The inner lambdas here are to also test implicit conversion + using namespace std::literals; + m.def("string_view_bytes", []() { return [](py::bytes b) { return b; }("abc \x80\x80 def"sv); }); + m.def("string_view_str", []() { return [](py::str s) { return s; }("abc \342\200\275 def"sv); }); + m.def("string_view_from_bytes", [](const py::bytes &b) { return [](std::string_view s) { return s; }(b); }); +#if PY_MAJOR_VERSION >= 3 + m.def("string_view_memoryview", []() { + static constexpr auto val = "Have some \360\237\216\202"sv; + return py::memoryview::from_memory(val); + }); +#endif + # 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"); }); + m.def("string_view8_str", []() { return py::str{std::u8string_view{u8"abc ‽ def"}}; }); # endif + + struct TypeWithBothOperatorStringAndStringView { + // NOLINTNEXTLINE(google-explicit-constructor) + operator std::string() const { return "success"; } + // NOLINTNEXTLINE(google-explicit-constructor) + operator std::string_view() const { return "failure"; } + }; + m.def("bytes_from_type_with_both_operator_string_and_string_view", + []() { return py::bytes(TypeWithBothOperatorStringAndStringView()); }); + m.def("str_from_type_with_both_operator_string_and_string_view", + []() { return py::str(TypeWithBothOperatorStringAndStringView()); }); #endif // test_integer_casting diff --git a/tests/test_builtin_casters.py b/tests/test_builtin_casters.py index 9c5e17a68..b1f1e395a 100644 --- a/tests/test_builtin_casters.py +++ b/tests/test_builtin_casters.py @@ -206,6 +206,17 @@ def test_string_view(capture): """ ) + assert m.string_view_bytes() == b"abc \x80\x80 def" + assert m.string_view_str() == u"abc ‽ def" + assert m.string_view_from_bytes(u"abc ‽ def".encode("utf-8")) == u"abc ‽ def" + if hasattr(m, "has_u8string"): + assert m.string_view8_str() == u"abc ‽ def" + if not env.PY2: + assert m.string_view_memoryview() == "Have some 🎂".encode() + + assert m.bytes_from_type_with_both_operator_string_and_string_view() == b"success" + assert m.str_from_type_with_both_operator_string_and_string_view() == "success" + def test_integer_casting(): """Issue #929 - out-of-range integer values shouldn't be accepted""" From a224d0cca5f1752acfcdad8e37369e4cda42259e Mon Sep 17 00:00:00 2001 From: Boris Rasin Date: Fri, 3 Dec 2021 21:10:36 +0200 Subject: [PATCH 27/37] fix: vs2022 compilation, issue #3477 (#3497) * fix: vs2022 compilation, issue #3477 * silence warning for python 2.7 * disable warning around mbstowcs call * move disable warning code closer to call site * turn on vs2022 ci test * ci: don't run helpers on Windows 2022 & Python 3.5 * limit workaround for stdlib shipped with vs2022 or later * fix for: limit workaround for stdlib shipped with vs2022 or later * fix 2 for: limit workaround for stdlib shipped with vs2022 or later * comment * ci: add a Windows 2019 run * ci: add Python 2.7 check too Co-authored-by: Henry Schreiner --- .github/workflows/ci.yml | 16 +++++++++++----- include/pybind11/detail/common.h | 8 ++++++++ include/pybind11/embed.h | 12 ++++++++++++ 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dcc61ecd7..8e67baf1c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: strategy: fail-fast: false matrix: - runs-on: [ubuntu-latest, windows-latest, macos-latest] + runs-on: [ubuntu-latest, windows-2022, macos-latest] python: - '2.7' - '3.5' @@ -37,19 +37,24 @@ jobs: # present), or add new keys to an existing matrix element if all the # existing keys match. # - # We support an optional keys: args, for cmake args + # We support an optional key: args, for cmake args include: # Just add a key - runs-on: ubuntu-latest - python: 3.6 + python: '3.6' args: > -DPYBIND11_FINDPYTHON=ON - runs-on: windows-latest - python: 3.6 + python: '3.6' args: > -DPYBIND11_FINDPYTHON=ON - runs-on: macos-latest - python: pypy-2.7 + python: 'pypy-2.7' + # Inject a couple Windows 2019 runs + - runs-on: windows-2019 + python: '3.9' + - runs-on: windows-2019 + python: '2.7' name: "🐍 ${{ matrix.python }} • ${{ matrix.runs-on }} • x64 ${{ matrix.args }}" runs-on: ${{ matrix.runs-on }} @@ -181,6 +186,7 @@ jobs: # setuptools - name: Setuptools helpers test run: pytest tests/extra_setuptools + if: "!(matrix.python == '3.5' && matrix.runs-on == 'windows-2022')" deadsnakes: diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index eb5fb0868..2d57367d0 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -154,6 +154,14 @@ // C4505: 'PySlice_GetIndicesEx': unreferenced local function has been removed (PyPy only) # pragma warning(disable: 4505) # if defined(_DEBUG) && !defined(Py_DEBUG) +// Workaround for a VS 2022 issue. +// NOTE: This workaround knowingly violates the Python.h include order requirement: +// https://docs.python.org/3/c-api/intro.html#include-files +// See https://github.com/pybind/pybind11/pull/3497 for full context. +# include +# if _MSVC_STL_VERSION >= 143 +# include +# endif # define PYBIND11_DEBUG_MARKER # undef _DEBUG # endif diff --git a/include/pybind11/embed.h b/include/pybind11/embed.h index 9843f0f97..af36340f3 100644 --- a/include/pybind11/embed.h +++ b/include/pybind11/embed.h @@ -102,6 +102,13 @@ inline wchar_t *widen_chars(const char *safe_arg) { wchar_t *widened_arg = Py_DecodeLocale(safe_arg, nullptr); #else wchar_t *widened_arg = nullptr; + +// warning C4996: 'mbstowcs': This function or variable may be unsafe. +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4996) +#endif + # if defined(HAVE_BROKEN_MBSTOWCS) && HAVE_BROKEN_MBSTOWCS size_t count = strlen(safe_arg); # else @@ -111,6 +118,11 @@ inline wchar_t *widen_chars(const char *safe_arg) { widened_arg = new wchar_t[count + 1]; mbstowcs(widened_arg, safe_arg, count + 1); } + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + #endif return widened_arg; } From 59aa99860c60bd171b9565e9920f125fdb749267 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Dec 2021 17:12:03 -0500 Subject: [PATCH 28/37] [pre-commit.ci] pre-commit autoupdate (#3533) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/psf/black: 21.11b1 → 21.12b0](https://github.com/psf/black/compare/21.11b1...21.12b0) * Keep blacken-docs in sync Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Aaron Gokaslan --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 601031243..4afbd53ef 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -44,7 +44,7 @@ repos: # Black, the code formatter, natively supports pre-commit - repo: https://github.com/psf/black - rev: 21.11b1 # Keep in sync with blacken-docs + rev: 21.12b0 # Keep in sync with blacken-docs hooks: - id: black @@ -53,7 +53,7 @@ repos: hooks: - id: blacken-docs additional_dependencies: - - black==21.11b1 # keep in sync with black hook + - black==21.12b0 # keep in sync with black hook # Changes tabs to spaces - repo: https://github.com/Lucas-C/pre-commit-hooks From 7516811315c76321e847cf28955937195c577d2f Mon Sep 17 00:00:00 2001 From: Bobby Impollonia Date: Mon, 13 Dec 2021 12:45:33 -0500 Subject: [PATCH 29/37] fix(setup_helpers): ensure ThreadPool is closed (#3548) * Ensure ThreadPool is closed in setup_helpers The ParallelCompile setup helper using a ThreadPool to enable its parallelism. It does not properly close the pool when it is done with it. This can lead to a "Exception ignored in: --- pybind11/setup_helpers.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pybind11/setup_helpers.py b/pybind11/setup_helpers.py index d6d84f672..5b7c9aab1 100644 --- a/pybind11/setup_helpers.py +++ b/pybind11/setup_helpers.py @@ -466,8 +466,14 @@ class ParallelCompile(object): threads = 1 if threads > 1: - for _ in ThreadPool(threads).imap_unordered(_single_compile, objects): - pass + pool = ThreadPool(threads) + # In Python 2, ThreadPool can't be used as a context manager. + # Once we are no longer supporting it, this can be 'with pool:' + try: + for _ in pool.imap_unordered(_single_compile, objects): + pass + finally: + pool.terminate() else: for ob in objects: _single_compile(ob) From d0406c747e9eb79bf7db9473a0da1122600d1866 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 20 Dec 2021 23:11:48 -0500 Subject: [PATCH 30/37] [pre-commit.ci] pre-commit autoupdate (#3563) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v0.910-1 → v0.920](https://github.com/pre-commit/mirrors-mypy/compare/v0.910-1...v0.920) - [github.com/shellcheck-py/shellcheck-py: v0.8.0.1 → v0.8.0.2](https://github.com/shellcheck-py/shellcheck-py/compare/v0.8.0.1...v0.8.0.2) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4afbd53ef..972d2472b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -104,7 +104,7 @@ repos: # Check static types with mypy - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.910-1 + rev: v0.920 hooks: - id: mypy # Running per-file misbehaves a bit, so just run on all files, it's fast @@ -128,7 +128,7 @@ repos: args: ["-L", "nd,ot,thist"] - repo: https://github.com/shellcheck-py/shellcheck-py - rev: v0.8.0.1 + rev: v0.8.0.2 hooks: - id: shellcheck From b3d9c3543dcbebde30185c163208b8a00793ae45 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 21 Dec 2021 11:23:49 -0800 Subject: [PATCH 31/37] vi: replacing currently broken ICC Latest C++17 with C++14. (#3551) * Trivial change. * Trying ICC Latest C++14 instead of C++17. * Trying ICC Latest C++20 instead of C++17. * Settling on ICC Latest C++14 for now. * Undoing trivial change. * ci: try using SETUPTOOLS_USE_DISTUTILS=stdlib Co-authored-by: Henry Schreiner --- .github/workflows/ci.yml | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8e67baf1c..f256f0509 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -247,6 +247,8 @@ jobs: python -m pip install -r tests/requirements.txt - name: Configure + env: + SETUPTOOLS_USE_DISTUTILS: stdlib run: > cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug @@ -555,37 +557,37 @@ jobs: set +e; source /opt/intel/oneapi/setvars.sh; set -e cmake --build build-11 --target test_cmake_build - - name: Configure C++17 + - name: Configure C++14 run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e - cmake -S . -B build-17 \ + cmake -S . -B build-14 \ -DPYBIND11_WERROR=ON \ -DDOWNLOAD_CATCH=ON \ -DDOWNLOAD_EIGEN=OFF \ - -DCMAKE_CXX_STANDARD=17 \ + -DCMAKE_CXX_STANDARD=14 \ -DCMAKE_CXX_COMPILER=$(which icpc) \ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - - name: Build C++17 + - name: Build C++14 run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e - cmake --build build-17 -j 2 -v + cmake --build build-14 -j 2 -v - - name: Python tests C++17 + - name: Python tests C++14 run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e sudo service apport stop - cmake --build build-17 --target check + cmake --build build-14 --target check - - name: C++ tests C++17 + - name: C++ tests C++14 run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e - cmake --build build-17 --target cpptest + cmake --build build-14 --target cpptest - - name: Interface test C++17 + - name: Interface test C++14 run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e - cmake --build build-17 --target test_cmake_build + cmake --build build-14 --target test_cmake_build # Testing on CentOS (manylinux uses a centos base, and this is an easy way From 39fbc7992b28188aac6bbcfa7d7814b217f54674 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Tue, 21 Dec 2021 14:24:21 -0500 Subject: [PATCH 32/37] fix: avoiding usage of _ if already defined (#3423) * fix: avoid usage of _ * ci: test _ defined * docs: include change in docs * fix: add a test and comment * refactor: const_str -> const_name --- .github/workflows/ci.yml | 4 ++- docs/advanced/cast/custom.rst | 2 +- docs/upgrade.rst | 4 +++ include/pybind11/cast.h | 30 +++++++++++----------- include/pybind11/chrono.h | 4 +-- include/pybind11/complex.h | 2 +- include/pybind11/detail/descr.h | 28 ++++++++++++-------- include/pybind11/detail/init.h | 2 +- include/pybind11/detail/type_caster_base.h | 2 +- include/pybind11/eigen.h | 20 +++++++-------- include/pybind11/functional.h | 4 +-- include/pybind11/numpy.h | 28 ++++++++++---------- include/pybind11/pybind11.h | 2 +- include/pybind11/pytypes.h | 2 +- include/pybind11/stl.h | 12 ++++----- include/pybind11/stl/filesystem.h | 2 +- tests/pybind11_tests.h | 2 +- tests/test_builtin_casters.cpp | 2 +- tests/test_copy_move.cpp | 6 ++--- tests/test_custom_type_casters.cpp | 11 +++++--- 20 files changed, 94 insertions(+), 75 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f256f0509..7176614de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,6 +44,7 @@ jobs: python: '3.6' args: > -DPYBIND11_FINDPYTHON=ON + -DCMAKE_CXX_FLAGS="-D_=1" - runs-on: windows-latest python: '3.6' args: > @@ -68,7 +69,8 @@ jobs: python-version: ${{ matrix.python }} - name: Setup Boost (Linux) - if: runner.os == 'Linux' + # Can't use boost + define _ + if: runner.os == 'Linux' && matrix.python != '3.6' run: sudo apt-get install libboost-dev - name: Setup Boost (macOS) diff --git a/docs/advanced/cast/custom.rst b/docs/advanced/cast/custom.rst index 19b935347..1df4d3e14 100644 --- a/docs/advanced/cast/custom.rst +++ b/docs/advanced/cast/custom.rst @@ -46,7 +46,7 @@ type is explicitly allowed. * function signatures and declares a local variable * 'value' of type inty */ - PYBIND11_TYPE_CASTER(inty, _("inty")); + PYBIND11_TYPE_CASTER(inty, const_name("inty")); /** * Conversion part 1 (Python->C++): convert a PyObject into a inty diff --git a/docs/upgrade.rst b/docs/upgrade.rst index 69609ca28..d91d51e6f 100644 --- a/docs/upgrade.rst +++ b/docs/upgrade.rst @@ -17,6 +17,10 @@ v2.9 converted to using ``py::module_::import("types").attr("SimpleNamespace")`` instead. +* The use of ``_`` in custom type casters can now be replaced with the more + readable ``const_name`` instead. The old ``_`` shortcut has been retained + unless it is being used as a macro (like for gettext). + .. _upgrade-guide-2.7: diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 01dc5df73..7930fb994 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -208,7 +208,7 @@ public: return PyLong_FromUnsignedLongLong((unsigned long long) src); } - PYBIND11_TYPE_CASTER(T, _::value>("int", "float")); + PYBIND11_TYPE_CASTER(T, const_name::value>("int", "float")); }; template struct void_caster { @@ -221,7 +221,7 @@ public: static handle cast(T, return_value_policy /* policy */, handle /* parent */) { return none().inc_ref(); } - PYBIND11_TYPE_CASTER(T, _("None")); + PYBIND11_TYPE_CASTER(T, const_name("None")); }; template <> class type_caster : public void_caster {}; @@ -264,7 +264,7 @@ public: template using cast_op_type = void*&; explicit operator void *&() { return value; } - static constexpr auto name = _("capsule"); + static constexpr auto name = const_name("capsule"); private: void *value = nullptr; }; @@ -315,7 +315,7 @@ public: static handle cast(bool src, return_value_policy /* policy */, handle /* parent */) { return handle(src ? Py_True : Py_False).inc_ref(); } - PYBIND11_TYPE_CASTER(bool, _("bool")); + PYBIND11_TYPE_CASTER(bool, const_name("bool")); }; // Helper class for UTF-{8,16,32} C++ stl strings: @@ -405,7 +405,7 @@ template struct string_caster { return s; } - PYBIND11_TYPE_CASTER(StringType, _(PYBIND11_STRING_NAME)); + PYBIND11_TYPE_CASTER(StringType, const_name(PYBIND11_STRING_NAME)); private: static handle decode_utfN(const char *buffer, ssize_t nbytes) { @@ -542,7 +542,7 @@ public: return one_char; } - static constexpr auto name = _(PYBIND11_STRING_NAME); + static constexpr auto name = const_name(PYBIND11_STRING_NAME); template using cast_op_type = pybind11::detail::cast_op_type<_T>; }; @@ -579,7 +579,7 @@ public: return cast(*src, policy, parent); } - static constexpr auto name = _("Tuple[") + concat(make_caster::name...) + _("]"); + static constexpr auto name = const_name("Tuple[") + concat(make_caster::name...) + const_name("]"); template using cast_op_type = type; @@ -764,14 +764,14 @@ template struct is_holder_type : template struct is_holder_type> : std::true_type {}; -template 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 = _("None"); }; -template <> struct handle_type_name { static constexpr auto name = _("*args"); }; -template <> struct handle_type_name { static constexpr auto name = _("**kwargs"); }; +template struct handle_type_name { static constexpr auto name = const_name(); }; +template <> struct handle_type_name { static constexpr auto name = const_name(PYBIND11_BYTES_NAME); }; +template <> struct handle_type_name { static constexpr auto name = const_name("int"); }; +template <> struct handle_type_name { static constexpr auto name = const_name("Iterable"); }; +template <> struct handle_type_name { static constexpr auto name = const_name("Iterator"); }; +template <> struct handle_type_name { static constexpr auto name = const_name("None"); }; +template <> struct handle_type_name { static constexpr auto name = const_name("*args"); }; +template <> struct handle_type_name { static constexpr auto name = const_name("**kwargs"); }; template struct pyobject_caster { diff --git a/include/pybind11/chrono.h b/include/pybind11/chrono.h index 61bbcbc54..007cc17b4 100644 --- a/include/pybind11/chrono.h +++ b/include/pybind11/chrono.h @@ -97,7 +97,7 @@ public: return PyDelta_FromDSU(dd.count(), ss.count(), us.count()); } - PYBIND11_TYPE_CASTER(type, _("datetime.timedelta")); + PYBIND11_TYPE_CASTER(type, const_name("datetime.timedelta")); }; inline std::tm *localtime_thread_safe(const std::time_t *time, std::tm *buf) { @@ -195,7 +195,7 @@ public: localtime.tm_sec, us.count()); } - PYBIND11_TYPE_CASTER(type, _("datetime.datetime")); + PYBIND11_TYPE_CASTER(type, const_name("datetime.datetime")); }; // Other clocks that are not the system clock are not measured as datetime.datetime objects diff --git a/include/pybind11/complex.h b/include/pybind11/complex.h index f8327eb37..e1ecf4358 100644 --- a/include/pybind11/complex.h +++ b/include/pybind11/complex.h @@ -59,7 +59,7 @@ public: return PyComplex_FromDoubles((double) src.real(), (double) src.imag()); } - PYBIND11_TYPE_CASTER(std::complex, _("complex")); + PYBIND11_TYPE_CASTER(std::complex, const_name("complex")); }; PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/include/pybind11/detail/descr.h b/include/pybind11/detail/descr.h index c62e541bd..ee72eccfe 100644 --- a/include/pybind11/detail/descr.h +++ b/include/pybind11/detail/descr.h @@ -53,9 +53,17 @@ constexpr descr operator+(const descr &a, c return plus_impl(a, b, make_index_sequence(), make_index_sequence()); } +template +constexpr descr const_name(char const(&text)[N]) { return descr(text); } +constexpr descr<0> const_name(char const(&)[1]) { return {}; } + +// The "_" might be defined as a macro - don't define it if so. +// Repeating the const_name code to avoid introducing a #define. +#ifndef _ template constexpr descr _(char const(&text)[N]) { return descr(text); } constexpr descr<0> _(char const(&)[1]) { return {}; } +#endif template struct int_to_str : int_to_str { }; template struct int_to_str<0, Digits...> { @@ -64,25 +72,25 @@ template struct int_to_str<0, Digits...> { // Ternary description (like std::conditional) template -constexpr enable_if_t> _(char const(&text1)[N1], char const(&)[N2]) { - return _(text1); +constexpr enable_if_t> const_name(char const(&text1)[N1], char const(&)[N2]) { + return const_name(text1); } template -constexpr enable_if_t> _(char const(&)[N1], char const(&text2)[N2]) { - return _(text2); +constexpr enable_if_t> const_name(char const(&)[N1], char const(&text2)[N2]) { + return const_name(text2); } template -constexpr enable_if_t _(const T1 &d, const T2 &) { return d; } +constexpr enable_if_t const_name(const T1 &d, const T2 &) { return d; } template -constexpr enable_if_t _(const T1 &, const T2 &d) { return d; } +constexpr enable_if_t const_name(const T1 &, const T2 &d) { return d; } template -auto constexpr _() -> remove_cv_t::digits)> { +auto constexpr const_name() -> remove_cv_t::digits)> { return int_to_str::digits; } -template constexpr descr<1, Type> _() { return {'%'}; } +template constexpr descr<1, Type> const_name() { return {'%'}; } constexpr descr<0> concat() { return {}; } @@ -92,12 +100,12 @@ constexpr descr concat(const descr &descr) { return descr; } template constexpr auto concat(const descr &d, const Args &...args) -> decltype(std::declval>() + concat(args...)) { - return d + _(", ") + concat(args...); + return d + const_name(", ") + concat(args...); } template constexpr descr type_descr(const descr &descr) { - return _("{") + descr + _("}"); + return const_name("{") + descr + const_name("}"); } PYBIND11_NAMESPACE_END(detail) diff --git a/include/pybind11/detail/init.h b/include/pybind11/detail/init.h index cace35296..eaaad5a07 100644 --- a/include/pybind11/detail/init.h +++ b/include/pybind11/detail/init.h @@ -24,7 +24,7 @@ public: template using cast_op_type = value_and_holder &; explicit operator value_and_holder &() { return *value; } - static constexpr auto name = _(); + static constexpr auto name = const_name(); private: value_and_holder *value = nullptr; diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h index 00ce1a7a1..48e218b2f 100644 --- a/include/pybind11/detail/type_caster_base.h +++ b/include/pybind11/detail/type_caster_base.h @@ -897,7 +897,7 @@ template class type_caster_base : public type_caster_generic { using itype = intrinsic_t; public: - static constexpr auto name = _(); + static constexpr auto name = const_name(); type_caster_base() : type_caster_base(typeid(type)) { } explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) { } diff --git a/include/pybind11/eigen.h b/include/pybind11/eigen.h index 965d66e8a..696099fa6 100644 --- a/include/pybind11/eigen.h +++ b/include/pybind11/eigen.h @@ -192,20 +192,20 @@ template struct EigenProps { static constexpr bool show_f_contiguous = !show_c_contiguous && show_order && requires_col_major; static constexpr auto descriptor = - _("numpy.ndarray[") + npy_format_descriptor::name + - _("[") + _(_<(size_t) rows>(), _("m")) + - _(", ") + _(_<(size_t) cols>(), _("n")) + - _("]") + + const_name("numpy.ndarray[") + npy_format_descriptor::name + + const_name("[") + const_name(const_name<(size_t) rows>(), const_name("m")) + + const_name(", ") + const_name(const_name<(size_t) cols>(), const_name("n")) + + const_name("]") + // For a reference type (e.g. Ref) we have other constraints that might need to be // satisfied: writeable=True (for a mutable reference), and, depending on the map's stride // options, possibly f_contiguous or c_contiguous. We include them in the descriptor output // to provide some hint as to why a TypeError is occurring (otherwise it can be confusing to // see that a function accepts a 'numpy.ndarray[float64[3,2]]' and an error message that you // *gave* a numpy.ndarray of the right type and dimensions. - _(", flags.writeable", "") + - _(", flags.c_contiguous", "") + - _(", flags.f_contiguous", "") + - _("]"); + const_name(", flags.writeable", "") + + const_name(", flags.c_contiguous", "") + + const_name(", flags.f_contiguous", "") + + const_name("]"); }; // Casts an Eigen type to numpy array. If given a base, the numpy array references the src data, @@ -600,8 +600,8 @@ struct type_caster::value>> { ).release(); } - PYBIND11_TYPE_CASTER(Type, _<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[", "scipy.sparse.csc_matrix[") - + npy_format_descriptor::name + _("]")); + PYBIND11_TYPE_CASTER(Type, const_name<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[", "scipy.sparse.csc_matrix[") + + npy_format_descriptor::name + const_name("]")); }; PYBIND11_NAMESPACE_END(detail) diff --git a/include/pybind11/functional.h b/include/pybind11/functional.h index ad5608c25..7912aef17 100644 --- a/include/pybind11/functional.h +++ b/include/pybind11/functional.h @@ -113,8 +113,8 @@ public: return cpp_function(std::forward(f_), policy).release(); } - PYBIND11_TYPE_CASTER(type, _("Callable[[") + concat(make_caster::name...) + _("], ") - + make_caster::name + _("]")); + PYBIND11_TYPE_CASTER(type, const_name("Callable[[") + concat(make_caster::name...) + const_name("], ") + + make_caster::name + const_name("]")); }; PYBIND11_NAMESPACE_END(detail) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index b43a77168..8e83b506e 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -39,7 +39,7 @@ class array; // Forward declaration PYBIND11_NAMESPACE_BEGIN(detail) -template <> struct handle_type_name { static constexpr auto name = _("numpy.ndarray"); }; +template <> struct handle_type_name { static constexpr auto name = const_name("numpy.ndarray"); }; template struct npy_format_descriptor; @@ -290,7 +290,7 @@ template struct array_info_scalar { using type = T; static constexpr bool is_array = false; static constexpr bool is_empty = false; - static constexpr auto extents = _(""); + static constexpr auto extents = const_name(""); static void append_extents(list& /* shape */) { } }; // Computes underlying type and a comma-separated list of extents for array @@ -309,8 +309,8 @@ template struct array_info> { array_info::append_extents(shape); } - static constexpr auto extents = _::is_array>( - concat(_(), array_info::extents), _() + static constexpr auto extents = const_name::is_array>( + concat(const_name(), array_info::extents), const_name() ); }; // For numpy we have special handling for arrays of characters, so we don't include @@ -1021,7 +1021,7 @@ template struct format_descriptor::is_array>> { static std::string format() { using namespace detail; - static constexpr auto extents = _("(") + array_info::extents + _(")"); + static constexpr auto extents = const_name("(") + array_info::extents + const_name(")"); return extents.text + format_descriptor>::format(); } }; @@ -1056,28 +1056,28 @@ struct npy_format_descriptor_name; template struct npy_format_descriptor_name::value>> { - static constexpr auto name = _::value>( - _("bool"), _::value>("numpy.int", "numpy.uint") + _() + static constexpr auto name = const_name::value>( + const_name("bool"), const_name::value>("numpy.int", "numpy.uint") + const_name() ); }; template struct npy_format_descriptor_name::value>> { - static constexpr auto name = _::value + static constexpr auto name = const_name::value || std::is_same::value || std::is_same::value || std::is_same::value>( - _("numpy.float") + _(), _("numpy.longdouble") + const_name("numpy.float") + const_name(), const_name("numpy.longdouble") ); }; template struct npy_format_descriptor_name::value>> { - static constexpr auto name = _::value + static constexpr auto name = const_name::value || std::is_same::value || std::is_same::value || std::is_same::value>( - _("numpy.complex") + _(), _("numpy.longcomplex") + const_name("numpy.complex") + const_name(), const_name("numpy.longcomplex") ); }; @@ -1105,7 +1105,7 @@ public: }; #define PYBIND11_DECL_CHAR_FMT \ - static constexpr auto name = _("S") + _(); \ + static constexpr auto name = const_name("S") + const_name(); \ static pybind11::dtype dtype() { return pybind11::dtype(std::string("S") + std::to_string(N)); } template struct npy_format_descriptor { PYBIND11_DECL_CHAR_FMT }; template struct npy_format_descriptor> { PYBIND11_DECL_CHAR_FMT }; @@ -1117,7 +1117,7 @@ private: public: static_assert(!array_info::is_empty, "Zero-sized arrays are not supported"); - static constexpr auto name = _("(") + array_info::extents + _(")") + base_descr::name; + static constexpr auto name = const_name("(") + array_info::extents + const_name(")") + base_descr::name; static pybind11::dtype dtype() { list shape; array_info::append_extents(shape); @@ -1705,7 +1705,7 @@ vectorize_extractor(const Func &f, Return (*) (Args ...)) { } template struct handle_type_name> { - static constexpr auto name = _("numpy.ndarray[") + npy_format_descriptor::name + _("]"); + static constexpr auto name = const_name("numpy.ndarray[") + npy_format_descriptor::name + const_name("]"); }; PYBIND11_NAMESPACE_END(detail) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index cfe03f6db..8c7545ba3 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -262,7 +262,7 @@ protected: } /* Generate a readable signature describing the function's arguments and return value types */ - static constexpr auto signature = _("(") + cast_in::arg_names + _(") -> ") + cast_out::name; + static constexpr auto signature = const_name("(") + cast_in::arg_names + const_name(") -> ") + cast_out::name; PYBIND11_DESCR_CONSTEXPR auto types = decltype(signature)::types(); /* Register the function with Python from generic (non-templated) code */ diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index f803a05ca..902fb1f07 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -435,7 +435,7 @@ inline void raise_from(error_already_set& err, PyObject *type, const char *messa #endif -/** \defgroup python_builtins _ +/** \defgroup python_builtins const_name Unless stated otherwise, the following C++ functions behave the same as their Python counterparts. */ diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h index 3608d2989..430349482 100644 --- a/include/pybind11/stl.h +++ b/include/pybind11/stl.h @@ -78,7 +78,7 @@ template struct set_caster { return s.release(); } - PYBIND11_TYPE_CASTER(type, _("Set[") + key_conv::name + _("]")); + PYBIND11_TYPE_CASTER(type, const_name("Set[") + key_conv::name + const_name("]")); }; template struct map_caster { @@ -120,7 +120,7 @@ template struct map_caster { return d.release(); } - PYBIND11_TYPE_CASTER(Type, _("Dict[") + key_conv::name + _(", ") + value_conv::name + _("]")); + PYBIND11_TYPE_CASTER(Type, const_name("Dict[") + key_conv::name + const_name(", ") + value_conv::name + const_name("]")); }; template struct list_caster { @@ -166,7 +166,7 @@ public: return l.release(); } - PYBIND11_TYPE_CASTER(Type, _("List[") + value_conv::name + _("]")); + PYBIND11_TYPE_CASTER(Type, const_name("List[") + value_conv::name + const_name("]")); }; template struct type_caster> @@ -223,7 +223,7 @@ public: return l.release(); } - PYBIND11_TYPE_CASTER(ArrayType, _("List[") + value_conv::name + _(_(""), _("[") + _() + _("]")) + _("]")); + PYBIND11_TYPE_CASTER(ArrayType, const_name("List[") + value_conv::name + const_name(const_name(""), const_name("[") + const_name() + const_name("]")) + const_name("]")); }; template struct type_caster> @@ -273,7 +273,7 @@ template struct optio return true; } - PYBIND11_TYPE_CASTER(Type, _("Optional[") + value_conv::name + _("]")); + PYBIND11_TYPE_CASTER(Type, const_name("Optional[") + value_conv::name + const_name("]")); }; #if defined(PYBIND11_HAS_OPTIONAL) @@ -353,7 +353,7 @@ struct variant_caster> { } using Type = V; - PYBIND11_TYPE_CASTER(Type, _("Union[") + detail::concat(make_caster::name...) + _("]")); + PYBIND11_TYPE_CASTER(Type, const_name("Union[") + detail::concat(make_caster::name...) + const_name("]")); }; #if defined(PYBIND11_HAS_VARIANT) diff --git a/include/pybind11/stl/filesystem.h b/include/pybind11/stl/filesystem.h index 431b94b4f..a9a6c8512 100644 --- a/include/pybind11/stl/filesystem.h +++ b/include/pybind11/stl/filesystem.h @@ -92,7 +92,7 @@ public: return true; } - PYBIND11_TYPE_CASTER(T, _("os.PathLike")); + PYBIND11_TYPE_CASTER(T, const_name("os.PathLike")); }; template<> struct type_caster diff --git a/tests/pybind11_tests.h b/tests/pybind11_tests.h index 800ddda48..9b9992323 100644 --- a/tests/pybind11_tests.h +++ b/tests/pybind11_tests.h @@ -65,7 +65,7 @@ PYBIND11_NAMESPACE_BEGIN(pybind11) PYBIND11_NAMESPACE_BEGIN(detail) template<> class type_caster { public: - PYBIND11_TYPE_CASTER(RValueCaster, _("RValueCaster")); + PYBIND11_TYPE_CASTER(RValueCaster, const_name("RValueCaster")); static handle cast(RValueCaster &&, return_value_policy, handle) { return py::str("rvalue").release(); } static handle cast(const RValueCaster &, return_value_policy, handle) { return py::str("lvalue").release(); } }; diff --git a/tests/test_builtin_casters.cpp b/tests/test_builtin_casters.cpp index fe629e7c3..4a9f33837 100644 --- a/tests/test_builtin_casters.cpp +++ b/tests/test_builtin_casters.cpp @@ -19,7 +19,7 @@ PYBIND11_NAMESPACE_BEGIN(detail) template <> class type_caster { public: - static constexpr auto name = _(); + static constexpr auto name = const_name(); // Input is unimportant, a new value will always be constructed based on the // cast operator. diff --git a/tests/test_copy_move.cpp b/tests/test_copy_move.cpp index 5fb0dd810..4711a9482 100644 --- a/tests/test_copy_move.cpp +++ b/tests/test_copy_move.cpp @@ -85,13 +85,13 @@ public: PYBIND11_NAMESPACE_BEGIN(pybind11) PYBIND11_NAMESPACE_BEGIN(detail) template <> struct type_caster { - PYBIND11_TYPE_CASTER(MoveOnlyInt, _("MoveOnlyInt")); + PYBIND11_TYPE_CASTER(MoveOnlyInt, const_name("MoveOnlyInt")); bool load(handle src, bool) { value = MoveOnlyInt(src.cast()); return true; } static handle cast(const MoveOnlyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); } }; template <> struct type_caster { - PYBIND11_TYPE_CASTER(MoveOrCopyInt, _("MoveOrCopyInt")); + PYBIND11_TYPE_CASTER(MoveOrCopyInt, const_name("MoveOrCopyInt")); bool load(handle src, bool) { value = MoveOrCopyInt(src.cast()); return true; } static handle cast(const MoveOrCopyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); } }; @@ -100,7 +100,7 @@ template <> struct type_caster { protected: CopyOnlyInt value; public: - static constexpr auto name = _("CopyOnlyInt"); + static constexpr auto name = const_name("CopyOnlyInt"); bool load(handle src, bool) { value = CopyOnlyInt(src.cast()); return true; } static handle cast(const CopyOnlyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); } static handle cast(const CopyOnlyInt *src, return_value_policy policy, handle parent) { diff --git a/tests/test_custom_type_casters.cpp b/tests/test_custom_type_casters.cpp index 076777d6f..8ad584de6 100644 --- a/tests/test_custom_type_casters.cpp +++ b/tests/test_custom_type_casters.cpp @@ -18,7 +18,12 @@ class ArgAlwaysConverts { }; namespace pybind11 { namespace detail { template <> struct type_caster { public: + // Classic +#ifndef _ PYBIND11_TYPE_CASTER(ArgInspector1, _("ArgInspector1")); +#else + PYBIND11_TYPE_CASTER(ArgInspector1, const_name("ArgInspector1")); +#endif bool load(handle src, bool convert) { value.arg = "loading ArgInspector1 argument " + @@ -33,7 +38,7 @@ public: }; template <> struct type_caster { public: - PYBIND11_TYPE_CASTER(ArgInspector2, _("ArgInspector2")); + PYBIND11_TYPE_CASTER(ArgInspector2, const_name("ArgInspector2")); bool load(handle src, bool convert) { value.arg = "loading ArgInspector2 argument " + @@ -48,7 +53,7 @@ public: }; template <> struct type_caster { public: - PYBIND11_TYPE_CASTER(ArgAlwaysConverts, _("ArgAlwaysConverts")); + PYBIND11_TYPE_CASTER(ArgAlwaysConverts, const_name("ArgAlwaysConverts")); bool load(handle, bool convert) { return convert; @@ -76,7 +81,7 @@ public: }; namespace pybind11 { namespace detail { template <> struct type_caster { - PYBIND11_TYPE_CASTER(DestructionTester, _("DestructionTester")); + PYBIND11_TYPE_CASTER(DestructionTester, const_name("DestructionTester")); bool load(handle, bool) { return true; } static handle cast(const DestructionTester &, return_value_policy, handle) { From e50f841de040a9455b2d76dc395c369869c89cdf Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Tue, 21 Dec 2021 15:42:34 -0500 Subject: [PATCH 33/37] fix: do not use LTS on mips64 and ppc64le (#3557) --- tools/pybind11Common.cmake | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/pybind11Common.cmake b/tools/pybind11Common.cmake index 69ac4b0f6..df2478121 100644 --- a/tools/pybind11Common.cmake +++ b/tools/pybind11Common.cmake @@ -318,13 +318,21 @@ function(_pybind11_generate_lto target prefer_thin_lto) set(cxx_append ";-fno-fat-lto-objects") endif() - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND prefer_thin_lto) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64le" OR CMAKE_SYSTEM_PROCESSOR MATCHES "mips64") + set(NO_FLTO_ARCH TRUE) + else() + set(NO_FLTO_ARCH FALSE) + endif() + + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" + AND prefer_thin_lto + AND NOT NO_FLTO_ARCH) _pybind11_return_if_cxx_and_linker_flags_work( HAS_FLTO_THIN "-flto=thin${cxx_append}" "-flto=thin${linker_append}" PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) endif() - if(NOT HAS_FLTO_THIN) + if(NOT HAS_FLTO_THIN AND NOT NO_FLTO_ARCH) _pybind11_return_if_cxx_and_linker_flags_work( HAS_FLTO "-flto${cxx_append}" "-flto${linker_append}" PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) From d4b9f3471f465f0cc6d05556a837c26589b08b29 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Tue, 21 Dec 2021 16:28:23 -0500 Subject: [PATCH 34/37] docs: update changelog (#3556) * docs: update changelog * Update changelog.rst * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- docs/changelog.rst | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index dff8ec808..87fce2f2b 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -10,6 +10,8 @@ Starting with version 1.8.0, pybind11 releases use a `semantic versioning IN DEVELOPMENT -------------- +This is the last version to support Python 2.7 and 3.5. + New Features: * Allow ``py::args`` to be followed by other arguments; the remaining arguments @@ -21,6 +23,16 @@ New Features: defining custom ``__setattr__`` and ``__getattr__`` methods. `#3387 `_ +Changes: + +* Make str/bytes/memoryview more interoperable with ``std::string_view``. + `#3521 `_ + +* Replace ``_`` with ``const_name`` in internals, avoid defining ``pybind::_`` + if ``_`` defined as macro (common gettext usage) + `#3423 `_ + + Bug fixes: * Fix a regression in 2.8.0 that caused undefined behavior (typically @@ -37,7 +49,8 @@ Bug fixes: * Add missing ``std::forward`` calls to some ``cpp_function`` overloads. `#3443 `_ -* Support PyPy 7.3.7 and the PyPy3.8 beta. Test python-3.11 on PRs with the ``python dev`` label. +* Support PyPy 7.3.7 and the PyPy3.8 beta. Test python-3.11 on PRs with the + ``python dev`` label. `#3419 `_ * Fix 2.8.0 regression with MSVC 2017 + C++17 mode + Python 3. @@ -59,6 +72,9 @@ Bug fixes: ``std::optional`` types. `#3376 `_ +* Tweaks to support Microsoft Visual Studio 2022. + `#3497 `_ + Build system improvements: * Nicer CMake printout and IDE organisation for pybind11's own tests. @@ -79,6 +95,12 @@ Build system improvements: overridden by ``.Pybind11Extension``. `#3436 `_ +* Ensure ThreadPool is closed in ``setup_helpers``. + `#3548 `_ + +* Avoid LTS on ``mips64`` and ``ppc64le`` (reported broken). + `#3557 `_ + v2.8.1 (Oct 27, 2021) --------------------- From cb302305a3d2697f8af17a14c5bf78f45359fb56 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Thu, 23 Dec 2021 14:50:10 -0500 Subject: [PATCH 35/37] fix: restore full range of _ functions (#3571) --- include/pybind11/detail/descr.h | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/include/pybind11/detail/descr.h b/include/pybind11/detail/descr.h index ee72eccfe..14f9223a5 100644 --- a/include/pybind11/detail/descr.h +++ b/include/pybind11/detail/descr.h @@ -57,14 +57,6 @@ template constexpr descr const_name(char const(&text)[N]) { return descr(text); } constexpr descr<0> const_name(char const(&)[1]) { return {}; } -// The "_" might be defined as a macro - don't define it if so. -// Repeating the const_name code to avoid introducing a #define. -#ifndef _ -template -constexpr descr _(char const(&text)[N]) { return descr(text); } -constexpr descr<0> _(char const(&)[1]) { return {}; } -#endif - template struct int_to_str : int_to_str { }; template struct int_to_str<0, Digits...> { static constexpr auto digits = descr(('0' + Digits)...); @@ -92,6 +84,31 @@ auto constexpr const_name() -> remove_cv_t constexpr descr<1, Type> const_name() { return {'%'}; } +// The "_" might be defined as a macro - don't define it if so. +// Repeating the const_name code to avoid introducing a #define. +#ifndef _ +template +constexpr descr _(char const(&text)[N]) { return const_name(text); } +template +constexpr enable_if_t> _(char const(&text1)[N1], char const(&text2)[N2]) { + return const_name(text1, text2); +} +template +constexpr enable_if_t> _(char const(&text1)[N1], char const(&text2)[N2]) { + return const_name(text1, text2); +} +template +constexpr enable_if_t _(const T1 &d1, const T2 &d2) { return const_name(d1, d2); } +template +constexpr enable_if_t _(const T1 &d1, const T2 &d2) { return const_name(d1, d2); } + +template +auto constexpr _() -> remove_cv_t::digits)> { + return const_name(); +} +template constexpr descr<1, Type> _() { return const_name(); } +#endif + constexpr descr<0> concat() { return {}; } template From 89769e6e6da425546c00a45ba19f63e5437901c4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 27 Dec 2021 18:28:30 -0500 Subject: [PATCH 36/37] [pre-commit.ci] pre-commit autoupdate (#3574) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.0.1 → v4.1.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.0.1...v4.1.0) - [github.com/pre-commit/mirrors-mypy: v0.920 → v0.930](https://github.com/pre-commit/mirrors-mypy/compare/v0.920...v0.930) - [github.com/shellcheck-py/shellcheck-py: v0.8.0.2 → v0.8.0.3](https://github.com/shellcheck-py/shellcheck-py/compare/v0.8.0.2...v0.8.0.3) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 972d2472b..3a6583ccf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: # Standard hooks - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.0.1 + rev: v4.1.0 hooks: - id: check-added-large-files - id: check-case-conflict @@ -104,7 +104,7 @@ repos: # Check static types with mypy - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.920 + rev: v0.930 hooks: - id: mypy # Running per-file misbehaves a bit, so just run on all files, it's fast @@ -128,7 +128,7 @@ repos: args: ["-L", "nd,ot,thist"] - repo: https://github.com/shellcheck-py/shellcheck-py - rev: v0.8.0.2 + rev: v0.8.0.3 hooks: - id: shellcheck From 45f792efdd92da094548e2095d6efdbfa7e536ee Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Tue, 28 Dec 2021 10:47:21 -0500 Subject: [PATCH 37/37] chore: prepare for 2.9 --- docs/changelog.rst | 4 ++-- include/pybind11/detail/common.h | 4 ++-- pybind11/_version.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 87fce2f2b..cc3f70efb 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -7,8 +7,8 @@ Starting with version 1.8.0, pybind11 releases use a `semantic versioning `_ policy. -IN DEVELOPMENT --------------- +Version 2.9.0 (Dec 28, 2021) +---------------------------- This is the last version to support Python 2.7 and 3.5. diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 2d57367d0..b08bbc559 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -11,11 +11,11 @@ #define PYBIND11_VERSION_MAJOR 2 #define PYBIND11_VERSION_MINOR 9 -#define PYBIND11_VERSION_PATCH 0.dev1 +#define PYBIND11_VERSION_PATCH 0 // Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html // Additional convention: 0xD = dev -#define PYBIND11_VERSION_HEX 0x020900D1 +#define PYBIND11_VERSION_HEX 0x02090000 #define PYBIND11_NAMESPACE_BEGIN(name) namespace name { #define PYBIND11_NAMESPACE_END(name) } diff --git a/pybind11/_version.py b/pybind11/_version.py index ce894a774..6627d4c7e 100644 --- a/pybind11/_version.py +++ b/pybind11/_version.py @@ -8,5 +8,5 @@ def _to_int(s): return s -__version__ = "2.9.0.dev1" +__version__ = "2.9.0" version_info = tuple(_to_int(s) for s in __version__.split("."))