diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 1101178ed..3c39841fc 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1148,6 +1148,10 @@ inline object handle::operator()(detail::args_proxy args, detail::kwargs_proxy k return result; } +template +dict::dict(Args &&...args) + : dict(detail::unpacking_collector<>(std::forward(args)...).kwargs()) { } + #define PYBIND11_MAKE_OPAQUE(Type) \ namespace pybind11 { namespace detail { \ template<> class type_caster : public type_caster_base { }; \ diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 374f5420b..e25f1a794 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -589,6 +589,9 @@ public: dict() : object(PyDict_New(), false) { if (!m_ptr) pybind11_fail("Could not allocate dict object!"); } + template ::value>> + dict(Args &&...args); size_t size() const { return (size_t) PyDict_Size(m_ptr); } detail::dict_iterator begin() const { return (++detail::dict_iterator(*this, 0)); } detail::dict_iterator end() const { return detail::dict_iterator(); } diff --git a/tests/test_callbacks.cpp b/tests/test_callbacks.cpp index bfb932691..31d4e39aa 100644 --- a/tests/test_callbacks.cpp +++ b/tests/test_callbacks.cpp @@ -89,12 +89,9 @@ test_initializer callbacks([](py::module &m) { }); m.def("test_dict_unpacking", [](py::function f) { - auto d1 = py::dict(); - d1["key"] = py::cast("value"); - d1["a"] = py::cast(1); + auto d1 = py::dict("key"_a="value", "a"_a=1); auto d2 = py::dict(); - auto d3 = py::dict(); - d3["b"] = py::cast(2); + auto d3 = py::dict("b"_a=2); return f("positional", 1, **d1, **d2, **d3); }); @@ -104,30 +101,24 @@ test_initializer callbacks([](py::module &m) { m.def("test_unpacking_and_keywords1", [](py::function f) { auto args = py::make_tuple(2); - auto kwargs = py::dict(); - kwargs["d"] = py::cast(4); + auto kwargs = py::dict("d"_a=4); return f(1, *args, "c"_a=3, **kwargs); }); m.def("test_unpacking_and_keywords2", [](py::function f) { - auto kwargs1 = py::dict(); - kwargs1["a"] = py::cast(1); - auto kwargs2 = py::dict(); - kwargs2["c"] = py::cast(3); - kwargs2["d"] = py::cast(4); + auto kwargs1 = py::dict("a"_a=1); + auto kwargs2 = py::dict("c"_a=3, "d"_a=4); return f("positional", *py::make_tuple(1), 2, *py::make_tuple(3, 4), 5, "key"_a="value", **kwargs1, "b"_a=2, **kwargs2, "e"_a=5); }); m.def("test_unpacking_error1", [](py::function f) { - auto kwargs = py::dict(); - kwargs["x"] = py::cast(3); + auto kwargs = py::dict("x"_a=3); return f("x"_a=1, "y"_a=2, **kwargs); // duplicate ** after keyword }); m.def("test_unpacking_error2", [](py::function f) { - auto kwargs = py::dict(); - kwargs["x"] = py::cast(3); + auto kwargs = py::dict("x"_a=3); return f(**kwargs, "x"_a=1); // duplicate keyword after ** }); diff --git a/tests/test_python_types.cpp b/tests/test_python_types.cpp index 1b462aba0..e527c0a0d 100644 --- a/tests/test_python_types.cpp +++ b/tests/test_python_types.cpp @@ -219,4 +219,10 @@ test_initializer python_types([](py::module &m) { auto s2 = "{a} + {b} = {c}"_s.format("a"_a=1, "b"_a=2, "c"_a=3); return py::make_tuple(s1, s2); }); + + m.def("test_dict_keyword_constructor", []() { + auto d1 = py::dict("x"_a=1, "y"_a=2); + auto d2 = py::dict("z"_a=3, **d1); + return d2; + }); }); diff --git a/tests/test_python_types.py b/tests/test_python_types.py index 369606978..087a9a20d 100644 --- a/tests/test_python_types.py +++ b/tests/test_python_types.py @@ -242,3 +242,9 @@ def test_str_api(): s1, s2 = test_str_format() assert s1 == "1 + 2 = 3" assert s1 == s2 + + +def test_dict_api(): + from pybind11_tests import test_dict_keyword_constructor + + assert test_dict_keyword_constructor() == {"x": 1, "y": 2, "z": 3}