Issue2719

classification
Title: Divergence of __str__ and __repr__ from CPython
Type: behaviour Severity: normal
Components: Core Versions: Jython 2.7
Milestone: Jython 2.7.2
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: jeff.allen Nosy List: jeff.allen, rferguson@devendortech.com
Priority: normal Keywords:

Created on 2018-12-11.23:43:26 by jeff.allen, last changed 2019-11-03.09:14:19 by jeff.allen.

Messages
msg12203 (view) Author: Jeff Allen (jeff.allen) Date: 2018-12-11.23:43:25
I'm raising this to cover what (I think) https://github.com/jythontools/jython/pull/126 aims to fix.

The following simple function probes str() and repr() behaviour for a supplied instance:

def dump(a):
    print type(a).__name__

    print "  repr(a):     ", repr(a)
    if hasattr(a, '__repr__'):
        print "  a.__repr__():", a.__repr__()
    else:
        print "  a.__repr__(): not defined"

    print "  str(a):      ", str(a)
    if hasattr(a, '__str__'):
        print "  a.__str__(): ", a.__str__()
    else:
        print "  a.__str__():  not defined"

In CPython:
>>> dump(buffer('hello'))
buffer
  repr(a):      <read-only buffer for 0x0000000002EA0238, size -1, offset 0 at 0x0000000002DCED88>
  a.__repr__(): <read-only buffer for 0x0000000002EA0238, size -1, offset 0 at 0x0000000002DCED88>
  str(a):       hello
  a.__str__():  hello
>>> def g(): pass
...
>>> dump(g)
function
  repr(a):      <function g at 0x0000000002E9C198>
  a.__repr__(): <function g at 0x0000000002E9C198>
  str(a):       <function g at 0x0000000002E9C198>
  a.__str__():  <function g at 0x0000000002E9C198>

While in Jython:
>>> dump(buffer('hello'))
buffer
  repr(a):      <read-only buffer for 0x8, size -1, offset 0 at 0x0x9>
  a.__repr__(): <buffer object at 0x9>
  str(a):       hello
  a.__str__():  <read-only buffer for 0x8, size -1, offset 0 at 0x0x9>
>>> def g(): pass
...
>>> dump(g)
function
  repr(a):      <function g at 0xa>
  a.__repr__(): <function object at 0xa>
  str(a):       <function g at 0xa>
  a.__str__():  <function g at 0xa>

Apart from the bovine superfluity in repr for buffer (one 0x too many), the main bug is that __repr__ and __str__ do not match expectations. The GitHub PR blames the curious and unexplained cross-wiring of __str__ and __repr__ as exposed from PyObject, without which there is apparently a stack overflow when new-style classes are defined. (This happens because PyObjectDerived.toString calls __repr__.)

While the cross-wiring doesn't lead to these errors directly, it makes them more difficult to understand and solve. The PR seeks to eliminate this confusion, defuse the recursion another way, and fix the substantive errors.
msg12574 (view) Author: Jeff Allen (jeff.allen) Date: 2019-07-09.06:58:15
I think we fixed this, but I'm putting this on the 2.7.2 milestone to remind me to check we've done enough..
msg12610 (view) Author: Jeff Allen (jeff.allen) Date: 2019-07-23.07:48:31
Good enough for now. We have documented the logic of the current design and fixed the identified consequences of misunderstanding it.

We may want to go further, but not for 2.7.2 I suggest.
History
Date User Action Args
2019-11-03 09:14:19jeff.allensetstatus: pending -> closed
2019-07-23 07:48:31jeff.allensetstatus: open -> pending
resolution: accepted -> fixed
messages: + msg12610
2019-07-09 06:58:15jeff.allensettype: behaviour
resolution: accepted
messages: + msg12574
milestone: Jython 2.7.2
2018-12-11 23:43:26jeff.allencreate