pybind / pybind11

Seamless operability between C++11 and Python
https://pybind11.readthedocs.io/
Other
15.08k stars 2.05k forks source link

[BUG]: py::args can not be combined with kw_only(), triggers static assert #5135

Open Tishj opened 1 month ago

Tishj commented 1 month ago

Required prerequisites

What version (or hash if on master) of pybind11 are you using?

2.12.0

Problem description

I am defining a method that takes py::args and needs to also accept be able to keyword arguments I don't want to accept just any keyword argument so I'm not using py::kwargs

The static assert seems to have a problem with this

Reproducible example code

m.def(
        "project",
        [](const py::object &df, const py::args &args, const string &groups) {
            return true;
        },
        py::arg("df"), py::arg("args"), py::kw_only(), py::arg("kw1") = "");
      lib/python3.12/site-packages/pybind11/include/pybind11/pybind11.h:261:9: error: static assertion failed due to requirement 'expected_num_args<pybind11::name, pybind11::scope, pybind11::sibling, pybind11::arg, pybind11::arg, pybind11::kw_only, pybind11::arg_v>(sizeof...(Args), argument_loader<const py::object &, const pybind11::args &, const std::string &>::args_pos >= 0, argument_loader<const py::object &, const pybind11::args &, const std::string &>::has_kwargs)': The number of argument annotations does not match the number of function arguments
              static_assert(
              ^
      lib/python3.12/site-packages/pybind11/include/pybind11/pybind11.h:145:9: note: in instantiation of function template specialization 'pybind11::cpp_function::initialize<(lambda at source.cpp:818:6), std::unique_ptr<duckdb::DuckDBPyRelation>, const py::object &, const pybind11::args &, const std::string &, pybind11::name, pybind11::scope, pybind11::sibling, pybind11::arg, pybind11::arg, pybind11::kw_only, pybind11::arg_v>' requested here
              initialize(
              ^
      lib/python3.12/site-packages/pybind11/include/pybind11/pybind11.h:1220:22: note: in instantiation of function template specialization 'pybind11::cpp_function::cpp_function<(lambda at source.cpp:818:6), pybind11::name, pybind11::scope, pybind11::sibling, pybind11::arg, pybind11::arg, pybind11::kw_only, pybind11::arg_v, void>' requested here
              cpp_function func(std::forward<Func>(f),
                           ^
      source.cpp:816:4: note: in instantiation of function template specialization 'pybind11::module_::def<(lambda at source.cpp:818:6), pybind11::arg, pybind11::arg, pybind11::kw_only, pybind11::arg_v>' requested here
              m.def(
                ^


### Is this a regression? Put the last known working version here if it is.

Not a regression
Tishj commented 1 month ago

Ah, looks like https://github.com/pybind/pybind11/pull/3402 fixes this if I read it correctly 👍

Tishj commented 1 month ago

I think actually the problem is that py::arg(...) should not be provided if the argument is py::args Which makes some sense, but since we're making a definition, and for python you do add *args explicitly, it feels counter-intuitive

I think a note about this on the docs would be helpful, I stumbled on this through trial and error only