test_kwargs_and_defaults.cpp 4.03 KB
Newer Older
1
/*
Dean Moldovan's avatar
Dean Moldovan committed
2
    tests/test_kwargs_and_defaults.cpp -- keyword arguments and default values
3

4
    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
5
6
7
8
9

    All rights reserved. Use of this source code is governed by a
    BSD-style license that can be found in the LICENSE file.
*/

Dean Moldovan's avatar
Dean Moldovan committed
10
#include "pybind11_tests.h"
11
#include "constructor_stats.h"
12
#include <pybind11/stl.h>
13

14
15
TEST_SUBMODULE(kwargs_and_defaults, m) {
    auto kw_func = [](int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); };
16

17
18
19
20
    // test_named_arguments
    m.def("kw_func0", kw_func);
    m.def("kw_func1", kw_func, py::arg("x"), py::arg("y"));
    m.def("kw_func2", kw_func, py::arg("x") = 100, py::arg("y") = 200);
21
    m.def("kw_func3", [](const char *) { }, py::arg("data") = std::string("Hello world!"));
22
23

    /* A fancier default argument */
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    std::vector<int> list{{13, 17}};
    m.def("kw_func4", [](const std::vector<int> &entries) {
        std::string ret = "{";
        for (int i : entries)
            ret += std::to_string(i) + " ";
        ret.back() = '}';
        return ret;
    }, py::arg("myList") = list);

    m.def("kw_func_udl", kw_func, "x"_a, "y"_a=300);
    m.def("kw_func_udl_z", kw_func, "x"_a, "y"_a=0);

    // test_args_and_kwargs
    m.def("args_function", [](py::args args) -> py::tuple { return args; });
    m.def("args_kwargs_function", [](py::args args, py::kwargs kwargs) {
        return py::make_tuple(args, kwargs);
    });

    // test_mixed_args_and_kwargs
    m.def("mixed_plus_args", [](int i, double j, py::args args) {
        return py::make_tuple(i, j, args);
    });
    m.def("mixed_plus_kwargs", [](int i, double j, py::kwargs kwargs) {
        return py::make_tuple(i, j, kwargs);
    });
    auto mixed_plus_both = [](int i, double j, py::args args, py::kwargs kwargs) {
        return py::make_tuple(i, j, args, kwargs);
    };
    m.def("mixed_plus_args_kwargs", mixed_plus_both);

    m.def("mixed_plus_args_kwargs_defaults", mixed_plus_both,
            py::arg("i") = 1, py::arg("j") = 3.14159);
Wenzel Jakob's avatar
Wenzel Jakob committed
56

57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
    // test_args_refcount
    // PyPy needs a garbage collection to get the reference count values to match CPython's behaviour
    #ifdef PYPY_VERSION
    #define GC_IF_NEEDED ConstructorStats::gc()
    #else
    #define GC_IF_NEEDED
    #endif
    m.def("arg_refcount_h", [](py::handle h) { GC_IF_NEEDED; return h.ref_count(); });
    m.def("arg_refcount_h", [](py::handle h, py::handle, py::handle) { GC_IF_NEEDED; return h.ref_count(); });
    m.def("arg_refcount_o", [](py::object o) { GC_IF_NEEDED; return o.ref_count(); });
    m.def("args_refcount", [](py::args a) {
        GC_IF_NEEDED;
        py::tuple t(a.size());
        for (size_t i = 0; i < a.size(); i++)
            // Use raw Python API here to avoid an extra, intermediate incref on the tuple item:
            t[i] = (int) Py_REFCNT(PyTuple_GET_ITEM(a.ptr(), static_cast<ssize_t>(i)));
        return t;
    });
    m.def("mixed_args_refcount", [](py::object o, py::args a) {
        GC_IF_NEEDED;
        py::tuple t(a.size() + 1);
        t[0] = o.ref_count();
        for (size_t i = 0; i < a.size(); i++)
            // Use raw Python API here to avoid an extra, intermediate incref on the tuple item:
            t[i + 1] = (int) Py_REFCNT(PyTuple_GET_ITEM(a.ptr(), static_cast<ssize_t>(i)));
        return t;
    });

85
86
87
88
89
90
91
92
93
94
95
96
    // pybind11 won't allow these to be bound: args and kwargs, if present, must be at the end.
    // Uncomment these to test that the static_assert is indeed working:
//    m.def("bad_args1", [](py::args, int) {});
//    m.def("bad_args2", [](py::kwargs, int) {});
//    m.def("bad_args3", [](py::kwargs, py::args) {});
//    m.def("bad_args4", [](py::args, int, py::kwargs) {});
//    m.def("bad_args5", [](py::args, py::kwargs, int) {});
//    m.def("bad_args6", [](py::args, py::args) {});
//    m.def("bad_args7", [](py::kwargs, py::kwargs) {});

    // test_function_signatures (along with most of the above)
    struct KWClass { void foo(int, float) {} };
97
98
99
    py::class_<KWClass>(m, "KWClass")
        .def("foo0", &KWClass::foo)
        .def("foo1", &KWClass::foo, "x"_a, "y"_a);
100
}