Skip to content

Commit

Permalink
macros: raise AttributeError on property deletion requests
Browse files Browse the repository at this point in the history
The setter function will receive a NULL value on deletion requests.
This wasn't properly handled before, leading to a panic.

The new code raises AttributeError in this scenario instead.

A test for the behavior has been added. Documentation has also
been updated to reflect the behavior.
  • Loading branch information
indygreg committed Aug 14, 2021
1 parent 254ea53 commit 410c9f1
Show file tree
Hide file tree
Showing 4 changed files with 12 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Fixed

- Restrict FFI definitions `PyGILState_Check` and `Py_tracefunc` to the unlimited API. [#1787](https://github.com/PyO3/pyo3/pull/1787)
- Raise `AttributeError` to avoid panic when calling `del` on a `[setter]` defined class property. [#1775](https://github.com/PyO3/pyo3/issues/1775)

## [0.14.2] - 2021-08-09

Expand Down
4 changes: 4 additions & 0 deletions guide/src/class.md
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,10 @@ impl MyClass {

In this case, the property `number` is defined and available from Python code as `self.number`.

Attributes defined by `#[setter]` or `#[pyo3(set)]` will always raise `AttributeError` on `del`
operations. Support for defining custom `del` behavior is tracked in
[#1778](https://github.com/PyO3/pyo3/issues/1778).

## Instance methods

To define a Python compatible method, an `impl` block for your struct has to be annotated with the
Expand Down
6 changes: 5 additions & 1 deletion pyo3-macros-backend/src/pymethod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,11 @@ pub fn impl_py_setter_def(cls: &syn::Type, property_type: PropertyType) -> Resul
) -> std::os::raw::c_int {
pyo3::callback::handle_panic(|_py| {
#slf
let _value = _py.from_borrowed_ptr::<pyo3::types::PyAny>(_value);
let _value = _py
.from_borrowed_ptr_or_opt(_value)
.ok_or_else(|| {
pyo3::exceptions::PyAttributeError::new_err("can't delete attribute")
})?;
let _val = pyo3::FromPyObject::extract(_value)?;

pyo3::callback::convert(_py, #setter_impl)
Expand Down
2 changes: 2 additions & 0 deletions tests/test_getter_setter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ fn class_with_properties() {
py_run!(py, inst, "inst.DATA = 20");
py_run!(py, inst, "assert inst.get_num() == 20 == inst.DATA");

py_expect_exception!(py, inst, "del inst.DATA", PyAttributeError);

py_run!(py, inst, "assert inst.get_num() == inst.unwrapped == 20");
py_run!(py, inst, "inst.unwrapped = 42");
py_run!(py, inst, "assert inst.get_num() == inst.unwrapped == 42");
Expand Down

0 comments on commit 410c9f1

Please sign in to comment.