Support keyword-only arguments

This adds support for a `py::args_kw_only()` annotation that can be
specified between `py::arg` annotations to indicate that any following
arguments are keyword-only.  This allows you to write:

    m.def("f", [](int a, int b) { /* ... */ },
          py::arg("a"), py::args_kw_only(), py::arg("b"));

and have it work like Python 3's:

    def f(a, *, b):
        # ...

with respect to how `a` and `b` arguments are accepted (that is, `a` can
be positional or by keyword; `b` can only be specified by keyword).
This commit is contained in:
Jason Rhinelander
2017-12-23 18:56:07 -04:00
committed by Wenzel Jakob
parent 03f9e4a8ec
commit be0d804523
6 changed files with 139 additions and 11 deletions

View File

@@ -107,6 +107,44 @@ def test_mixed_args_and_kwargs(msg):
""" # noqa: E501 line too long
def test_keyword_only_args(msg):
assert m.kwonly_all(i=1, j=2) == (1, 2)
assert m.kwonly_all(j=1, i=2) == (2, 1)
with pytest.raises(TypeError) as excinfo:
assert m.kwonly_all(i=1) == (1,)
assert "incompatible function arguments" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo:
assert m.kwonly_all(1, 2) == (1, 2)
assert "incompatible function arguments" in str(excinfo.value)
assert m.kwonly_some(1, k=3, j=2) == (1, 2, 3)
assert m.kwonly_with_defaults(z=8) == (3, 4, 5, 8)
assert m.kwonly_with_defaults(2, z=8) == (2, 4, 5, 8)
assert m.kwonly_with_defaults(2, j=7, k=8, z=9) == (2, 7, 8, 9)
assert m.kwonly_with_defaults(2, 7, z=9, k=8) == (2, 7, 8, 9)
assert m.kwonly_mixed(1, j=2) == (1, 2)
assert m.kwonly_mixed(j=2, i=3) == (3, 2)
assert m.kwonly_mixed(i=2, j=3) == (2, 3)
assert m.kwonly_plus_more(4, 5, k=6, extra=7) == (4, 5, 6, {'extra': 7})
assert m.kwonly_plus_more(3, k=5, j=4, extra=6) == (3, 4, 5, {'extra': 6})
assert m.kwonly_plus_more(2, k=3, extra=4) == (2, -1, 3, {'extra': 4})
with pytest.raises(TypeError) as excinfo:
assert m.kwonly_mixed(i=1) == (1,)
assert "incompatible function arguments" in str(excinfo.value)
with pytest.raises(RuntimeError) as excinfo:
m.register_invalid_kwonly(m)
assert msg(excinfo.value) == """
arg(): cannot specify an unnamed argument after an args_kw_only() annotation
"""
def test_args_refcount():
"""Issue/PR #1216 - py::args elements get double-inc_ref()ed when combined with regular
arguments"""