mirror of
https://github.com/pybind/pybind11.git
synced 2026-05-13 09:46:10 +00:00
Allow py::arg().none(false) argument attribute
This attribute lets you disable (or explicitly enable) passing None to an argument that otherwise would allow it by accepting a value by raw pointer or shared_ptr.
This commit is contained in:
@@ -123,9 +123,10 @@ struct argument_record {
|
||||
const char *descr; ///< Human-readable version of the argument value
|
||||
handle value; ///< Associated Python object
|
||||
bool convert : 1; ///< True if the argument is allowed to convert when loading
|
||||
bool none : 1; ///< True if None is allowed when loading
|
||||
|
||||
argument_record(const char *name, const char *descr, handle value, bool convert)
|
||||
: name(name), descr(descr), value(value), convert(convert) { }
|
||||
argument_record(const char *name, const char *descr, handle value, bool convert, bool none)
|
||||
: name(name), descr(descr), value(value), convert(convert), none(none) { }
|
||||
};
|
||||
|
||||
/// Internal data structure which holds metadata about a bound function (signature, overloads, etc.)
|
||||
@@ -338,8 +339,8 @@ template <> struct process_attribute<is_operator> : process_attribute_default<is
|
||||
template <> struct process_attribute<arg> : process_attribute_default<arg> {
|
||||
static void init(const arg &a, function_record *r) {
|
||||
if (r->is_method && r->args.empty())
|
||||
r->args.emplace_back("self", nullptr, handle(), true /*convert*/);
|
||||
r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert);
|
||||
r->args.emplace_back("self", nullptr, handle(), true /*convert*/, false /*none not allowed*/);
|
||||
r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -347,7 +348,7 @@ template <> struct process_attribute<arg> : process_attribute_default<arg> {
|
||||
template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
|
||||
static void init(const arg_v &a, function_record *r) {
|
||||
if (r->is_method && r->args.empty())
|
||||
r->args.emplace_back("self", nullptr /*descr*/, handle() /*parent*/, true /*convert*/);
|
||||
r->args.emplace_back("self", nullptr /*descr*/, handle() /*parent*/, true /*convert*/, false /*none not allowed*/);
|
||||
|
||||
if (!a.value) {
|
||||
#if !defined(NDEBUG)
|
||||
@@ -370,7 +371,7 @@ template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
|
||||
"Compile in debug mode for more information.");
|
||||
#endif
|
||||
}
|
||||
r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert);
|
||||
r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1381,14 +1381,17 @@ template <return_value_policy policy = return_value_policy::automatic_reference,
|
||||
/// Annotation for arguments
|
||||
struct arg {
|
||||
/// Constructs an argument with the name of the argument; if null or omitted, this is a positional argument.
|
||||
constexpr explicit arg(const char *name = nullptr) : name(name), flag_noconvert(false) { }
|
||||
constexpr explicit arg(const char *name = nullptr) : name(name), flag_noconvert(false), flag_none(true) { }
|
||||
/// Assign a value to this argument
|
||||
template <typename T> arg_v operator=(T &&value) const;
|
||||
/// Indicate that the type should not be converted in the type caster
|
||||
arg &noconvert(bool flag = true) { flag_noconvert = flag; return *this; }
|
||||
/// Indicates that the argument should/shouldn't allow None (e.g. for nullable pointer args)
|
||||
arg &none(bool flag = true) { flag_none = flag; return *this; }
|
||||
|
||||
const char *name; ///< If non-null, this is a named kwargs argument
|
||||
bool flag_noconvert : 1; ///< If set, do not allow conversion (requires a supporting type caster!)
|
||||
bool flag_none : 1; ///< If set (the default), allow None to be passed to this argument
|
||||
};
|
||||
|
||||
/// \ingroup annotations
|
||||
@@ -1421,6 +1424,9 @@ public:
|
||||
/// Same as `arg::noconvert()`, but returns *this as arg_v&, not arg&
|
||||
arg_v &noconvert(bool flag = true) { arg::noconvert(flag); return *this; }
|
||||
|
||||
/// Same as `arg::nonone()`, but returns *this as arg_v&, not arg&
|
||||
arg_v &none(bool flag = true) { arg::none(flag); return *this; }
|
||||
|
||||
/// The default value
|
||||
object value;
|
||||
/// The (optional) description of the default value
|
||||
|
||||
@@ -466,18 +466,23 @@ protected:
|
||||
size_t args_copied = 0;
|
||||
|
||||
// 1. Copy any position arguments given.
|
||||
bool bad_kwarg = false;
|
||||
bool bad_arg = false;
|
||||
for (; args_copied < args_to_copy; ++args_copied) {
|
||||
if (kwargs_in && args_copied < func.args.size() && func.args[args_copied].name
|
||||
&& PyDict_GetItemString(kwargs_in, func.args[args_copied].name)) {
|
||||
bad_kwarg = true;
|
||||
argument_record *arg_rec = args_copied < func.args.size() ? &func.args[args_copied] : nullptr;
|
||||
if (kwargs_in && arg_rec && arg_rec->name && PyDict_GetItemString(kwargs_in, arg_rec->name)) {
|
||||
bad_arg = true;
|
||||
break;
|
||||
}
|
||||
|
||||
call.args.push_back(PyTuple_GET_ITEM(args_in, args_copied));
|
||||
call.args_convert.push_back(args_copied < func.args.size() ? func.args[args_copied].convert : true);
|
||||
handle arg(PyTuple_GET_ITEM(args_in, args_copied));
|
||||
if (arg_rec && !arg_rec->none && arg.is_none()) {
|
||||
bad_arg = true;
|
||||
break;
|
||||
}
|
||||
call.args.push_back(arg);
|
||||
call.args_convert.push_back(arg_rec ? arg_rec->convert : true);
|
||||
}
|
||||
if (bad_kwarg)
|
||||
if (bad_arg)
|
||||
continue; // Maybe it was meant for another overload (issue #688)
|
||||
|
||||
// We'll need to copy this if we steal some kwargs for defaults
|
||||
|
||||
Reference in New Issue
Block a user