icecream icon indicating copy to clipboard operation
icecream copied to clipboard

Detect and pretty print dictionary views (dict_keys(), dict_values(), and dict_items())

Open gruns opened this issue 5 years ago • 6 comments

eg detect and pretty print

d = { ... }
ic(d.keys())
ic(d.values())

like

d = { ... }
ic(list(d.keys()))
ic(list(d.values()))

gruns avatar Jun 17 '20 18:06 gruns

I don't get it.

from icecream import ic

d = {'key': 'value'}

ic(d.keys())
ic(d.values())

Output:

ic| d.keys(): dict_keys(['key'])
ic| d.values(): dict_values(['value'])

Are you saying you want the output to be:

ic| d.keys(): ['key']
ic| d.values(): ['value']

Seems like a marginal improvement.

alexmojaki avatar Jun 17 '20 18:06 alexmojaki

Example with larger dicts exhibits less-than-optimal formatting:

from icecream import ic
from random import choice
from string import ascii_letters as letters

randomWord = lambda: ''.join(choice(letters) for i in range(10))
d = {randomWord():randomWord() for i in range(10)}

ic(d)  # Nicely formatted.
ic(d.items())  # Poorly formatted.

Output:

ic| d: {'CsTAmcmuz': 'rDCAyhFrk',
        'TWrUmbiPu': 'nnXNZceYI',
        'XeNFOVFdl': 'dXoIbTrYd',
        'XhhXFHIFj': 'qpSSOaJwp',
        'cCvxMwZYB': 'nGYfUkhGB',
        'dHPrOMQZN': 'ysaCBpiUU',
        'dZnvdVmAv': 'DuxmrCRyj',
        'hAwafTchI': 'CUvXhhqjz',
        'lRbAsPfMG': 'cRFFohVXc',
        'sIGOEzebe': 'fqotZssCh'}
ic| d.items(): dict_items([('dZnvdVmAv', 'DuxmrCRyj'), ('CsTAmcmuz', 'rDCAyhFrk'), ('cCvxMwZYB', 'nGYfUkhGB'), ('XeNFOVFdl', 'dXoIbTrYd'), ('XhhXFHIFj', 'qpSSOaJwp'), ('TWrUmbiPu', 'nnXNZceYI'), ('hAwafTchI', 'CUvXhhqjz'), ('lRbAsPfMG', 'cRFFohVXc'), ('dHPrOMQZN', 'ysaCBpiUU'), ('sIGOEzebe', 'fqotZssCh')])

I'm not sure how practical it is to generally 'discover' internal dict-like, or list-like, structures that should be formatted as dicts or lists in arbitrary objects. Or, alternatively, whether dictionary view objects (dict.keys(), dict.values(), and dict.items()) are a useful enough corner case to add a specific check for in IceCream.

I'm leaning the latter. For now, at least. Until this problem crops up again with other, arbitrary objects with internal dict-like and/or list-like structures that would benefit from formatting. One problem at a time.

What do you think?

gruns avatar Jun 18 '20 19:06 gruns

Ah OK, I didn't realise this was about pprint.

This made me look up alternatives to the built in pprint. Here's what I found:

  • https://github.com/tommikaikkonen/prettyprinter
  • https://github.com/panyanyany/beeprint
  • https://github.com/wolever/pprintpp

It turns out none of these handle dict_keys. Maybe that implies a lack of demand?

Either way, if we want to improve formatting in general, maybe using one of these by default could be a good idea? And if we do, then adding support for dict views there might be more worthwhile.

I was once similarly asked to add support for pprintpp in snoop, although I never got around to doing it: https://github.com/alexmojaki/snoop/issues/13

alexmojaki avatar Jun 18 '20 19:06 alexmojaki

Actually just ran into another organic example just now: ic(os.environ):

import os
from icecream import ic

ic(os.environ)

Output:

ic| os.environ: environ({'PWD': ... a really long, not-pretty-printed, single-line string ... })

Also pretty print is a much better description of the issue than format :). Updated the Issue title.

gruns avatar Jun 18 '20 20:06 gruns

Yes, this will be an issue with loads of custom classes.

Here is a quick attempt at a general solution for some cases. Don't have time to go into this more.

import ast
import pprint
import re


def clever_pformat(x):
    result = pprint.pformat(x)
    match = re.match("([\w.]+)\((.+)\)$", result)
    if not match:
        return result

    name, inner = match.groups()
    try:
        value = ast.literal_eval(inner)
    except ValueError:
        return result

    return "{}({})".format(name, pprint.pformat(value))


import os

print(clever_pformat(os.environ))
print(clever_pformat(dict(os.environ).keys()))

alexmojaki avatar Jun 18 '20 20:06 alexmojaki

I'll think about this more, too. I created the Issue yesterday so the potential improvement wouldn't get lost.

gruns avatar Jun 18 '20 21:06 gruns