111986Sandreas.sandberg@arm.com/*
211986Sandreas.sandberg@arm.com    tests/test_kwargs_and_defaults.cpp -- keyword arguments and default values
311986Sandreas.sandberg@arm.com
411986Sandreas.sandberg@arm.com    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
511986Sandreas.sandberg@arm.com
611986Sandreas.sandberg@arm.com    All rights reserved. Use of this source code is governed by a
711986Sandreas.sandberg@arm.com    BSD-style license that can be found in the LICENSE file.
811986Sandreas.sandberg@arm.com*/
911986Sandreas.sandberg@arm.com
1011986Sandreas.sandberg@arm.com#include "pybind11_tests.h"
1114299Sbbruce@ucdavis.edu#include "constructor_stats.h"
1211986Sandreas.sandberg@arm.com#include <pybind11/stl.h>
1311986Sandreas.sandberg@arm.com
1412391Sjason@lowepower.comTEST_SUBMODULE(kwargs_and_defaults, m) {
1512391Sjason@lowepower.com    auto kw_func = [](int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); };
1611986Sandreas.sandberg@arm.com
1712391Sjason@lowepower.com    // test_named_arguments
1812391Sjason@lowepower.com    m.def("kw_func0", kw_func);
1912391Sjason@lowepower.com    m.def("kw_func1", kw_func, py::arg("x"), py::arg("y"));
2012391Sjason@lowepower.com    m.def("kw_func2", kw_func, py::arg("x") = 100, py::arg("y") = 200);
2111986Sandreas.sandberg@arm.com    m.def("kw_func3", [](const char *) { }, py::arg("data") = std::string("Hello world!"));
2211986Sandreas.sandberg@arm.com
2311986Sandreas.sandberg@arm.com    /* A fancier default argument */
2412391Sjason@lowepower.com    std::vector<int> list{{13, 17}};
2512391Sjason@lowepower.com    m.def("kw_func4", [](const std::vector<int> &entries) {
2612391Sjason@lowepower.com        std::string ret = "{";
2712391Sjason@lowepower.com        for (int i : entries)
2812391Sjason@lowepower.com            ret += std::to_string(i) + " ";
2912391Sjason@lowepower.com        ret.back() = '}';
3012391Sjason@lowepower.com        return ret;
3112391Sjason@lowepower.com    }, py::arg("myList") = list);
3211986Sandreas.sandberg@arm.com
3312391Sjason@lowepower.com    m.def("kw_func_udl", kw_func, "x"_a, "y"_a=300);
3412391Sjason@lowepower.com    m.def("kw_func_udl_z", kw_func, "x"_a, "y"_a=0);
3511986Sandreas.sandberg@arm.com
3612391Sjason@lowepower.com    // test_args_and_kwargs
3714299Sbbruce@ucdavis.edu    m.def("args_function", [](py::args args) -> py::tuple {
3814299Sbbruce@ucdavis.edu        return std::move(args);
3914299Sbbruce@ucdavis.edu    });
4012391Sjason@lowepower.com    m.def("args_kwargs_function", [](py::args args, py::kwargs kwargs) {
4112391Sjason@lowepower.com        return py::make_tuple(args, kwargs);
4212391Sjason@lowepower.com    });
4311986Sandreas.sandberg@arm.com
4412391Sjason@lowepower.com    // test_mixed_args_and_kwargs
4512391Sjason@lowepower.com    m.def("mixed_plus_args", [](int i, double j, py::args args) {
4612391Sjason@lowepower.com        return py::make_tuple(i, j, args);
4712391Sjason@lowepower.com    });
4812391Sjason@lowepower.com    m.def("mixed_plus_kwargs", [](int i, double j, py::kwargs kwargs) {
4912391Sjason@lowepower.com        return py::make_tuple(i, j, kwargs);
5012391Sjason@lowepower.com    });
5112391Sjason@lowepower.com    auto mixed_plus_both = [](int i, double j, py::args args, py::kwargs kwargs) {
5212391Sjason@lowepower.com        return py::make_tuple(i, j, args, kwargs);
5312391Sjason@lowepower.com    };
5412391Sjason@lowepower.com    m.def("mixed_plus_args_kwargs", mixed_plus_both);
5512391Sjason@lowepower.com
5612391Sjason@lowepower.com    m.def("mixed_plus_args_kwargs_defaults", mixed_plus_both,
5712391Sjason@lowepower.com            py::arg("i") = 1, py::arg("j") = 3.14159);
5812391Sjason@lowepower.com
5914299Sbbruce@ucdavis.edu    // test_args_refcount
6014299Sbbruce@ucdavis.edu    // PyPy needs a garbage collection to get the reference count values to match CPython's behaviour
6114299Sbbruce@ucdavis.edu    #ifdef PYPY_VERSION
6214299Sbbruce@ucdavis.edu    #define GC_IF_NEEDED ConstructorStats::gc()
6314299Sbbruce@ucdavis.edu    #else
6414299Sbbruce@ucdavis.edu    #define GC_IF_NEEDED
6514299Sbbruce@ucdavis.edu    #endif
6614299Sbbruce@ucdavis.edu    m.def("arg_refcount_h", [](py::handle h) { GC_IF_NEEDED; return h.ref_count(); });
6714299Sbbruce@ucdavis.edu    m.def("arg_refcount_h", [](py::handle h, py::handle, py::handle) { GC_IF_NEEDED; return h.ref_count(); });
6814299Sbbruce@ucdavis.edu    m.def("arg_refcount_o", [](py::object o) { GC_IF_NEEDED; return o.ref_count(); });
6914299Sbbruce@ucdavis.edu    m.def("args_refcount", [](py::args a) {
7014299Sbbruce@ucdavis.edu        GC_IF_NEEDED;
7114299Sbbruce@ucdavis.edu        py::tuple t(a.size());
7214299Sbbruce@ucdavis.edu        for (size_t i = 0; i < a.size(); i++)
7314299Sbbruce@ucdavis.edu            // Use raw Python API here to avoid an extra, intermediate incref on the tuple item:
7414299Sbbruce@ucdavis.edu            t[i] = (int) Py_REFCNT(PyTuple_GET_ITEM(a.ptr(), static_cast<ssize_t>(i)));
7514299Sbbruce@ucdavis.edu        return t;
7614299Sbbruce@ucdavis.edu    });
7714299Sbbruce@ucdavis.edu    m.def("mixed_args_refcount", [](py::object o, py::args a) {
7814299Sbbruce@ucdavis.edu        GC_IF_NEEDED;
7914299Sbbruce@ucdavis.edu        py::tuple t(a.size() + 1);
8014299Sbbruce@ucdavis.edu        t[0] = o.ref_count();
8114299Sbbruce@ucdavis.edu        for (size_t i = 0; i < a.size(); i++)
8214299Sbbruce@ucdavis.edu            // Use raw Python API here to avoid an extra, intermediate incref on the tuple item:
8314299Sbbruce@ucdavis.edu            t[i + 1] = (int) Py_REFCNT(PyTuple_GET_ITEM(a.ptr(), static_cast<ssize_t>(i)));
8414299Sbbruce@ucdavis.edu        return t;
8514299Sbbruce@ucdavis.edu    });
8614299Sbbruce@ucdavis.edu
8712391Sjason@lowepower.com    // pybind11 won't allow these to be bound: args and kwargs, if present, must be at the end.
8812391Sjason@lowepower.com    // Uncomment these to test that the static_assert is indeed working:
8912391Sjason@lowepower.com//    m.def("bad_args1", [](py::args, int) {});
9012391Sjason@lowepower.com//    m.def("bad_args2", [](py::kwargs, int) {});
9112391Sjason@lowepower.com//    m.def("bad_args3", [](py::kwargs, py::args) {});
9212391Sjason@lowepower.com//    m.def("bad_args4", [](py::args, int, py::kwargs) {});
9312391Sjason@lowepower.com//    m.def("bad_args5", [](py::args, py::kwargs, int) {});
9412391Sjason@lowepower.com//    m.def("bad_args6", [](py::args, py::args) {});
9512391Sjason@lowepower.com//    m.def("bad_args7", [](py::kwargs, py::kwargs) {});
9612391Sjason@lowepower.com
9712391Sjason@lowepower.com    // test_function_signatures (along with most of the above)
9812391Sjason@lowepower.com    struct KWClass { void foo(int, float) {} };
9911986Sandreas.sandberg@arm.com    py::class_<KWClass>(m, "KWClass")
10011986Sandreas.sandberg@arm.com        .def("foo0", &KWClass::foo)
10111986Sandreas.sandberg@arm.com        .def("foo1", &KWClass::foo, "x"_a, "y"_a);
10212391Sjason@lowepower.com}
103