Skip to content

Commit b42e9b9

Browse files
committed
fix: review points from @YannickJadoul
1 parent dd0768c commit b42e9b9

File tree

4 files changed

+32
-21
lines changed

4 files changed

+32
-21
lines changed

include/pybind11/attr.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ struct function_record {
138138
function_record()
139139
: is_constructor(false), is_new_style_constructor(false), is_stateless(false),
140140
is_operator(false), is_method(false),
141-
has_args(false), has_kwargs(false), has_kwonly_args(false), has_pos_only_args(false) { }
141+
has_args(false), has_kwargs(false), has_kwonly_args(false) { }
142142

143143
/// Function name
144144
char *name = nullptr; /* why no C++ strings? They generate heavier code.. */
@@ -188,16 +188,13 @@ struct function_record {
188188
/// True once a 'py::kwonly' is encountered (any following args are keyword-only)
189189
bool has_kwonly_args : 1;
190190

191-
/// True once a 'py::pos_only' is encountered (any previous args are pos-only)
192-
bool has_pos_only_args : 1;
193-
194191
/// Number of arguments (including py::args and/or py::kwargs, if present)
195192
std::uint16_t nargs;
196193

197194
/// Number of trailing arguments (counted in `nargs`) that are keyword-only
198195
std::uint16_t nargs_kwonly = 0;
199196

200-
/// Number of trailing arguments (counted in `nargs`) that are positional-only
197+
/// Number of leading arguments (counted in `nargs`) that are positional-only
201198
std::uint16_t nargs_pos_only = 0;
202199

203200
/// Python method object
@@ -432,7 +429,6 @@ template <> struct process_attribute<kwonly> : process_attribute_default<kwonly>
432429
/// Process a positional-only-argument maker
433430
template <> struct process_attribute<pos_only> : process_attribute_default<pos_only> {
434431
static void init(const pos_only &, function_record *r) {
435-
r->has_pos_only_args = true;
436432
r->nargs_pos_only = static_cast<std::uint16_t>(r->args.size());
437433
}
438434
};

include/pybind11/pybind11.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010

1111
#pragma once
1212

13-
#include <iostream>
14-
1513
#if defined(__INTEL_COMPILER)
1614
# pragma warning push
1715
# pragma warning disable 68 // integer conversion resulted in a change of sign
@@ -194,7 +192,7 @@ class cpp_function : public function {
194192
has_args = any_of<std::is_same<args, Args>...>::value,
195193
has_arg_annotations = any_of<is_keyword<Extra>...>::value;
196194
static_assert(has_arg_annotations || !has_kwonly_args, "py::kwonly requires the use of argument annotations");
197-
static_assert(has_arg_annotations || !has_pos_only_args, "py::pos_only requires the use of argument annotations (for doc string generation)");
195+
static_assert(has_arg_annotations || !has_pos_only_args, "py::pos_only requires the use of argument annotations (for docstrings and aligning the annotations to the arguments)");
198196
static_assert(!(has_args && has_kwonly_args), "py::kwonly cannot be combined with a py::args argument");
199197
}
200198

@@ -261,7 +259,8 @@ class cpp_function : public function {
261259
// Write arg name for everything except *args and **kwargs.
262260
if (*(pc + 1) == '*')
263261
continue;
264-
// Seperator for keyword only arguments
262+
// Separator for keyword-only arguments, placed before the kw
263+
// arguments start
265264
if (rec->nargs_kwonly > 0 && arg_index + rec->nargs_kwonly == args)
266265
signature += "*, ";
267266
if (arg_index < rec->args.size() && rec->args[arg_index].name) {
@@ -278,7 +277,8 @@ class cpp_function : public function {
278277
signature += " = ";
279278
signature += rec->args[arg_index].descr;
280279
}
281-
// Seperator for positional only arguments
280+
// Separator for positional-only arguments (placed after the
281+
// argument, rather than before like *
282282
if (rec->nargs_pos_only > 0 && (arg_index + 1) == rec->nargs_pos_only)
283283
signature += ", /";
284284
arg_index++;

tests/test_kwargs_and_defaults.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,18 +107,20 @@ TEST_SUBMODULE(kwargs_and_defaults, m) {
107107
return py::make_tuple(i, j, k, kwargs); },
108108
py::arg() /* positional */, py::arg("j") = -1 /* both */, py::kwonly(), py::arg("k") /* kw-only */);
109109

110+
m.def("register_invalid_kwonly", [](py::module m) {
111+
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+
110115
// test_positional_only_args
111116
m.def("pos_only_all", [](int i, int j) { return py::make_tuple(i, j); },
112117
py::arg("i"), py::arg("j"), py::pos_only());
113118
m.def("pos_only_mix", [](int i, int j) { return py::make_tuple(i, j); },
114119
py::arg("i"), py::pos_only(), py::arg("j"));
115120
m.def("pos_kw_only_mix", [](int i, int j, int k) { return py::make_tuple(i, j, k); },
116121
py::arg("i"), py::pos_only(), py::arg("j"), py::kwonly(), py::arg("k"));
117-
118-
m.def("register_invalid_kwonly", [](py::module m) {
119-
m.def("bad_kwonly", [](int i, int j) { return py::make_tuple(i, j); },
120-
py::kwonly(), py::arg() /* invalid unnamed argument */, "j"_a);
121-
});
122+
m.def("pos_only_def_mix", [](int i, int j, int k) { return py::make_tuple(i, j, k); },
123+
py::arg("i"), py::arg("j") = 2, py::pos_only(), py::arg("k") = 3);
122124

123125
// These should fail to compile:
124126
// argument annotations are required when using kwonly

tests/test_kwargs_and_defaults.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -175,13 +175,26 @@ def test_positional_only_args(msg):
175175
m.pos_kw_only_mix(1, 2, 3)
176176
assert "incompatible function arguments" in str(excinfo.value)
177177

178+
with pytest.raises(TypeError) as excinfo:
179+
m.pos_only_def_mix()
180+
assert "incompatible function arguments" in str(excinfo.value)
181+
182+
assert m.pos_only_def_mix(1) == (1, 2, 3)
183+
assert m.pos_only_def_mix(1, 4) == (1, 4, 3)
184+
assert m.pos_only_def_mix(1, 4, 7) == (1, 4, 7)
185+
assert m.pos_only_def_mix(1, 4, k=7) == (1, 4, 7)
186+
187+
with pytest.raises(TypeError) as excinfo:
188+
m.pos_only_def_mix(1, j=4)
189+
assert "incompatible function arguments" in str(excinfo.value)
190+
178191

179192
def test_signatures():
180-
assert "kwonly_all(*, i: int, j: int) -> tuple" in m.kwonly_all.__doc__
181-
assert "kwonly_mixed(i: int, *, j: int) -> tuple" in m.kwonly_mixed.__doc__
182-
assert "pos_only_all(i: int, j: int, /) -> tuple" in m.pos_only_all.__doc__
183-
assert "pos_only_mix(i: int, /, j: int) -> tuple" in m.pos_only_mix.__doc__
184-
assert "pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple" in m.pos_kw_only_mix.__doc__
193+
assert "kwonly_all(*, i: int, j: int) -> tuple\n" == m.kwonly_all.__doc__
194+
assert "kwonly_mixed(i: int, *, j: int) -> tuple\n" == m.kwonly_mixed.__doc__
195+
assert "pos_only_all(i: int, j: int, /) -> tuple\n" == m.pos_only_all.__doc__
196+
assert "pos_only_mix(i: int, /, j: int) -> tuple\n" == m.pos_only_mix.__doc__
197+
assert "pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple\n" == m.pos_kw_only_mix.__doc__
185198

186199

187200
@pytest.mark.xfail("env.PYPY and env.PY2", reason="PyPy2 doesn't double count")

0 commit comments

Comments
 (0)