-
-
Notifications
You must be signed in to change notification settings - Fork 30.8k
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
property
assumes that its subclasses have __dict__
#98963
Comments
Recommend ignoring the |
Thinking about it more, I came to the opposite conclusion. Ignoring The main issue here is that the error is surprising – it's not clear what's happening and what the right course of action is. If you're subclassing |
I also don't think that losing the Would it not be an option to relax the condition at the top? Instead of
|
This commit ports a few improvements from the 'limited_api' branch of nanobind. In particular - 'nb_static_property' is constructed in a different way by exposing a writeable '__doc__' member field. This is to work around an issue in CPython (related discussion can be found here: python/cpython#98963) - Instead of copy-pasting GC ``tp_clear`` and ``tp_traverse`` slots from parent to child classes, we rely on ``PyType_Ready`` doing this automatically.
To make |
FWIW,. this code has been stable for 20 years. AFAICT, the only motivation for an edit is to accommodate single, new, and somewhat exotic C extension. So any proposed change should be minimally invasive.
It doesn't feel like my assessment is being valued. |
I definitely agree with that! I hope to only touch the error case.
My opinion here is more nuanced though. The C API is not used only with C, and I've been trying to make it more useful with other languages (C++, Rust, Java). Language bindings work at a lower level than typical C extensions, so they run into subtle bugs we haven't seen before.
I'm sorry I made you feel this way. I tried to react to you and explain my reasoning. How can I do better? |
For what it's worth, I understand @rhettinger's concern that this is somewhat of a niche issue. While making Python behave more as expected is desirable, I would already be very happy simply with guidance on how to work around this issue in a stable manner (meaning that it works for past Python versions, and that I can have some reasonable assurance it won't break in the future). Alas, that requirement of stability is what is making things very difficult:
If you have advice on other things to try, I am all ears.. :) |
…ut __doc__ Subclasses created using the C API don't get __dict__, which means their __doc__ can't be set for each property separately. The __doc__ descriptor from `property` itself is shadowed by the subclass's docstring. This edge case isn't really worth mentioning in the docs. This adds a note that should guide anyone encountering the issue to the right fix.
Aha! It turns out that this was not stable -- in fact this was just changed for 3.12: #23205 @wjakob: There's even some pybind11 fallout: pybind/pybind11#4168
|
Aha, it's great to know that v3.12 is the place where this change happened. Incidentally, this is also the first Python version for which So what I am thinking to do now as a workaround is:
The error message in PR #99058 looks good to me. |
The handling of the ``__doc__`` member of CPython's ``property`` type changes in version 3.12. This commit changes the way in which this type is created pre/post-v3.12. See python/cpython#98963 for details.
Actually, the Python 3.12 change was for the |
Are you referring to the The docstring is specified directly to the Note: this commit does not yet use the features from your tentative PEP (negative |
This came up in protobuf because it has a class _FieldProperty(property):
__slots__ = ("DESCRIPTOR",) calling property.__init__(self, getter, setter, doc=doc)
AttributeError: '_FieldProperty' object attribute '__doc__' is read-only If In older versions of Python the the property constructor silently does not assign a docstring rather than causing an |
That is narrower than the larger issue here, but I think we should mirror that silent doc-dropping behavior for 3.12 and consider if we're deprecating that behavior later or just want to make it official. |
Ignore doc string assignment failures in `property` as has been the behavior of all past Python releases. One behavior change: The longstanding tested behavior of raising an `AttributeError` when using a slotted no-dict property subclass as a decorator on a getter sporting a docstring is now consistent with the subclassing behavior and does not produce an error.
re-reading things, I don't think that is true. This issue title talks about a dict, but the issue is entirely about a the docstring being unsettable and whether that is ignored as it always has been or is an expected behavior changing error. Existing code depends on it being ignored. |
Ignore doc string assignment failures in `property` as has been the behavior of all past Python releases.
…thonGH-105262) Ignore doc string assignment failures in `property` as has been the behavior of all past Python releases. (cherry picked from commit 418befd) Co-authored-by: Gregory P. Smith <greg@krypto.org>
closing as the 3.12 PR is set to automerge; previous exception / ignored error behavior has been restored. |
…H-105262) (#105297) gh-98963: Restore the ability to have a dict-less property. (GH-105262) Ignore doc string assignment failures in `property` as has been the behavior of all past Python releases. (the docstring is discarded) (cherry picked from commit 418befd) This fixes a behavior regression in 3.12beta1 where an AttributeError was being raised in a situation it has never been in the past. It keeps the existing unusual single situation where AttributeError does get raised. Existing widely deployed projects depend on this not raising an exception. Co-authored-by: Gregory P. Smith <greg@krypto.org>
Related to this in general... CPython <=3.11 has some seriously smelly behavior: Python 3.10.9 (main, Dec 7 2022, 13:47:07) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class slotted_property(property):
... __slots__ = ()
...
>>> slotted_property()
<__main__.slotted_property object at 0x7f36e189dad0>
>>> slotted_property(lambda x: None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'slotted_property' object attribute '__doc__' is read-only
>>> slotted_property(lambda x: None, doc='ignored').__doc__
>>> slotted_property(lambda x: None, doc='').__doc__
>>> slotted_property(lambda x: None, doc=None).__doc__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'slotted_property' object attribute '__doc__' is read-only
>>> |
Those surprisingly inconsistent |
Thank you for taking this on! |
A thanks from me as well. With your change, I was able to remove the Python 3.12-specific workaround/hack from nanobind. |
property
'stp_init
has this code:This assumes that subclasses of
property
have a__dict__
(or a__doc__
attribute settable by other means). That is the case when subclassed using theclass
statement, but might not be true using C.A C-API reproducer is at https://github.com/wjakob/inheritance_issue/blob/master/inheritance_issue.c
I don't see a good way to fix this. We could:
Py_TPFLAGS_MANAGED_DICT
(or provide a__doc__
descriptor), orAttributeError
, unless__doc__
was set explicitly?The text was updated successfully, but these errors were encountered: