-
Notifications
You must be signed in to change notification settings - Fork 761
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
Panic when calling del typ.attr
on a [setter] defined attribute
#1775
Comments
Yikes! I think your proposal to resolve with minimal backwards-compatibility is the correct approach. Let's implement the two bullets as separate PRs. In particular I think raising Adding the Is there a particular reason you want |
They should be able to use |
I don't rely on Also, since we're using Anyway, changing to |
Using the latest code in
main
/0.14.2
, it is possible to trigger a panic from Python by callingdel
on a[setter]
defined attribute on a Rust type. This can be reproduced with the following patch to the official test harness:Here's context from the crash:
I believe the problem resides in the implementation of
[setter]
:__wrap
here ultimately seems to become the value for aPyTypeObject.tp_getset
entryPyGetSetDef.set
. From the official docs (https://docs.python.org/3/c-api/structures.html#c.PyGetSetDef):The important takeaway here is the value can be
NULL
if adel
/__delattr__
operation is being performed.However, the implementation calls
from_borrowed_ptr
, which panics onNULL
, leading to the error reported in this issue.This
[setter]
generated code needs to accommodateNULL
values to reflect a deletion. For comparison, the cpython crate handles this by passingOption<T>
to setter function, whereNone
represents theNULL
value case / deletion request (http://dgrunwald.github.io/rust-cpython/doc/cpython/macro.py_class.html#properties). Ideally PyO3 would adopt that convention as well. But this is obviously backwards incompatible, since existing#[setter]
implementation may useOption<T>
arguments to coerce a PythonNone
/<other type>
into a RustOption<T>
. (You would need to change this toOption<Option<T>>
where the outerOption
represents the presence of a value and the innerOption<T>
representing aNone
-able Python value.Here's one potential idea for fixing this with minimal backwards compatibility concerns:
PySetter
wrapper to raiseAttributeError
on_value.is_null()
. (The exact exception type can be bikeshedded but I thinkAttributeError
is appropriate.)[deleter]
(or similar) annotation for [pymethods] that allows defining a custom Rust function to handle attribute deletions. If present, the auto-generatedPySetter
wrapper would call this function on_value.is_null()
instead of raising an exception.This is a bit complex, but it does get the job done.
Other potential solutions entail arguments to
[setter]
to control behavior. Perhaps[setter(optional)]
to opt in to a mode that handlesNULL
and passesOption<T>
to the Rust function?The text was updated successfully, but these errors were encountered: