test_kwargs_and_defaults.cpp 5.38 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
    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
Henry Schreiner's avatar
Henry Schreiner committed
37
38
39
    m.def("args_function", [](py::args args) -> py::tuple {
        return std::move(args);
    });
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
    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
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
85
86
    // 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;
    });

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) {});

97
98
    // test_keyword_only_args
    m.def("kwonly_all", [](int i, int j) { return py::make_tuple(i, j); },
99
            py::kwonly(), py::arg("i"), py::arg("j"));
100
    m.def("kwonly_some", [](int i, int j, int k) { return py::make_tuple(i, j, k); },
101
            py::arg(), py::kwonly(), py::arg("j"), py::arg("k"));
102
    m.def("kwonly_with_defaults", [](int i, int j, int k, int z) { return py::make_tuple(i, j, k, z); },
103
            py::arg() = 3, "j"_a = 4, py::kwonly(), "k"_a = 5, "z"_a);
104
    m.def("kwonly_mixed", [](int i, int j) { return py::make_tuple(i, j); },
105
            "i"_a, py::kwonly(), "j"_a);
106
107
    m.def("kwonly_plus_more", [](int i, int j, int k, py::kwargs kwargs) {
            return py::make_tuple(i, j, k, kwargs); },
108
            py::arg() /* positional */, py::arg("j") = -1 /* both */, py::kwonly(), py::arg("k") /* kw-only */);
109
110
111

    m.def("register_invalid_kwonly", [](py::module m) {
        m.def("bad_kwonly", [](int i, int j) { return py::make_tuple(i, j); },
112
                py::kwonly(), py::arg() /* invalid unnamed argument */, "j"_a);
113
114
115
    });

    // These should fail to compile:
116
117
118
119
    // argument annotations are required when using kwonly
//    m.def("bad_kwonly1", [](int) {}, py::kwonly());
    // can't specify both `py::kwonly` and a `py::args` argument
//    m.def("bad_kwonly2", [](int i, py::args) {}, py::kwonly(), "i"_a);
120

121
122
    // test_function_signatures (along with most of the above)
    struct KWClass { void foo(int, float) {} };
123
124
125
    py::class_<KWClass>(m, "KWClass")
        .def("foo0", &KWClass::foo)
        .def("foo1", &KWClass::foo, "x"_a, "y"_a);
126
}