Irit Katriel <[email protected]> added the comment:
This issue only impacts container objects where the len(repr(o)) is less than
width. If the length is greater than width, containers are handled by a
different code path which is covered by a unit test and works correctly.
For this case, indeed it works in Python 2 but not in Python 3. The
PrettyPrinter._format code has been refactored quite a lot with respect to
handling of containers.
In both Python 2 and 3 this happens:
PrettyPrinter.pprint([10]) calls
PrettyPrinter._format([10]) which calls
PrettyPrinter._repr([10]) which calls
MyPrettyPrinter.format([10]) which calls
PrettyPrinter.format([10]) which calls
_safe_repr([10]) which calls
_safe_repr(10)
returns 10
returns [10]
returns [10]
returns [10]
returns [10]
But then they diverge - in Python 3 the [10] is returned as the result, but in
Python 2 there is another piece of code (starting here
https://github.com/python/cpython/blob/fdda200195f9747e411d3491aae0806bc1fcd919/Lib/pprint.py#L179)
which overrides this result and recalculates the representation for
containers. In our case it does:
since issubclass(type([10]), list):
# ignore the [10] calculated above, now call
self._format(10) which calls
PrettyPrinter._repr(10) which calls
MyPrettyPrinter.format(10)
returns 0xa
returns 0xa
returns 0xa
returns [0xa]
This explains the difference between Python 2 and 3.
As to why the first calculation returns [10] and not [0xa]:
This is because _safe_repr is defined at module scope, so once it is called we
are no longer on the PrettyPrinter instance, and the format() override is no
longer accessible. When _safe_repr needs to recurse on container contents, it
calls itself.
I think the solution is to make _safe_repr a method of PrettyPrinter, and make
it call self.format() when it needs to recurse. The default self.format() just
calls _safe_repr, so when there is no override the result is the same.
The PR's diff looks substantial, but that's mostly due to the indentation of
_safe_repr code. To make it easier to review, I split it into several commits,
where the indentation is done in one commit as a noop change. The other commits
have much smaller diffs.
----------
versions: +Python 3.10, Python 3.8, Python 3.9 -Python 3.5, Python 3.6, Python
3.7
_______________________________________
Python tracker <[email protected]>
<https://bugs.python.org/issue28850>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com