Can I make pprint in python3 not split strings, like in python2?
Asked Answered
V

4

20

Is there a way to tell pprint in Python 3 not to split strings on whitespace? Python 2's pprint did not do this. Can this behavior be disabled? I looked through the source for pprint and it doesn't look like there's an option I saw for this.

Can I trick it somehow?

Here's an example of what I'm getting:

>>> PP.pprint("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ ZZZZZ",width=-1,compact=True)
('ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ '
 'ZZZZZ')

And here's what I want:

>>> PP.pprint("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ ZZZZZ",width=-1,compact=True)
('ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ ZZZZZ')

To clarify, I do want it to obey widths, just not for strings. So when I see eg:

PP.pprint(["ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ ZZZZZZZZZZZZZ","CATS"])

I want:

['ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ ZZZZZZZZZZZZZ',
 'CATS']

Not:

['ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ '
 'ZZZZZZZZZZZZZ',
 'CATS']
Ventriloquize answered 17/7, 2015 at 22:4 Comment(0)
A
18

You could just set the width option to a really large value, such as sys.maxsize:

>>> import sys
>>> import pprint as PP
>>> PP.pprint("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ ZZZZZ",width=sys.maxsize,compact=True)
'ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ ZZZZZ'

Setting width to -1 has no special meaning.

The only other option is to subclass the PrettyPrinter() class, and wrapping the _format() method:

import sys
from pprint import PrettyPrinter

class NoStringWrappingPrettyPrinter(PrettyPrinter):
    def _format(self, object, *args):
        if isinstance(object, str):
            width = self._width
            self._width = sys.maxsize
            try:
                super()._format(object, *args)
            finally:
                self._width = width
        else:
            super()._format(object, *args)

NoStringWrappingPrettyPrinter().pprint(yourobject)

This sets the width to sys.maxsize only for strings:

>>> NoStringWrappingPrettyPrinter().pprint(["ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ ZZZZZ", "CATS"])
['ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ ZZZZZ',
 'CATS']
Alpenglow answered 17/7, 2015 at 22:8 Comment(6)
I guess it didn't grow an option for this in the meantime?Sena
@JürgenA.Erhard: nope.Alpenglow
We already subclassed PrettyPrinter so the latter solution worked fine. I agree with the OP that Python 2 behavior is better when formatting lists and dicts, but I can see use cases where Python 3 approach works better. It's also strange that only Unicode strings, not bytes, are split like this. It would be best if there was an option to control this behavior.Palma
@PekkaKlärck: the pprint module is in dire need of a rewrite. I fear it currently is too gnarly to support new features like this easily.Alpenglow
@MartijnPieters I've noticed that. We wanted to slightly modify formatting strings and bytes and that wasn't as easy as it could have been. That said, adding support for not splitting strings shouldn't be that complicated.Palma
Just noticed in my testing that Python 3.4 doesn't split long byte strings but Python 3.5+ do. Needed to change isinstance(object, str)in the above solution to isinstance(object, (str, bytes, bytearray)) to fix that.Palma
G
3

For list, you can try json.dump. Code:

import json
from pprint import pprint
import sys

li = ['zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz zzz', 'cats']

print("pprint directly:")
pprint(li)
print('-' * 20)
print("pprint with large width:")
pprint(li, width=sys.maxsize, compact=True)
print('-' * 20)
print("json dumps:")
print(json.dumps(li, indent=4))

output:

pprint directly:
['zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz '
 'zzz',
 'cats']
--------------------
pprint with large width:
['zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz zzz', 'cats']
--------------------
json dumps:
[
    "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz zzz",
    "cats"
]

Setting a large width makes pprint not wraping even the list object is very long

Gingham answered 10/2, 2021 at 3:34 Comment(0)
A
2

It appears that you need to set the width to be the length of your string + 3 (for the quotes on either side and the newline) at an absolute minimum.

>>> x = 'ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ ZZZZZ'
>>> PP.pprint(x, width=len(x))
'ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ '
'ZZZZZ'
>>> PP.pprint(x, width=len(x) + 3)
'ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ ZZZZZ'
Androus answered 17/7, 2015 at 22:10 Comment(0)
S
2

Another approach, similar to that of Martijn Pieters, but which relies less on the internals of pprint is to subclass PrettyPrinter and override format. Inside you can delegate to super().format but in the result you can fake the length of strings, such that they won't be split. This relies on the output stream (e.g. sys.stdout or StringIO()) not looking at the string length.

class Python2PrettyPrinter(pprint.PrettyPrinter):
    class _fake_short_str(str):
        def __len__(self):
            return 1 if super().__len__() else 0

    def format(self, object, context, maxlevels, level):
        res = super().format(object, context, maxlevels, level)
        if isinstance(object, str):
            return (self._fake_short_str(res[0]), ) + res[1:]
        return res

    from io import StringIO
    assert StringIO().write(_fake_short_str('_' * 1000)) == 1000


Python2PrettyPrinter().pprint(["TEST " * 20] * 2)
# ['TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST ',
#  'TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST ']

The 100% clean way would be to modify the behavior of format for all supported container classes, and substitute every string for a custom object which has the same representation.

Sherborn answered 10/4, 2019 at 18:38 Comment(1)
I couldn't get this to work for a list of strings until I set __len__() to always return 0. I'm not sure if that would work in general though.Fleabag

© 2022 - 2025 — McMap. All rights reserved.