Merge pull request #1779 from indygreg/setter-handle-del

macros: raise AttributeError on property deletion requests
This commit is contained in:
David Hewitt 2021-08-14 08:57:33 +01:00 committed by GitHub
commit 584de688c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 12 additions and 1 deletions

View File

@ -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. [#1779](https://github.com/PyO3/pyo3/issues/1779)
- Add missing `_type` field to `PyStatus` struct definition. [#1791](https://github.com/PyO3/pyo3/pull/1791)
## [0.14.2] - 2021-08-09

View File

@ -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

View File

@ -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)

View File

@ -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");