You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
str(weakref) throws error KeyError: '__name__' if the original obj override __getattr__ #99184
This does not look like a bug to me.
What do you expect to happen?
Right now weakrefobject.c has these lines:
staticPyObject*weakref_repr(PyWeakReference*self)
{
PyObject*name, *repr;
PyObject*obj=PyWeakref_GET_OBJECT(self);
if (obj==Py_None) {
returnPyUnicode_FromFormat("<weakref at %p; dead>", self);
}
Py_INCREF(obj);
if (_PyObject_LookupAttr(obj, &_Py_ID(__name__), &name) <0) {
Py_DECREF(obj);
returnNULL;
}
// ...
It tries to get __name__ attribute from the passed object. Since __getattr__ tries to get __name__ from self - it fails with a KeyError. It works exactly as it is written.
@sobolevn Thanks for your quick response! I do agree this works well in functionality's perspective, but I'd like to say if this is a good user experience. If users are just trying to override __getattr__ to implement their own functionality(like what I'm doing in the example), it means they should handle a lot of other python internal stuff at well. I think this would sort of increase the complexity, and make users can't focus on their own functionality.
So, probably you are asking from some kind of fallback for cases like this. Please, correct me if I am wrong :)
I think that repr() of weakref.ref would have a default value if _PyObject_LookupAttr(obj, &_Py_ID(__name__), &name) fails.
Example: <weakref at 0x1085b5800; to __some_default__ at 0x7ffd1071c080 (...)>
However, I don't think this is a good user experience either.
It is better to see an explicit exception early on than very strange and mostly unreadable repr somewhere in logs.
Considering your class, it looks problematic to me. It does not respect basic python's API, like: __dict__, __name__, __qualname__, __class__, __module__, etc.
They are quite basic, many other parts of CPython (and 3rd party projects) do use it.
And you will have a lot of other failure when these fundamentals cannot be accessed 🤔
If users don't user weakref, it works well even they don't handle __dict__, __name__, __qualname__, __class__, __module__, etc. Do you think the inconsistency will confuse users?
If the goal is to look up __name__ on the class of the instance, shouldn't the weakref code be using _PyObject_LookupSpecial (or _PyObject_LookupSpecialId, though I guess those are the same thing now?), not _PyObject_LookupAttr? The only advantage to the latter is if we wanted to allow instances to change their names by overwriting __name__. Using the LookupSpecial API would bypass the instance and avoid this issue (as well as being faster and likely more correct).
Activity
sobolevn commentedon Nov 7, 2022
This does not look like a bug to me.
What do you expect to happen?
Right now
weakrefobject.chas these lines:It tries to get
__name__attribute from the passed object. Since__getattr__tries to get__name__fromself- it fails with aKeyError. It works exactly as it is written.To fix this you can do something like:
yanboliang commentedon Nov 7, 2022
@sobolevn Thanks for your quick response! I do agree this works well in functionality's perspective, but I'd like to say if this is a good user experience. If users are just trying to override
__getattr__to implement their own functionality(like what I'm doing in the example), it means they should handle a lot of other python internal stuff at well. I think this would sort of increase the complexity, and make users can't focus on their own functionality.sobolevn commentedon Nov 7, 2022
So, probably you are asking from some kind of fallback for cases like this. Please, correct me if I am wrong :)
I think that
repr()ofweakref.refwould have a default value if_PyObject_LookupAttr(obj, &_Py_ID(__name__), &name)fails.Example:
<weakref at 0x1085b5800; to __some_default__ at 0x7ffd1071c080 (...)>However, I don't think this is a good user experience either.
It is better to see an explicit exception early on than very strange and mostly unreadable
reprsomewhere in logs.Considering your class, it looks problematic to me. It does not respect basic python's API, like:
__dict__,__name__,__qualname__,__class__,__module__, etc.They are quite basic, many other parts of CPython (and 3rd party projects) do use it.
And you will have a lot of other failure when these fundamentals cannot be accessed 🤔
Do you agree with me?
yanboliang commentedon Nov 7, 2022
I can understand your point, if other parts of CPython do the same way, it's fine. But if you take a look at this example:
If users don't user
weakref, it works well even they don't handle__dict__, __name__, __qualname__, __class__, __module__, etc. Do you think the inconsistency will confuse users?MojoVampire commentedon Nov 8, 2022
If the goal is to look up
__name__on the class of the instance, shouldn't the weakref code be using_PyObject_LookupSpecial(or_PyObject_LookupSpecialId, though I guess those are the same thing now?), not_PyObject_LookupAttr? The only advantage to the latter is if we wanted to allow instances to change their names by overwriting__name__. Using theLookupSpecialAPI would bypass the instance and avoid this issue (as well as being faster and likely more correct).pythongh-99184: Bypass instance attribute access in `repr` of `weakre…
sobolevn commentedon Nov 8, 2022
@MojoVampire yes, this is a good idea. Thank you! I didn't think about it :)
I've submitted #99244 with your proposal.
gh-99184: Bypass instance attribute access in `repr` of `weakref.ref` (…
pythongh-99184: Bypass instance attribute access in `repr` of `weakre…
[3.11] gh-99184: Bypass instance attribute access in `repr` of `weakr…
Merge branch 'main' into superopt
Merge branch 'superopt' into superopt_spec