-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Added write only property functions for issue #1142 #1144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -51,6 +51,7 @@ NAMESPACE_BEGIN(PYBIND11_NAMESPACE) | |
class cpp_function : public function { | ||
public: | ||
cpp_function() { } | ||
cpp_function(std::nullptr_t) { } | ||
|
||
/// Construct a cpp_function from a vanilla function pointer | ||
template <typename Return, typename... Args, typename... Extra> | ||
|
@@ -954,18 +955,18 @@ class generic_type : public object { | |
tinfo->get_buffer_data = get_buffer_data; | ||
} | ||
|
||
// rec_func must be set for either fget or fset. | ||
void def_property_static_impl(const char *name, | ||
handle fget, handle fset, | ||
detail::function_record *rec_fget) { | ||
const auto is_static = !(rec_fget->is_method && rec_fget->scope); | ||
const auto has_doc = rec_fget->doc && pybind11::options::show_user_defined_docstrings(); | ||
|
||
detail::function_record *rec_func) { | ||
const auto is_static = rec_func && !(rec_func->is_method && rec_func->scope); | ||
const auto has_doc = rec_func && rec_func->doc && pybind11::options::show_user_defined_docstrings(); | ||
auto property = handle((PyObject *) (is_static ? get_internals().static_property_type | ||
: &PyProperty_Type)); | ||
attr(name) = property(fget.ptr() ? fget : none(), | ||
fset.ptr() ? fset : none(), | ||
/*deleter*/none(), | ||
pybind11::str(has_doc ? rec_fget->doc : "")); | ||
pybind11::str(has_doc ? rec_func->doc : "")); | ||
} | ||
}; | ||
|
||
|
@@ -1199,7 +1200,7 @@ class class_ : public detail::generic_type { | |
/// Uses cpp_function's return_value_policy by default | ||
template <typename... Extra> | ||
class_ &def_property_readonly(const char *name, const cpp_function &fget, const Extra& ...extra) { | ||
return def_property(name, fget, cpp_function(), extra...); | ||
return def_property(name, fget, nullptr, extra...); | ||
} | ||
|
||
/// Uses return_value_policy::reference by default | ||
|
@@ -1211,7 +1212,7 @@ class class_ : public detail::generic_type { | |
/// Uses cpp_function's return_value_policy by default | ||
template <typename... Extra> | ||
class_ &def_property_readonly_static(const char *name, const cpp_function &fget, const Extra& ...extra) { | ||
return def_property_static(name, fget, cpp_function(), extra...); | ||
return def_property_static(name, fget, nullptr, extra...); | ||
} | ||
|
||
/// Uses return_value_policy::reference_internal by default | ||
|
@@ -1241,21 +1242,25 @@ class class_ : public detail::generic_type { | |
template <typename... Extra> | ||
class_ &def_property_static(const char *name, const cpp_function &fget, const cpp_function &fset, const Extra& ...extra) { | ||
auto rec_fget = get_function_record(fget), rec_fset = get_function_record(fset); | ||
char *doc_prev = rec_fget->doc; /* 'extra' field may include a property-specific documentation string */ | ||
detail::process_attributes<Extra...>::init(extra..., rec_fget); | ||
if (rec_fget->doc && rec_fget->doc != doc_prev) { | ||
free(doc_prev); | ||
rec_fget->doc = strdup(rec_fget->doc); | ||
auto *rec_active = rec_fget; | ||
if (rec_fget) { | ||
char *doc_prev = rec_fget->doc; /* 'extra' field may include a property-specific documentation string */ | ||
detail::process_attributes<Extra...>::init(extra..., rec_fget); | ||
if (rec_fget->doc && rec_fget->doc != doc_prev) { | ||
free(doc_prev); | ||
rec_fget->doc = strdup(rec_fget->doc); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One consequence of this is that you can now do: cl.def_property("x", nullptr, nullptr) and get an >>> class A:
... x = property(None, None)
...
>>> a = A()
>>> a.x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: unreadable attribute
>>> a.x = 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute (So in other words, no change needed here, just an observation in passing). |
||
} | ||
if (rec_fset) { | ||
doc_prev = rec_fset->doc; | ||
char *doc_prev = rec_fset->doc; | ||
detail::process_attributes<Extra...>::init(extra..., rec_fset); | ||
if (rec_fset->doc && rec_fset->doc != doc_prev) { | ||
free(doc_prev); | ||
rec_fset->doc = strdup(rec_fset->doc); | ||
} | ||
if (! rec_active) rec_active = rec_fset; | ||
} | ||
def_property_static_impl(name, fget, fset, rec_fget); | ||
def_property_static_impl(name, fget, fset, rec_active); | ||
return *this; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is pretty minor, but I think with this
nullptr
constructor it would be slightly nicer to changedef_property_readonly
anddef_property_readonly_static
to passnullptr
rather thancpp_function()
. It won't make any difference to how it works, but conceptually it seems nicer since the PR adds (and documents) passing anullptr
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Related to this: it should also be possible to specify a default-constructed
cpp_function()
for either the setter or getter, so perhaps add another property such as:.def_property("impossible", py::cpp_function(), py::cpp_function())
with associated tests for attribute errors on both set or get (as per my other comment), but mainly just so we still have some test suite code invoking that code path.