Title: __setattr__ does not always overload operators
Type: behavior Stage: patch review
Components: Interpreter Core Versions: Python 3.7, Python 3.6, Python 3.5, Python 2.7
Status: open Resolution:
Dependencies: Superseder:
Assigned To: serhiy.storchaka Nosy List: Dominik Schmid, berker.peksag, eryksun, louielu, serhiy.storchaka
Priority: normal Keywords: patch

Created on 2015-12-04 08:52 by Dominik Schmid, last changed 2017-04-23 18:13 by serhiy.storchaka.

File name Uploaded Description Edit Dominik Schmid, 2015-12-04 08:52 source code reproducing the bug
issue25794_2.patch eryksun, 2015-12-04 12:15 review
Messages (4)
msg255853 - (view) Author: Dominik Schmid (Dominik Schmid) Date: 2015-12-04 08:52
While implementing my own Integer class that keeps track of when operations are applied I noticed that setattr had a strange behaviour when I tried to wrap operator functions.

When the attribute string had a different id to its literal it failed to overload the operator.
Are we doing a 'is' rather than a '==' somewhere in setattr?

expected result: 
139723705431168    a.__add__(b)= (5)    a+b= (5)
139723705431168    a.__add__(b)= (5)    a+b= (5)
139723704361584    a.__add__(b)= (5)    a+b= (5)

actual result:
139723705431168    a.__add__(b)= (5)    a+b= (5)
139723705431168    a.__add__(b)= (5)    a+b= (5)
139723704361584    a.__add__(b)= (5)    a+b=
Traceback (most recent call last):
  File "/home/dom/Documents/leastOps/", line 41, in <module>
  File "/home/dom/Documents/leastOps/", line 28, in testSetattr
    print '   a+b=', a+b
TypeError: unsupported operand type(s) for +: 'Integer' and 'Integer'

2.7.10 (default, Oct 14 2015, 16:09:02) 
[GCC 5.2.1 20151010]
ubuntu 14.10
msg255859 - (view) Author: Eryk Sun (eryksun) * Date: 2015-12-04 11:51
Normally Python code calls built-in setattr, which calls the C API PyObject_SetAttr. This API interns the attribute name before calling the type's tp_setattro or tp_setattr function. Interning the string is a critical step, since the implementation for updating slots assumes the name is interned. 

The __setattr__ slot wrapper calls wrap_setattr in Objects/typeobject.c. In line with how PyObject_SetAttr works, the attached patch interns the name in wrap_setattr before calling the wrapped setattrofunc. For good measure it also applies the same change to wrap_delattr, though that's not strictly necessary.
msg255862 - (view) Author: Eryk Sun (eryksun) * Date: 2015-12-04 12:15
This updated patch calls PyUnicode_Check to ensure the name is a string before calling PyUnicode_InternInPlace.
msg292176 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-04-23 18:13
Eryk, could you create a pull request? Please take into account my and Berker's comments on Rietveld.
Date User Action Args
2017-04-23 18:13:32serhiy.storchakasetmessages: + msg292176
2017-04-17 05:02:51rhettingersetassignee: serhiy.storchaka
2017-04-14 17:03:48louielusetnosy: + louielu
2017-04-14 15:36:07serhiy.storchakasetnosy: + serhiy.storchaka

versions: + Python 3.7
2015-12-16 00:05:48berker.peksagsetnosy: + berker.peksag
stage: patch review

versions: - Python 3.4
2015-12-04 12:15:30eryksunsetfiles: + issue25794_2.patch

messages: + msg255862
2015-12-04 12:12:58eryksunsetfiles: - issue25794_1.patch
2015-12-04 11:51:56eryksunsetfiles: + issue25794_1.patch
versions: + Python 3.4, Python 3.5, Python 3.6
nosy: + eryksun

messages: + msg255859

keywords: + patch
2015-12-04 08:52:36Dominik Schmidcreate