macros: raise AttributeError on property deletion requests
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.
This commit is contained in:
parent
254ea53f3f
commit
410c9f13c9
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue